You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言入门疑问:结构体中字符串为何无需调用malloc?

结构体中的字符串为何无需调用malloc?

我这周刚学C语言,遇到一个想不通的矛盾点:

  • 我知道函数结束后,栈上的内容会被释放,要让变量在作用域结束后还能用得用malloc。结构体也是如此,如果不用malloc分配结构体,在创建它的函数外打印值会报错。
  • 但我发现,如果用malloc分配结构体,然后直接把char指针(字符串)赋值给结构体成员,程序能正常打印——我原本以为得先给结构体成员malloc,再拷贝字符串进去才行?

下面这段代码能正常打印结构体成员:

typedef struct person {
  char *name;
} person;

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

person *person_generator(char *name) {
  person *person = malloc(sizeof(person));
  // 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;
}

我困惑的是,为什么下面这段需要malloc成员并拷贝的代码不是必须的?

typedef struct person {
  char *name;
} person;

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

person *person_generator(char *name) {
  person *person = malloc(sizeof(person));
  // 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;
}

我本来以为create_default_person()结束后,内部的指针会被销毁,结构体成员应该指向垃圾数据才对?

补充问题:
有人说字符串字面量会在程序整个生命周期中存储,那再看这个从文件读取字符串的例子,不调用malloc直接赋值给结构体成员,为什么也能正确打印?

typedef struct person {
  char *name;
} person;

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

person *person_generator(char *name) {
  person *person = malloc(sizeof(person));
  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;
}

核心原因:字符串的存储位置决定了指针的有效性

1. 字符串字面量的特殊存储

你第一个例子里的"Alfred Hitchcock"是字符串字面量,它既不在栈上,也不在堆上,而是存在程序的静态存储区。这块内存会在程序启动时分配,直到程序结束才会释放。

所以即使create_default_person()函数执行完毕,结构体成员name指向的依然是静态存储区里的字符串字面量,内存没有被回收,自然能正常打印。

这种情况下,确实不需要给结构体的name成员malloc——因为你只是复用了静态存储区里已经存在的字符串,没有必要再拷贝一份。

2. 文件读取例子:只是“侥幸”能运行,属于未定义行为

你补充的文件读取例子里,buffer是create_default_person()函数里的栈局部数组。函数结束后,栈帧被回收,buffer占用的内存会被标记为可用,后续其他函数调用可能会覆盖这块内存。

你现在能正常打印,只是因为函数刚结束,这块内存还没被改写而已——这是完全不可靠的,属于C语言里的未定义行为。如果在print_person()之前调用其他函数,或者编译器优化等级不同,大概率会输出垃圾数据甚至程序崩溃。

这种场景下,才必须给结构体的name成员malloc,把buffer里的字符串拷贝到堆内存中,这样即使栈上的buffer被回收,堆上的字符串依然有效。

3. 什么时候需要给结构体的字符串成员malloc?

总结两种必须malloc的场景:

  • 当你要保存的字符串是栈上的局部变量(比如函数里的char数组、栈上的临时字符串);
  • 当你需要字符串的生命周期独立于原数据(比如原字符串可能被修改、释放,而结构体需要保留自己的副本)。

如果字符串本身存在静态存储区(比如字符串字面量),或者已经在堆上(比如别人malloc好传给你的),那直接赋值指针就行,不需要额外malloc。

内容的提问来源于stack exchange,提问作者Nathaniel Woodbury

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 00:11:09