Passing a dynamic array to functions in C

I am trying to create a function that takes an array as an argument, adds values ​​to it (increasing its size if necessary) and returns the number of elements. So far, I:

int main(int argc, char** argv) { int mSize = 10; ent a[mSize]; int n; n = addValues(a,mSize); for(i=0;i<n;i++) { //Print values from a } } int addValues(ent *a, int mSize) { int size = mSize; i = 0; while(....) { //Loop to add items to array if(i>=size-1) { size = size*2; a = realloc(a, (size)*sizeof(ent)); } //Add to array i++; } return i; } 

This works if mSize is large enough to hold all the potential elements of the array, but if it needs to be resized, I get a segmentation error.

I also tried:

 int main(int argc, char** argv) { ... ent *a; ... } int addValues(ent *a, int mSize) { ... a = calloc(1, sizeof(ent); //usual loop ... } 

To no avail.

I assume this is because when I call realloc, the copy of "a" is indicated elsewhere - how can I change this so that "a" always points to the same location?

Am I right about this? Are there more efficient ways to work with dynamic structures in C? Should I implement a linked list to solve these problems?

+4
source share
8 answers

The main problem is that you are trying to use realloc with a stack allocated array. You have:

 ent a[mSize]; 

This is an automatic distribution on the stack. If you want to use realloc () for this later, you must create an array on the heap using malloc (), for example:

 ent *a = (ent*)malloc(mSize * sizeof(ent)); 

So, the malloc library (and therefore realloc (), etc.) knows about your array. In appearance, you can mislead variable-length arrays with variable-length arrays with true dynamic arrays , so make sure you understand the difference there before trying to fix it.

Indeed, if you write dynamic arrays in C, you should try using the OOP-ish construct to encapsulate information about your arrays and hide it from the user. You want to consolidate information (for example, pointer and size) about your array into structure and operations (for example, selection, adding elements, deleting elements, deallocation, etc.) into special functions that work with your structure. So you can:

 typedef struct dynarray { elt *data; int size; } dynarray; 

And you can define some functions for working with dynarrays:

 // malloc a dynarray and its data and returns a pointer to the dynarray dynarray *dynarray_create(); // add an element to dynarray and adjust its size if necessary void dynarray_add_elt(dynarray *arr, elt value); // return a particular element in the dynarray elt dynarray_get_elt(dynarray *arr, int index); // free the dynarray and its data. void dynarray_free(dynarray *arr); 

Thus, the user does not need to remember exactly how to distribute things or what size of the array is currently. Hope you get started.

+10
source

Try processing it so that the pointer to the pointer to the array is passed, i.e. ent **a . Then you can update the caller in the new location of the array.

+6
source

You pass an array pointer by value. It means:

 int main(int argc, char** argv) { ... ent *a; // This... ... } int addValues(ent *a, int mSize) { ... a = calloc(1, sizeof(ent); // ...is not the same as this //usual loop ... } 

therefore, changing the value of a in the addValues function addValues not change the value of a in main. To change the value of a in the main, you need to pass a link to addValues . Currently, the value of a is copied and passed to addValues . To pass a usage link:

 int addValues (int **a, int mSize) 

and name it like this:

 int main(int argc, char** argv) { ... ent *a; // This... ... addValues (&a, mSize); } 

In addValues , access the following items:

 (*a)[element] 

and redistribute the array as follows:

 (*a) = calloc (...); 
+1
source

This is a good reason to use OOP. yes, you can do OOP in C, and it even looks good if everything is done correctly.

in this simple case, you do not need inheritance or polymorphism, just the concept of encapsulation and methods:

  • define a structure with a length and data pointer. maybe the size of the item.
  • write getter / setter functions that work with pointers to this structure.
  • the grow function changes the data pointer inside the structure, but any pointer to the structure remains valid.
+1
source

If you changed the variable declaration in main to be

 ent *a = NULL; 

the code will work more than you expected without freeing up the array allocated by the stack. Setting a to NULL works because realloc treats it as if the user had called malloc (size). Keep in mind that with this change, the addValue prototype should change to

 int addValues(ent **a, int mSize) 

and that the code should handle the realloc failure case. for instance

 while(....) { //Loop to add items to array tmp = realloc(*a, size*sizeof(ent)); if (tmp) { *a = tmp; } else { // allocation failed. either free *a or keep *a and // return an error } //Add to array i++; } 

I would expect that most realloc implementations would internally allocate twice as much memory if the current buffer needs to be resized, creating

source code <
 size = size * 2; 

not required.

+1
source

Xahtep explains how your caller can handle the fact that realloc () can move the array to a new location. While you do this, you should be fine.

realloc () can become expensive if you start working with large arrays. This is when it's time to think about using other data structures - a linked list, a binary tree, etc.

0
source

As indicated, you must pass a pointer to a pointer to update the value of the pointer.
But I would suggest redesigning and avoiding this technique, in most cases it can and should be avoided. Not knowing what exactly you are trying to achieve, it is difficult to offer an alternative design, but I'm 99% sure that this can be done in another way. And how sad Javier is, think that the object is oriented and you will always get the best code.

0
source

Do you really need to use C? This would be a great C ++ "std :: vector" application, which is an array with dynamic size (easy to resizeble with one call, which you don't need to write and debug yourself).

0
source

All Articles