3

i want to dynamically add numbers to an array in c. My idea is to just allocate a new array with size + 1, add the number, free the root array and change the pointer from the temp to the root array. Like this:

void addNumber(int* a, int* size, int number)
{
    *size = *size + 1;
    int* temp = (int*)(calloc(*size, sizeof(int)));
    int i, j = 0;
    for(i = 0; i < *size-1; i++) {
        if(a[i] < number) {
            printf("add ai");
            temp[j] = a[i];
            j++;
        } else {
            printf("add number");
            temp[j] = number;
        }
    }
    if(j != *size) {
        printf("add new number");
        temp[j] = number;
    }
    free(a);
    a = temp;
}

int main(int argc, char* argv[])
{
    int n = 10;
    int* a;
    int size = 1;

    a = (int*) (calloc(1, sizeof(int)));
    a[0] = 1;

    if(!contains(a, size, 2)) {
        addNumber(a, &size, 2);
    }

    printArray(a,size);

    return 0;
}

The problem is that in the addNumber function the code works and the *a has the right values of the new array. But in the main function the array *a has the values 1,0. So the new inserted value 2 is not added. Why? Can't get the reason.

15
  • a = temp; serves no purpose. a is a local variable. That assignment does not affect a of main(). Commented Oct 11, 2016 at 19:27
  • 4
    realloc exactly does what you want. Commented Oct 11, 2016 at 19:32
  • 1
    why not simply enlarge the previously allocated memory with realloc? Commented Oct 11, 2016 at 19:32
  • 2
    @RPGillespie if only this were a C++ question... Commented Oct 11, 2016 at 19:34
  • 3
    @RPGillespie If OP is not familiar with C++ (see stackoverflow.com/users/3172567/user3172567) or viewers of this C tagged post are not familiar with C++, then offering C++ solutions is significant less value than focusing on C, perhaps even counter productive. Commented Oct 11, 2016 at 19:39

4 Answers 4

2

To dynamically change the array size, you can use the realloc() routine. Apart from being eaiser to use, it can be faster than the approach of calling free() and malloc() sequentially.

It is guaranteed the reallocated block will be populated with the content of the old memory block.

The problem is that in the addNumber function the code works and the *a has the right values of the new array

There are two major flaws in your code. The first is that you your addNumber() routine doesn't return the newly allocated memory block (thus it is being leaked), you should either use double pointer or return the new block as function result.

And the second one results from the first - after a has been freed, you continue to write to it.

If you prefer to stick to your current approach, this modified code should work:

void addNumber(int** a, int* size, int number)
{
    *size = *size + 1;
    int* temp = (int*)(calloc(*size, sizeof(int)));
    int i, j = 0;
    for(i = 0; i < *size-1; i++) {
        if((*a)[i] < number) {
            printf("add ai");
            temp[j] = (*a)[i];
            j++;
        } else {
            printf("add number");
            temp[j] = number;
        }
    }
    if(j != *size) {
        printf("add new number");
        temp[j] = number;
    }
    free(*a);
    *a = temp;
}

int main(int argc, char* argv[])
{
    int n = 10;
    int* a;
    int size = 1;

    a = (int*) (calloc(1, sizeof(int)));
    a[0] = 1;

    if(!contains(a, size, 2)) {
        addNumber(&a, &size, 2);
    }

    printArray(a,size);

    return 0;
}
Sign up to request clarification or add additional context in comments.

Comments

2

What you're looking for is realloc(). It can be used to grow or shrink memory while retaining its contents.

/* array is now sizeof(int) * new_size bytes */
array = realloc(array, sizeof(int) * new_size);

realloc() might change the existing memory allocation, or it might allocate a whole new block of memory. This is why it's important to reassign the result back to the thing being reallocated.

But if addNumber() reallocates the array by making new memory, main() won't know it. This is for the same reason this doesn't work.

void incrementNumber(int num) {
    num = num + 1;
}

int num is a number that gets passed by value. If you want it to be reflected in the caller, you need to pass it as a pointer.

void incrementNumber(int *num) {
    *num = *num + 1;
}

Pointers are the same way. They're still numbers. int *a passes a pointer by value. If you change a in addNumber it won't be seen by the caller. Just like before, you need to pass it as a pointer. A pointer to a pointer used like this is known as a double pointer.

void addNumber( int **array_ptr, size_t *array_size, size_t type_size, int number ) {
    /* Increment the size and make sure that bubbles up */
    *array_size = *array_size + 1;

    /* realloc might grow the memory, or it might allocate new memory
       either way, assign the result back to its original variable
       by dereferencing the double pointer.
     */
    *array_ptr = realloc(*array_ptr, *array_size * type_size);

    /* Since it's a double pointer, we have to first dereference it before using
       it as an array */
    (*array_ptr)[*array_size - 1] = number;
}

(Note that I also pass in the sizeof the elements in the array, that can't be assumed).

This is called by passing a pointer to the array.

addNumber(&a, &size, sizeof(int), 5);

After that, everything is the same.

for( int i = 0; i < size; i++ ) {
    printf("%d ", a[i]);
}
puts("");

Eventually you'll want to improve this by having the array, size, and type in a struct so you can pass that around in a neat package.

typedef struct {
    int *array;
    size_t size;
} IntArray;

This is great to do as an exercise, you'll learn a lot and kick a lot of bad habits about static memory. But doing dynamic data structures correctly and efficiently is difficult (for example, allocating one extra slot at a time is very inefficient).

There are many, many libraries out there which provide such dynamic structures. So continue with this as an exercise, but for real code use a library such as Gnome Lib.

Comments

1

Why? Can't get the reason.

That's because you are modifying the value of a locally in addNumber. That does not change the value of a in main.

In order for main to have access to the newly allocated memory, you need to change addNumber to return the newly allocated pointer.

int* addNumber(int* a, int* size, int number){
   ...
   return a;
}

and then change main to:

if(!contains(a, size, 2)){
    a = addNumber(a, &size, 2);
    // Assign to a the new pointer value.
}

Comments

0

Your 'a' in main is already a pointer, passing it to a function passes a copy of it. What you have to do is - pass the adress '&a' and receive it in funtion as double pointer '**a' and inside the function, use dereference to get values inside array ( like *a[i] and free(*a). Change the last line to 'return temp' and collect it in main as a=addnumber(&a,&size,2);

By the way, instead of going through all these hassle why don't you just use realloc() function. It increases the size of array dynamically. After using realloc you can just add the new number at the last index.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.