未使用的int变量为何会显著影响C语言代码运行?
问题根源分析
让我来帮你拆解这个奇怪的现象——你遇到的问题本质是两个代码错误叠加,再加上全局变量内存布局的巧合,才导致了“有无int p=0;程序表现完全不同”的情况:
1. copystring函数的字符串终止逻辑错误
先看你的字符串复制函数:
void copystring(char *s, char *t) /* copy t to s*/ { while(*t!='\0'){ *s=*t; s++; t++; } s++; *s='\0'; }
这里的核心问题是:
- 循环结束时,
s已经精准指向了应该写入终止符'\0'的位置(也就是t中'\0'对应的位置),但你多执行了一次s++,才写入终止符。 - 这就导致复制后的字符串没有正确终止:原字符串最后一个字符和
'\0'之间多了一个未初始化的垃圾字节。当printf输出时,会从起始地址一直读取,直到遇到某个'\0'——如果这个垃圾字节不是'\0',就会越界读取后续内存。
2. allocbuf函数的剩余内存判断完全错误
再看内存分配函数的判断逻辑:
if(BUFSIZ+allcp-alloc<n){ printf("Buf full, cannot assign memory!\n"); return 0; }
这个计算逻辑完全搞反了:
- 正确的剩余内存应该是
alloc + BUFSIZ - allcp(起始地址+总内存大小 - 当前可用地址),表示还能分配的字节数。 - 你写的
BUFSIZ + allcp - alloc,实际是BUFSIZ + 已使用内存大小,这个值永远远大于n=ASSIGNLEN,所以内存已满的判断永远不会触发,程序会一直分配内存,直到allcp超出alloc数组的合法范围,访问非法内存。
为什么int p=0;存在时程序看似正常?
这是全局变量内存布局的巧合:
- 全局变量
alloc、allcp、lineptr、p会被放在程序的全局数据区,且顺序由编译器按声明顺序排列。 - 当
copystring越界写入时,刚好写到了p的内存位置——而p被初始化为0,这个0就充当了字符串的终止符,让printf停止读取,不会继续越界到更危险的区域。 - 当你删除
p后,lineptr后面的内存是未初始化的垃圾数据,没有'\0',printf就会一直读取,直到触发内存访问错误EXC_BAD_ACCESS。
修正后的代码
针对以上两个错误,修改后的代码如下:
修正copystring函数
void copystring(char *s, char *t) /* copy t to s*/ { while(*t!='\0'){ *s=*t; s++; t++; } *s='\0'; // 直接在当前位置写入终止符,无需额外s++ }
修正allocbuf函数的内存判断逻辑
char *allocbuf(void) { int n = ASSIGNLEN; // 正确计算剩余内存:总大小 - 已使用大小 if( (alloc + BUFSIZ - allcp) < n ){ printf("Buf full, cannot assign memory!\n"); return 0; } else{ allcp += ASSIGNLEN; return allcp-ASSIGNLEN; } }
另外,建议在readcontent里增加对lineptr数组越界的判断,避免超过NUMLINES的限制:
// 在调用allocbuf前先检查行数是否超出上限 if(i >= NUMLINES) { printf("Too many lines!\n"); break; } copystring((lineptr[i]=allocbuf()), temp);
这样修改后,无论有无int p=0;,程序都能稳定运行,不会再出现内存访问错误。
内容的提问来源于stack exchange,提问作者Chen
相关产品推荐
相关产品推荐

