Well, the original array needs to be malloc'ed, rather than on the stack. Then you can use realloc:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int * numbers = malloc(6*sizeof(int));
for(int ii = 0; ii < 6; ++ii) {
numbers[ii] = 5;
}
numbers = realloc(numbers, 7*sizeof(*numbers));
if(!numbers) {
printf("Memory allocation failed, sorry dude!\n");
exit(1);
}
numbers[6] = 7;
for(int ii = 0; ii< 7; ++ii) {
printf("%d\n", numbers[ii]);
}
free(numbers);
}
Answer from user14717 on Stack OverflowWell, the original array needs to be malloc'ed, rather than on the stack. Then you can use realloc:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int * numbers = malloc(6*sizeof(int));
for(int ii = 0; ii < 6; ++ii) {
numbers[ii] = 5;
}
numbers = realloc(numbers, 7*sizeof(*numbers));
if(!numbers) {
printf("Memory allocation failed, sorry dude!\n");
exit(1);
}
numbers[6] = 7;
for(int ii = 0; ii< 7; ++ii) {
printf("%d\n", numbers[ii]);
}
free(numbers);
}
The simplest solution probably would be to make an array that is larger than it needs to be upon declaration.
Your example array has six elements, so perhaps the array would be declared to have a length of eight. This would be enough to allow two more elements to be "added". You would have to keep track of both what the actual length of the array is and the number of relevant elements it contains are (eight and six respectively).
If you wanted to "add" a third element then you would have to make a new array. The new array could be twice the length of the previous one (sixteen). Copy all the elements of the previous array to the new one and then "add" the new element.
int arr[10] = {0, 5, 3, 64};
arr[4] = 5;
EDIT: So I was asked to explain what's happening when you do:
int arr[10] = {0, 5, 3, 64};
you create an array with 10 elements and you allocate values for the first 4 elements of the array.
Also keep in mind that arr starts at index arr[0] and ends at index arr[9] - 10 elements
arr[0] has value 0;
arr[1] has value 5;
arr[2] has value 3;
arr[3] has value 64;
after that the array contains garbage values / zeroes because you didn't allocated any other values
But you could still allocate 6 more values so when you do
arr[4] = 5;
you allocate the value 5 to the fifth element of the array.
You could do this until you allocate values for the last index of the arr that is arr[9];
Sorry if my explanation is choppy, but I have never been good at explaining things.
There are only two ways to put a value into an array, and one is just syntactic sugar for the other:
a[i] = v;
*(a+i) = v;
Thus, to put something as the element at index 4, you don't have any choice but arr[4] = 5.
A naive implementation of ArrayList in c, open to criticism and feedback to improve upon my implementation.
https://github.com/kingxcold/Array_list-in-c
I know how to make a LinkedList in C but I'm struggling to understand how an ArrayList would be implemented in C - especially the addition and direct access parts
First, a word on naming:
The name you've chosen for your type, _arraylist is a bad name for a library interface
type. Names starting with _ are not pleasant to work with in user code. They are commonly
used inside library internals. Better names would be ArrayList or array_list.
Actually, in your usage example, you have ArrayList. Does this mean that in the header,
which is not included here, you have something like this?
typedef _arraylist ArrayList;
If you did define an opaque type in the header, like above, that would be a good practice.
But then you should not use any reference to _arraylist in your code. Use always the typedef'd name to avoid confusion.
The function name prefix should also follow exactly the name of the type, so for ArrayList all functions should be prefixed the ArrayList_, e.g.:
ArrayList * ArrayList_create();
Also, I would suggest that you avoid tightlypacked names, like in arraylist_getsize(). Adding an
underscore to separate words makes them a lot more readable. E.g.: ArrayList_get_size().
Problems with memory:
Lets look at arraylist_create():
struct _arraylist *arraylist_create() {
struct _arraylist *list = malloc(sizeof(struct _arraylist));
assert(list != NULL);
list->size = 0;
list->data = calloc(2, sizeof(void *));
assert(list->data != NULL);
list->data[0] = NULL;
return list;
}
First thing unusual here is the assertions. Assertions are not the proper way to
handle a memory allocation failure. Plus, they are commonly disabled on release builds,
so on release, if you'd happen to run out of memory, the program would just crash silently.
You should probably return a NULL in this case (maybe also log to stderr) and let the caller handle this error as he/she sees fit.
Second problem here is with calloc(). You are allocating 2 void pointers, however, size is set to zero.
I don't really get the point of this. Since your structure is more like and array of arrays then a list,
what you should do is allocate the array of pointers with some predefined default size, then allocate the
individual arrays as needed. Growing the array of pointers on demand. How arraylist_create() should look like:
ArrayList * ArrayList_create() {
ArrayList *list = malloc(sizeof *list);
if (list == NULL) {
return NULL;
}
list->size = 0;
list->data = calloc(INITIAL_BASE_ARRAY_SIZE, sizeof(void *));
if (list->data == NULL) {
free(list); // Don't leek memory here!
return NULL;
}
return list;
}
Another big memory issue is the constant re-allocations done by arraylist_add() and arraylist_remove().
Remove should not shrink the sequence. Keep that space around if the array grows again in the future. You can add an explicit way to let the user shrink the storage if necessary (a la std::vector::shrink_to_fit()).
Adding to the array can be made to run in amortised-constant time if you pre-allocate storage with a larger size then the requested. (Again inspired by the STL vector).
sizeof mistake:
This will not return what you expect:
size_t arraylist_getsizeof(struct _arraylist *list) {
/* Returns the size of the internal array in memory */
return sizeof(*list->data);
}
The sizeof operator always returns the size of the type it is applied to.
It cannot infer the size of an array pointed by a pointer, because it is a
compile-time operation. arraylist_getsizeof() will always return the same value,
the size of a void pointer, which will be 4 or 8, depending on the architecture.
Use assertions to check for invariants:
You should assert that the *list parameter of every function is valid. This is a precondition of every function, they cannot work without a valid ArrayList instance, so you should assert that once the function enters.
Miscellaneous:
You don't need to check if the pointer is null before freeing it. In arraylist_deallocate() the if (list->data != NULL) check is uneeded.
arraylist_deallocate would be more symmetric with arraylist_create if named arraylist_destroy.
Lets talk about perfomance
What if you need to use your list very frequently?
Let's look closer at function arraylist_add; if I need a list with 1 million bytes, which is 1MB, it will reallocate your data struct member 1 million times.
It is lowest part of your list!
Suggestions
Allocate memory by chunks, e.g., C++ std::vector uses increasing size of appended chunks depending on current size of std::vector.
This will increase perfomance it few times in purpose of adding new elements.
Lets talk about code as is
Try to implement some elegant, but simple program flow.
Create value type (int) ArrayList, which will allocate memory by chuncks instead of reallocate full array, and add some list behaviour under the hood. I mean list of chunks, you still need to manage it.
Here is my solution with with example of using chuncks of data for each node instead of reallocating nodes. Different chunck size may be best for one of purposes: writing, reading long arrays; r\w short arrays; removing elements; etc.
#include <stdio.h>
#include <stdlib.h>
typedef struct ArrayList ArrayList;
typedef ArrayList* ArrayListPtr;
struct ArrayList {
size_t capacity;
size_t size;
int *data;
ArrayListPtr parent;
ArrayListPtr child;
};
const size_t ARRAY_LIST_CHUNCK_SIZE = 64;
ArrayListPtr array_list_create_with_parent_and_chunck_size(ArrayListPtr parent,
size_t chunck_size) {
ArrayListPtr result = (ArrayListPtr)calloc(sizeof(ArrayList), 1);
result->parent = parent;
result->capacity = chunck_size;
result->data = (int*)malloc(sizeof(int) * chunck_size);
return result;
}
ArrayListPtr array_list_create_with_parent(ArrayListPtr parent) {
return array_list_create_with_parent_and_chunck_size(
parent, ARRAY_LIST_CHUNCK_SIZE
);
}
ArrayListPtr array_list_create() {
return array_list_create_with_parent_and_chunck_size(
NULL, ARRAY_LIST_CHUNCK_SIZE
);
}
void array_list_push_back(ArrayListPtr list, int value) {
if (list->size >= list->capacity) {
if (!list->child) {
list->child = array_list_create_with_parent(list);
}
array_list_push_back(list->child, value);
} else {
list->data[list->size++] = value;
}
}
int* array_list_get_value_by_index(ArrayListPtr list, size_t index) {
if (index >= list->capacity || index >= list->size) {
if (list->child) {
return array_list_get_value_by_index(list->child,
index - list->size);
} else {
return NULL;
}
}
return list->data + index;
}
int main(int argc, char *argv[]) {
ArrayListPtr list = array_list_create();
for (int i = 0; i < 100*1000; ++i) {
array_list_push_back(list, i);
}
size_t test[] = {0,1,2,3,4,5,6,7,8,9,10,11,12,31,32,33,63,64,65,999,1000};
for (int i = 0; i < sizeof(test) / sizeof(size_t); ++i) {
int* result = array_list_get_value_by_index(list, test[i]);
if (result) {
printf("list[%ld] = %d\n", test[i], *result);
} else {
printf("Can't get value by index %ld\n", test[i]);
}
}
}
Hi, so I'm a new C user and I found this code online that prints how many times each character in a string is used. So if the input is hello, it prints
'h' = 1
'e' = 1
'l' = 2
'o' = 1
but what if I want to store each of those words and the times it has been used in a list? So in python I know I can use a for loop and append each string, but how would I do that in C? So like, if the input is "hello", I want to create two lists, list 1 = ['h','e','l','o'] and list 2 would be the amount of times it has been used so list 2 = [1,1,2,1] so integers.
#include <stdio.h>
#include <string.h>
int main()
{
char s[1000];
int i,j,k,count=0,n;
printf("Enter the string : ");
scanf("%s", s);
for(j=0;s[j];j++);
n=j;
printf(" frequency count character in string:\n");
for(i=0;i<n;i++)
{
count=1;
if(s[i])
{
for(j=i+1;j<n;j++)
{
if(s[i]==s[j])
{
count++;
s[j]='\0';
}
}
printf(" '%c' = %d \n",s[i],count);
}
}
return 0;
}
I was making a program that needs to create a list of numbers, however this number greatly varied with the input, and there’s no closed expression for how long the list would need to be in terms of the input. Something like a linked list would’ve worked nicely but I do not believe there’s an analog of that in c++. I just made a string and would add the numbers after converting them into a string and created a method to read the string like an array which definitely is not very efficient. I’m pretty new/bad at c++ so I apologize if this is a stupid question.