C语言:为何调用无关函数后未操作的字符串指针值改变?
字符串指针值意外变更的原因及修复
问题现象
使用程序提取文件中的姓与名时,出现指针内容意外被修改的情况:
- 当f1文件内容为
Martin、f2文件内容为Joseph时,调用GetPrenom(f2)能得到正确结果Joseph; - 但调用
GetNom(f1)后,原本的prenom指针指向的内容变为Martin,最终打印结果不符合预期。
问题代码
#include<stdlib.h> #include<string.h> #include <stdarg.h> char* GetNom(FILE* f1) { char* nam = malloc(25 * sizeof(char)); fseek (f1, 0, SEEK_END); int length = ftell (f1); fseek (f1, 0, SEEK_SET); char line1[length]; fgets(line1, length, f1); nam = strtok(line1, " , "); rewind(f1); return nam ; } char* GetPrenom( FILE* f2) { char* lastname = malloc(25 * sizeof(char)); fseek (f2, 0, SEEK_END); int length = ftell (f2); fseek (f2, 0, SEEK_SET); char line2[length]; fgets(line2, length, f2); lastname = strtok(line2, " ; "); rewind(f2); return lastname ; } int main() { FILE* f1 = ....; //openning the two files FILE* f2 = ....; char* prenom = GetPrenom(f2); char* nom = GetNom(f1); printf("%s \n", prenom); return 0; }
原因分析
- 栈内存被复用覆盖:函数中的
line1、line2是栈上的局部数组,函数执行完毕返回时,这块栈内存会被系统回收。strtok返回的指针指向的是这些栈数组的内存地址,后续调用GetNom时,新的栈局部变量会覆盖之前GetPrenom中line2占用的栈内存,导致prenom指针指向的内容被修改。 - 内存泄漏:函数开头用
malloc分配的内存被直接赋值为strtok的返回值,原malloc指针被丢弃,造成内存泄漏。
修复方案
将strtok分割后的字符串复制到malloc分配的堆内存中,避免返回栈内存指针:
#include<stdlib.h> #include<string.h> #include <stdarg.h> char* GetNom(FILE* f1) { char* nam = malloc(25 * sizeof(char)); if (nam == NULL) { // 检查内存分配是否成功 return NULL; } fseek (f1, 0, SEEK_END); int length = ftell (f1); fseek (f1, 0, SEEK_SET); char line1[length + 1]; // 多留一个位置存储字符串结束符 fgets(line1, sizeof(line1), f1); char* token = strtok(line1, " , "); if (token != NULL) { strncpy(nam, token, 24); // 复制到堆内存,预留结束符位置 nam[24] = '\0'; // 确保字符串以结束符收尾 } else { nam[0] = '\0'; // 处理无有效分割结果的情况 } rewind(f1); return nam ; } char* GetPrenom( FILE* f2) { char* lastname = malloc(25 * sizeof(char)); if (lastname == NULL) { return NULL; } fseek (f2, 0, SEEK_END); int length = ftell (f2); fseek (f2, 0, SEEK_SET); char line2[length + 1]; fgets(line2, sizeof(line2), f2); char* token = strtok(line2, " ; "); if (token != NULL) { strncpy(lastname, token, 24); lastname[24] = '\0'; } else { lastname[0] = '\0'; } rewind(f2); return lastname ; } int main() { FILE* f1 = fopen("f1.txt", "r"); // 补充文件打开逻辑 FILE* f2 = fopen("f2.txt", "r"); if (f1 == NULL || f2 == NULL) { perror("Failed to open file"); return 1; } char* prenom = GetPrenom(f2); char* nom = GetNom(f1); printf("%s \n", prenom); // 释放堆内存,避免泄漏 free(prenom); free(nom); // 关闭文件,释放资源 fclose(f1); fclose(f2); return 0; }
修复要点
- 不再直接返回栈数组指针,而是将分割结果复制到堆内存中返回;
- 增加
malloc成功检查,避免空指针操作; - 使用
strncpy控制复制长度,防止内存越界; - 在
main函数中补充文件关闭和堆内存释放逻辑,避免资源泄漏。
内容的提问来源于stack exchange,提问作者ConnorRK987
相关产品推荐
相关产品推荐

