Your problem is misunderstanding pointers. Let's start with some very similar code that would work.
#include <string.h>
#include <stdio.h>
typedef struct { char name[10]; } Item;
typedef struct { Item item; } MyStruct; // <--- Removed the *
MyStruct make(char *name) {
MyStruct st;
Item item;
strncpy(item.name, name, 10); // <--- strncpy because name[] is a fixed length
st.item = item; // <-- Removed the &; *copies* item into st
printf("name: %s\n", st.item.name); // <-- . rather than ->
return st;
}
int main() {
MyStruct s1, s2;
s1 = make("hi");
s2 = make("hey");
printf("\nname: %s\n", s1.item.name); // <-- . rather than ->
printf("name: %s\n", s2.item.name); // <-- . rather than ->
}
In this code I got rid of the pointers and everything should work. Item
is 10 chars, and MyStruct
is also 10 chars long. When you return it, those 10 chars of memory are copied, just like an int.
But you didn't do this; you added pointers. Since item
is a local variable, it's in the current stack frame, not the heap. The stack frame disappears at the end of the current scope. (But it doesn't really disappear. It's just undefined behavior to reference it out of scope, so it can return anything.)
Doing it without pointers means more copying (though actually not that much more copying; on a 64-bit system, a pointer is 8 bytes). It also means changes to one copy don't impact the others. That's either good or bad depending on your problem. Getting rid of pointers this way can actually be a very good design as long as the struct doesn't get too big. Once you add pointers, you're going to need to manage memory and decide about ownership and when to free the memory and all the other headaches. It depends on your problem which approach is best.
As a note, if you go this way, there's no reason to create an intermediate item
(and it's inefficient to do so because it's making two copies of the string). Instead you'd just copy directly into st
:
MyStruct make(char *name) {
MyStruct st;
strncpy(st.item.name, name, 10);
printf("name: %s\n", st.item.name);
return st;
}