Is it safe to assign a struct member pointer to another dynamically memory allocated pointer?

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

struct Test {
    const char *str;
};

void test_new(Test *test) {
    char *s = malloc(100);
    
    s[0] = 'H';
    s[1] = 'i';
    s[2] = '\0';
    
    test->str = s;
}

int main(void) {
    struct Test test;
    
    test_new(&test);
    
    puts(test.str);
    free(test.str);
    
    return 0;
}

Is this allowed? Assigning a struct member to a local variable (character pointer) in the test_new function? (Is test->str = s allowed?)

I heard that array variables, which are local when it is, are freed after the end of the function. I wonder if that applies to memory allocated local variables.

Like this:

char *test(void) {
    char s[100];
    return s;
}

s will be gone by the time the function ends, so I wonder if this applies to my struct, especially that instead of returning, I'm changing a member.

Is it safe to assign a struct member pointer (which is test->str) to another dynamically memory allocated pointer (which is s)?

2 Answers

From the test_new function lets take a look at these two lines:

// 1
char *s = malloc(100);

// 2
test->str = s;

After 1 you have something like this:

+---+     +-------------------------------+
| s | --> | memory allocated by malloc... |
+---+     +-------------------------------+

Then after 2 you have something like this:

+---+
| s | ----------\
+---+            \     +-------------------------------+
                  >--> | memory allocated by malloc... |
+-----------+    /     +-------------------------------+
| test->str | --/
+-----------+

Then once test_new returns, you have only this in the main function:

+----------+     +-------------------------------+
| test.str | --> | memory allocated by malloc... |
+----------+     +-------------------------------+

This is perfectly fine.

The allocation/assignment done in your test_new function is allowed and is safe. This is because the char *s = malloc(100); line allocates memory on the heap (not on the 'local' stack), and the test->str = s; line assigns the pointer to that allocated memory to a member of a structure passed by reference. So, that member in the structure variable of the calling code will be modified, as you intend.

What would be wrong (using the example of local memory in your second snippet) would be something like this:

void test_bad(Test *test) {
    char s[100]; // Local memory - gone when function returns
    s[0] = 'H';
    s[1] = 'i';
    s[2] = '\0';    
    test->str = s; // Pointer member of structure will be invalid after the return.
}

The above bad code will compile (it is syntactically correct) but any decent compiler will (or should) warn you about using a pointer to a local variable.

Related