Search code examples
cstructmallocc-strings

Beginner to C - Malloc Not Required For String In Struct


Why is Malloc not required to be called on string in struct?

Hi, I just started studying C this week, and I found a weird inconsistency I can't explain.

From what I know, when a function ends, the allocated items in the "stack" are removed from memory. If we want a variable to last longer past this (when the scope ends), we use malloc.

This makes total sense for structs and is consistent. If you create a struct then try to print the values outside of the scope of the function it was created - it will cause a error unless you malloc the struct.

However, I found that if I try to create a struct and malloc it with a default value (the size of the struct), then add a char pointer (string) as a struct member, it receives the value and no error is reached when trying to print it - I thought I would need to call malloc on the struct member itself, then copy the string into it?

Any ideas what is happening here??

This prints the struct member with no issue.

typedef struct person {
  char *name;
} person;

// print struct fields
void print_person(person *input) { printf("Name: %s", input->name); }

person *person_generator(char *name) {
  my_struct *person = malloc(sizeof(my_struct));
  // assign given char pointer to struct field
  person->name = name;
  return person;
}

person *create_default_person() {
  person *new_person = person_generator("Alfred Hitchcock");
  return new_person;
}

int main() {
  person *default_person = create_default_person();
  print_person(default_person);
  return 0;
}

Im confused why the following code below is not mandatory?

typedef struct person {
  char *name;
} person;

// print struct fields
void print_person(person *input) { printf("Name: %s", input->name); }

person *person_generator(char *name) {
  my_struct *person = malloc(sizeof(my_struct));
  // didnt need to do this?
  person->name = malloc(strlen(name) + 1);
  strcpy(person->name, name);
  return person;
}

char *get_string() {
  char *item = "Alfred Hitchcock";
  return item;
}

person *create_default_person() {
  char *value = get_string();
  person *new_person = person_generator(value);
  return new_person;
}

int main() {
  person *default_person = create_default_person();
  print_person(default_person);
  return 0;
}

I am expecting when "create_default_person()" function ends, the pointer it created is destroyed from the stack its inside of, then the struct member should be pointing to garbage data right?

EDIT

Additional question:

I was told the answer was that string literals are stored for the lifetime of the application. Lets take another example. Read a string from a file, then assign it into struct field without calling malloc.

Why does this still print correctly

typedef struct person {
  char *name;
} person;

void print_person(person *input) { printf("Name: %s", input->name); }

person *person_generator(char *name) {
  my_struct *person = malloc(sizeof(my_struct));
  person->name = name;
  return person;
}

person *create_default_person() {
  FILE *fp;
  fp = fopen("./data.txt", "r");
  char buffer[255];

  if (fp == NULL) {
    printf("Couldnt open\n");
    return NULL;
  }

  fgets(buffer, 255, fp);
  fclose(fp);

  person *new_person = person_generator(buffer);
  return new_person;
}

int main() {
  person *human = create_default_person();
  if (human == NULL) {
    printf("Failed to find human");
    return 0;
  }
  print_person(human);
  return 0;
}

Solution

  • In C, string literals (like "Alfred Hitchcock") are stored statically as part of the process's static data.

    As such, they are guaranteed to remain valid for the lifetime of the process, and their storage space doesn't need to be manually allocated or freed. A simple pointer to them is enough to use them, as you discovered.

    If you were making up random new names at runtime, on the other hand, you would need to explicitly allocate space for those runtime-generated strings and manage their lifetimes with malloc()/free()/etc.

    I am expecting when "create_default_person()" function ends, the pointer it created is destroyed from the stack its inside of, then the struct member should be pointing to garbage data right?

    Not quite -- the pointer gets destroyed when the function ends, but the data the pointer points to does not. The string literal itself, in this case, remains valid indefinitely, regardless of what is or is not pointing to it.