0

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));
}
3
  • 2
    You shouldn't use spaces around the arrow -> or dot . operators. They bind very tightly; that should be shown visually by not including any spaces around them. (Yes, in terms of syntax, spaces are fine; spaces are allowed anywhere between tokens, so you could write each token on its own line. For readability, don't include spaces around arrow or dot.) Commented Oct 18, 2015 at 20:53
  • Thanks for telling me that, even though they don't really detract from the problem. Commented Oct 18, 2015 at 20:58
  • YW: that's why it is a comment, not an answer. Commented Oct 18, 2015 at 20:58

2 Answers 2

2

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 */
    ...
}
Sign up to request clarification or add additional context in comments.

3 Comments

Is this 100% impossible to do with only a FooStruct * ptr parameter in my function?
@JohnH No, it's not possible. The function can only modify its local copy.
@JohnH: Yes, it is 100% impossible with just a FooStruct *ptr parameter. You could do without the parameter and return the allocated structure; that would be legitimate. Or you can have the calling code do the memory allocation and simply have the constructor initialize the data in the previously allocated storage. This is how a C++ constructor works. The advantage is that you can then construct local variables and global variables of this type; you aren't forcing people to use dynamically allocated memory.
2

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:

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.