zxgear
zxgear

Reputation: 1168

Initialization function (i.e. "constructor") for struct, why are variables not being initialized properly?

I have an unnamed structure called `FooStruct', and I wrote a function for it that initializes all its variables and also takes care of dynamic memory allocation.

I tried running this code, but it is not producing the results that I am expecting. For some reason, the variables are initialized correctly when inside the function, but then they change again once the block is exited.

A project that I'm working on requires that I use unnamed structs only. Why is this happening?

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

typedef struct {
    int fooPrimitive;
} FooStruct;

void FooStructInit(FooStruct * ptr, int num) {
    ptr = (FooStruct*)malloc(sizeof(FooStruct));
    ptr -> fooPrimitive = num;

    // Expected output: 5
    // Actual output: 5
    printf("ptr -> fooPrimitive: %d\n", (ptr -> fooPrimitive));
}

int main() {
    FooStruct * ptr;
    FooStructInit(ptr, 5);

    // Expected output: 5
    // Actual output: some random number
    printf("FooStruct -> fooPrimitive: %d\n", (ptr -> fooPrimitive));
}

Upvotes: 0

Views: 42

Answers (2)

cadaniluk
cadaniluk

Reputation: 15229

When you pass ptr to FooStructInit, it is copied and this copy is assigned the return value of malloc then. This is called pass-by-value. Instead, pass a pointer to ptr to actually write to ptr and not just the passed argument:

void FooStructInit(FooStruct** ptr, int num) {
    *ptr = malloc(sizeof(FooStruct));
    (*ptr)->fooPrimitive = num;

    // Expected output: 5
    // Actual output: 5
    printf("(*ptr)->fooPrimitive: %d\n", ((*ptr)->fooPrimitive));
}

int main() {
    FooStruct* ptr;
    FooStructInit(&ptr, 5);

    // Expected output: 5
    // Actual output: 5
    printf("FooStruct->fooPrimitive: %d\n", (ptr->fooPrimitive));
}

Notes:

Upvotes: 2

PC Luddite
PC Luddite

Reputation: 6088

C only has pass by value semantics, so when you pass a pointer to a function, the original value of the pointer is not changed, only the local copy is changed in the function.

The way to get around this is to pass a pointer to a pointer, so that you can change the value at the original memory location.

void FooStructInit(FooStruct **ptr, int num) {
    *ptr = malloc(sizeof(FooStruct));
    ...
}

int main(void) {
    FooStruct * ptr;
    FooStructInit(&ptr, 5); /* get the address of the pointer */
    ...
}

Upvotes: 2

Related Questions