C语言:调用void函数后字符串指针变量值丢失的问题
问题:void版本星期字符串函数无法正确传递结果的原因
问题场景
你需要实现一个void dayWeekStr(DatePtr date, char *buffer)函数,将日期对应的星期字符串存入传入的buffer中。你最初的实现是在函数内通过switch给buffer赋值字符串常量,main函数中传入未初始化的字符指针strDay,但运行后main里无法获取到正确的星期字符串——函数内部打印buffer是对的,但回到main后strDay为空。而改成返回char*的版本却能正常运行。
有问题的void版函数代码
void dayWeekStr(DatePtr date,char *buffer) { switch (dayWeek(date)) { case 0: buffer="Sunday"; break; case 1: buffer="Monday"; break; case 2: buffer="Tuesday"; break; case 3: buffer="Wednesday"; break; case 4: buffer="Thursday"; break; case 5: buffer="Friday"; break; case 6: buffer="Saturday"; break; default: printf("ERROR\n"); break; } }
对应的main函数代码片段
char *strDay; dayWeekStr(date1,strDay); printf("Date: %s, %s\n",strDay,s);
核心原因
这是C语言值传递机制导致的:
- 当你把
strDay传入dayWeekStr时,传递的是strDay这个指针变量的副本——函数里的buffer是一个新的指针变量,只是和strDay指向同一个地址(但这里strDay未初始化,本身就是野指针,指向随机内存)。 - 你在函数里执行
buffer="Sunday",只是把buffer这个副本的指向改成了字符串常量"Sunday"的地址,但main里的strDay根本没被修改,它还是原来的野指针状态,所以打印时输出为空甚至可能崩溃。 - 而返回
char*的版本能正常运行,是因为函数返回了字符串常量的地址,main里的strDay直接接收了这个地址,自然能访问到正确的字符串。
另外,main里的char *strDay;是未初始化的野指针,本身就存在内存访问风险,这也是问题的一个诱因。
正确的void版本实现
要让void版本的函数正确传递结果,有两种常见方案:
方案1:调用者提供足够大的缓冲区,用字符串复制
让main函数提前分配好足够容纳最长星期字符串的缓冲区(比如数组),函数内部用strcpy把字符串复制到缓冲区里:
#include <string.h> // 必须包含string.h头文件以使用strcpy void dayWeekStr(DatePtr date, char *buffer) { // 用数组存储星期字符串,比switch更简洁 const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; int day_num = dayWeek(date); if (day_num >= 0 && day_num <= 6) { strcpy(buffer, weekdays[day_num]); } else { strcpy(buffer, "ERROR"); } }
对应的main函数修改:
// 定义足够大的字符数组作为缓冲区,避免野指针问题 char strDay[20]; dayWeekStr(date1, strDay); printf("Date: %s, %s\n", strDay, s);
方案2:函数内部分配内存,传递指针的指针
如果需要动态分配内存,需要传递指针的指针(char **buffer),这样函数才能修改main里指针变量的指向:
#include <string.h> #include <stdlib.h> // 包含malloc所需的头文件 void dayWeekStr(DatePtr date, char **buffer) { const char *weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"}; int day_num = dayWeek(date); if (day_num >= 0 && day_num <= 6) { // 分配足够存储字符串的内存(+1是为了存结束符'\0') *buffer = malloc(strlen(weekdays[day_num]) + 1); strcpy(*buffer, weekdays[day_num]); } else { *buffer = malloc(6); // "ERROR"加结束符共6个字符 strcpy(*buffer, "ERROR"); } }
对应的main函数修改:
char *strDay = NULL; dayWeekStr(date1, &strDay); printf("Date: %s, %s\n", strDay, s); // 使用完毕后必须释放内存,避免内存泄漏 free(strDay); strDay = NULL;
内容的提问来源于stack exchange,提问作者Frank S.
相关产品推荐
相关产品推荐

