调试问题:双向链表指针链接异常原因排查
问题根源:数组越界写入破坏了
prev指针 你的链表链接问题完全是数组越界写入导致的内存破坏,具体分析如下:
1. 越界写入的触发点
在main函数的文件读取循环中,这段代码存在明显的内存访问错误:
size_t noBytesRead = fread(tmp->text, sizeof(char), CAPACITY, pFile); tmp->text[noBytesRead] = '\0';
你定义的CAPACITY是128,blob结构体的text数组大小也为128个字符。数组下标从0开始,所以text的有效索引范围是0~127。当fread刚好读取128字节(即noBytesRead == CAPACITY)时,tmp->text[noBytesRead]等价于tmp->text[128]——这已经超出了数组的合法边界,属于非法内存写入。
2. 为什么会破坏prev指针
C语言中结构体成员是按声明顺序连续存储的,你的blob结构体内存布局大致是:
struct blob { char text[CAPACITY]; // 占用128字节 struct blob* prev; // 紧跟在text数组之后(通常4/8字节,取决于平台) struct blob* next; };
向text[128]写入'\0'时,这个字节会直接覆盖prev指针的部分或全部内存,篡改了prev的地址值,导致它无法正确指向前一个节点,最终出现链接异常。
3. 为什么直接调用insertAtTail的场景没问题
在那个测试场景中,你没有对text数组进行任何写入操作,自然不会触发越界写入,prev指针的内存没有被破坏,链表链接也就正常。
修复方案
最安全的修复方式是调整fread的读取长度,预留一个字节给字符串终止符:
// 最多读取CAPACITY-1个字节,留位置存'\0' size_t noBytesRead = fread(tmp->text, sizeof(char), CAPACITY - 1, pFile); tmp->text[noBytesRead] = '\0';
这样无论读取多少字节,tmp->text[noBytesRead]都不会超出数组边界,从根源上避免了内存破坏。
另外补充一个小建议:feof的判断逻辑可以优化——feof只有在尝试读取超出文件末尾后才会被置位,更稳妥的写法是先执行读取操作,再根据读取结果判断是否到达文件末尾或读取失败。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

