2

I've tried to search out a solution via Google: I couldn't find anything that helped; it even seemed as if I was doing this correctly. The only pages I could find regarding sending my dynamically allocated array through a function dealt with the array being inside a struct, which is scalar of course, so behaves differently. I don't want to use a struct right now -- I'm trying to learn about DAM and working with pointers and functions.

That said, I'm sure it's very elementary, but I'm stuck. The code compiles, but it freezes up when I run the executable. (I'm using minGW gcc, if that matters. And I'm not clear at all, right now, on how to use gdb.)

Here's the code (eventually, I want the entire code to be an ArrayList-like data structure):

#include <stdio.h>
#include <stdlib.h>

void add( int element, int *vector);
void display_vector( int *vector );
void initialize_vector( int *vector );

int elements = 0;
int size = 10;

int main(void)
{
    int *vector = 0; 
    initialize_vector(vector);
    add(1, vector);
    //add(2, vector);
    //add(3, vector);
    //add(4, vector);
    //add(5, vector);
    //add(6, vector);
    //add(7, vector);
    //add(8, vector);
    //add(9, vector);
    //add(10, vector);
    //add(11, vector);
    display_vector(vector); 

    return 0;
}

void add( int element, int *vector)
{
    vector[elements++] = element;
    return;
}

void display_vector( int *vector )
{
    int i;
    for( i = 0; i < elements; i++)
    {
        printf("%2d\t", vector[i]);
        if( (i + 1) % 5 == 0 )
            printf("\n");
    }
    printf("\n");
    return; 
}

void initialize_vector( int *vector )
{
    vector = (int *)malloc(sizeof(int) * size);

}
4
  • 1
    Why do you have elements and size as global variables, but vector is a local variable? Since you can't have more than one vector because of the global elements variable, you might as well make vector a global variable as well. Commented May 2, 2014 at 17:12
  • You are assigning the address of the newly allocated memory to the local pointer. The original pointer is still a NULLPTR. Commented May 2, 2014 at 17:13
  • Very good point @Barmar. Commented May 2, 2014 at 17:19
  • @alvits, should I not make the original pointer null then? It runs the way it's set up now with dboals code changes. Commented May 2, 2014 at 17:21

3 Answers 3

3

Edited to make a little bit more clear.

The problem is your init routine is working with a copy of "vector" and is malloc'ing into that copy rather than the original vector pointer. You loose the pointer to the memory block on the return from the initialize.

Change parameter for vector to a handle (pointer to pointer) in this function

void initialize_vector( int **vector )
{
    *vector = (int *)malloc(sizeof(int) * size);
}

Then change the call to init to this

initialize_vector(&vector);

I didn't compile this, but it should fix the code.

Sign up to request clarification or add additional context in comments.

1 Comment

It should be *vector = ...
2

In C, function arguments are passed by value, which means there is a local copy for every arguments you passed to a function, if you change an argument in a function, you only change the local copy of that argument. So if you want to change the value of an argument in a function, you need to pass its address to that function, derefer that address and assign to the result in that function.

Enough for the theory, here is how to fix your code:

void initialize_vector( int **vector );

initialize_vector(&vector);

void initialize_vector( int **vector )
{
    *vector = (int *)malloc(sizeof(int) * size);

}

1 Comment

Thanks very much @Lee Duhem. I +1'd you.
1

In addition of other replies, I would suggest another approach.

Assuming at least C99 compliant compiler, I would rather suggest to keep the allocated size in a member of a structure ending with a flexible array member (see also this) like:

 typedef struct vector_st {
    unsigned count; // used length
    unsigned size;  // allocated size, always >= length
    int vectarr[];
 } Vector;

Then you would construct such a vector with

 Vector* make_vector (unsigned size) { 
   Vector* v = malloc(sizeof(Vector)+size*sizeof(int));
   if (!v) { perror("malloc vector"); exit (EXIT_FAILURE); };
   memset (v->vectarr, 0, size*sizeof(int));
   v->count = 0;
   v->size = size;
 }

To add an element into a vector, returning the original vector or a grown one:

Vector* append_vector (Vector*vec, int elem) {
  assert (vec != NULL);
  unsigned oldcount = vec->count;
  if (oldcount < vec->size) {
     vec->vectarr[vec->count++] = elem;
     return vec;
  } else {
     unsigned newsize = ((4*oldcount/3)|7) + 1;
     Vector* oldvec = vec;
     vec = malloc(sizeof(Vector)+newsize*sizeof(int));
     if (!vec) { perror("vector grow"); exit(EXIT_FAILURE); };
     memcpy (vec->vectarr, oldvec->vectarr, oldcount*sizeof(int));
     memset (vec->vectarr + oldcount, 0, 
             (newsize-oldcount) * sizeof(int));
     vec->vectarr[oldcount] = elem;
     vec->count = oldcount+1;
     vec->size = newsize;
     free (oldvec);
     return vec;
  }
}

and you could code:

Vector* myvec = make_vector(100);
myvec = append_vector(myvec, 35);
myvec = append_vector(myvec, 17);
for (int i=0; i<150; i++)
   myvec = append_vector(myvec, i*2);

To release such a vector, just use free(myvec);


If you really don't want to use any struct you should keep in separate variables the used length of your vector, the allocated size of your vector, the pointer to your dynamically allocated array:

  unsigned used_count; // useful "length"
  unsigned allocated_size; // allocated size, always not less than used_count
  int *dynamic_array; // the pointer to the dynamically allocated array

If you want to be able to manage several vectors, then either pack together the above useful length, allocated size and dynamic array into some struct dynamic_array_st (whose pointer you would pass to appropriate routines like make_dynamic_vector(struct dynamic_array_st*), append_dynamic_vector(struct dynamic_array_st*, int), etc ....) or else pass them as three separate formals to similar routines, and then you'll need to pass their address because the routines would change them, e.g. create_dynamic_vector(unsigned *countptr, unsigned *sizeptr, int**vectarrptr) that you would invoke as create_dynamic_vector(&mycount, &mysize, &myvectarr); etc.

I do think that a flexible array member is still the cleanest approach.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.