Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a dynamic array in to functions in C

I'm trying to create a function which takes an array as an argument, adds values to it (increasing its size if necessary) and returns the count of items. So far I have:

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 resizing, I get a Segmentation Fault.

I have 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 pointed elsewhere - how is it possible to modify this so that 'a' always points to the same location?

Am I going about this correctly? Are there better ways to deal with dynamic structures in C? Should I be implementing a linked list to deal with these?

like image 399
Tom Avatar asked Dec 04 '08 16:12

Tom


2 Answers

The main problem here is that you're trying to use realloc with a stack-allocated array. You have:

ent a[mSize];

That's automatic allocation on the stack. If you wanted to use realloc() on this later, you would create the array on the heap using malloc(), like this:

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

So that the malloc library (and thus realloc(), etc.) knows about your array. From the looks of this, you may be confusing C99 variable-length arrays with true dynamic arrays, so be sure you understand the difference there before trying to fix this.

Really, though, if you are writing dynamic arrays in C, you should try to use OOP-ish design to encapsulate information about your arrays and hide it from the user. You want to consolidate information (e.g. pointer and size) about your array into a struct and operations (e.g. allocation, adding elements, removing elements, freeing, etc.) into special functions that work with your struct. So you might have:

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

And you might define some functions to work 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);

This way the user doesn't have to remember exactly how to allocate things or what size the array is currently. Hope that gets you started.

like image 106
Todd Gamblin Avatar answered Sep 22 '22 03:09

Todd Gamblin


Try reworking it so a pointer to a pointer to the array is passed in, i.e. ent **a. Then you will be able to update the caller on the new location of the array.

like image 21
xahtep Avatar answered Sep 22 '22 03:09

xahtep