C语言指针异常:print语句前后指针输出值不同的原因与修复
问题原因与修复方案
问题原因
你在set函数里定义的char arr[25]是局部栈变量,它的内存分配在函数调用栈上。当set函数执行完毕返回main时,这块栈内存会被系统标记为可复用空间,但database[code].name还指向这个已经失效的内存地址——这就是所谓的野指针。
在display函数中,第一条printf执行时,这块失效的内存还没被新的操作覆盖,所以碰巧能打印正确字符;但执行打印表头的printf时,函数内部的栈操作会覆盖原arr的内存区域,此时野指针指向的内容已经变成随机垃圾数据,因此输出未知字符。
如果把set里的代码移到main函数中,arr就成为main的局部变量,main函数执行期间栈内存不会被回收,指针始终有效,自然不会出现问题。
修复方案
方案1:使用静态局部变量
将set函数里的arr改为静态变量,它的内存会分配在全局数据区,函数结束后不会被释放:
#include <stdio.h> #include <string.h> struct team { int code; char *name; } database[32]; void set(int code){ static char arr[25]; // 添加static关键字 printf("Enter Team Name: "); fgets(arr, sizeof(arr), stdin); // 替换不安全的gets,避免缓冲区溢出 arr[strcspn(arr, "\n")] = '\0'; // 去除fgets读取的换行符 database[code].name = arr; } // display和main函数不变
注意:静态变量是全局共享的,后续调用set会覆盖之前存储的队名,仅适用于单一条目存储的场景。
方案2:动态分配堆内存
使用malloc在堆上分配内存,堆内存不会随函数结束自动释放,可存储多个独立的队名,但需要手动释放避免内存泄漏:
#include <stdio.h> #include <stdlib.h> #include <string.h> struct team { int code; char *name; } database[32]; void set(int code){ char arr[25]; printf("Enter Team Name: "); fgets(arr, sizeof(arr), stdin); arr[strcspn(arr, "\n")] = '\0'; // 分配足够存储字符串的堆内存,+1用于存放终止符'\0' database[code].name = malloc(strlen(arr) + 1); if (database[code].name != NULL) { // 检查内存分配是否成功 strcpy(database[code].name, arr); } } void display(int first, int last) { printf("Name Before line: %c\n", *database[1].name); printf("Team Code\tTeam Name\t\tGroup Seeding\tPrimary Kit Colour\n"); printf("Name After line %c", *database[1].name); } int main() { for (int i = 0; i < 32; i++) { database[i].code = 1; database[i].name = NULL; // 初始化改为NULL,便于后续判断是否需要释放 } set(1); display(0, 32); // 程序结束前释放堆内存 for (int i = 0; i < 32; i++) { if (database[i].name != NULL) { free(database[i].name); } } return 0; }
这个方案更灵活,支持存储多个不同的队名,但必须记得在不需要使用内存时调用free释放,否则会造成内存泄漏。
另外,原代码中的gets函数存在严重的缓冲区溢出风险,已被C标准废弃,因此替换为更安全的fgets函数。
内容的提问来源于stack exchange,提问作者user20498320
相关产品推荐
相关产品推荐

