5
#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)?

Jack Murrow
  • 396
  • 3
  • 11

2 Answers2

5

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Thank you for creating a picture to see what's going on. I thought of the malloc in a different way, but after looking at this, I can now see clearly what's going on. I really appreciate the way you represented memory allocation by text only. – Jack Murrow Nov 01 '20 at 17:07
2

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.

Adrian Mole
  • 49,934
  • 160
  • 51
  • 83
  • In the code you have posted, even though I'm probably never gonna make a static variable, would be creating `static char s[100];` be safe, right? – Jack Murrow Nov 01 '20 at 17:03
  • @JackMurrow You *could* use a `static` variable there, and that would be 'safe'. However, if you call that function with pointers to many *different* structures, each of those structures' pointer member will then point to the *same* `char` data. – Adrian Mole Nov 01 '20 at 17:04