Search code examples
carrayspointersstructdynamic-allocation

Difficulties to understand pointers, dynamic allocation and call to functions behaviour


I'm working in C.

I have a simple struct named Entity

typedef struct Entity
{
    int x, y;
    int velX, velY;
}Entity;

I'm creating a dynamic array of type Entity and size 1. Then I add one element with my addEntity function

void addEntity(Entity** array, int sizeOfArray)
{
    Entity* temp = malloc((sizeOfArray + 1) * sizeof(Entity));

    memmove(temp, *array, (sizeOfArray)*sizeof(Entity));

    free (*array);
    *array = temp;
}

Then I use another function to change the values of the two elements :

int main()
{
    Entity* entities = malloc(sizeof(Entity)); // dynamic array of size 1

    addEntity(&entities, 1); // add one element
    changeValue(&entities[0], 10); // change the values of the first two elemebts
    changeValue(&entities[1], 20);

    printf("%d\n", entities[0].x); // print the values
    printf("%d", entities[1].x); 

    free(entities); // free the memory

    return 0;
}

void changeValue(Entity* entity, int nb)
{
    entity->x = nb;
}

The result of this is 10 and 20, everything works fine. Now if I use this syntax instead

int main()
    {
        Entity* entities = malloc(sizeof(Entity)); // dynamic array of size 1
        addEntityAndSetValues(entities);

        printf("%d\n", entities[0].x); // print the values
        printf("%d", entities[1].x); 

        free(entities); // free the memory

        return 0;
    }

void addEntityAndSetValues(Entity* entities)
{
    addEntity(&entities, 1);
    changeValue(&entities[0], 10);
    changeValue(&entities[1], 20);
}

I don't get 10 and 20 but some random numbers. I really don't understand why.


Solution

  • Reason is C is pass by value.

    When in the second case you pass the pointer - a copy of it is passed to the function. Now when you write &entities it is the address of the local variable. And the variables in main don't see any change - because you didn't change them. So you get garbage value.

    To be more clear

    void addEntityAndSetValues(Entity* entities)
    {
        addEntity(&entities, 1); <--- entities is a local variable.
    }
    

    Now you add call addEntity:

    void addEntity(Entity** array, int sizeOfArray)
    {
        ...
        free (*array);
        *array = temp; <--- assigning to the local variable the address of the allocated chunk.
    }
    

    Then you call the other function to change it's value - those are alright. But when you return from the function then everything in that local variable is gone.

    If you do this - then it would work.

    In main()

    addEntityAndSetValues(&entities);
    

    In addEntityAndSetValues()

    void addEntityAndSetValues(Entity** entities)
    {
        addEntity(entities, 1);
        changeValue(&(*entities)[0], 10);
        changeValue(&(*entities)[1], 20);
    }
    

    Here it worked because you have passed the the address of the variable in main() and then you made changes to that variable - and every change in the value of it reflected.