Valgrind报Invalid read错误求助:C语言数组操作内存问题排查
Valgrind报错解析与代码问题修复
报错含义解释
Valgrind给出的核心报错信息:
16958 Invalid read of size 4
16958 at 0x109637: arr_del (in /home/students/s/smelov.vp/lab3/lab3)
16958 Address 0x4a19938 is 0 bytes after a block of size 24 alloc'd
- Invalid read of size 4:程序尝试读取一块不属于自身的内存区域,读取的是4字节(对应C语言的
int类型)。 - 报错触发点在
arr_del函数,访问的地址刚好是arr_corr中realloc分配的内存块的末尾边界,属于数组越界访问。
代码中的具体问题
1. arr_del函数的越界读取
arr_del的循环逻辑错误:
for(size_t i=index; i<(size_t)(*s); i++){ arr[i]=arr[i+1]; }
数组当前有效元素个数是*s,合法索引范围是0到*s-1。当循环执行到i = *s - 1时,i+1等于*s,此时访问arr[i+1]就是读取数组边界外的内存,直接触发Valgrind报错。
修复方式:修改循环条件,避免访问超出数组边界的位置:
for(size_t i=index; i < (size_t)(*s) - 1; i++){ arr[i] = arr[i+1]; }
2. arr_corr函数的越界写入与潜在死循环
arr_corr的循环存在两个致命问题:
(*s) = (*s)+1; arr = (int*) realloc(arr, (size_t)(*s) * sizeof(int)); for(size_t i = (size_t)((*s)-1); i>=index; i--){ arr[i+1] = arr[i]; }
- 越界写入:
*s已经加1,新数组的有效索引范围是0到*s-1,但循环中i从*s-1开始,arr[i+1]对应arr[*s],属于数组边界外的内存,会导致非法写入。 - 潜在死循环:
size_t是无符号整数类型,若index为0,当i减到0后执行i--会变成SIZE_MAX(无符号整数的最大值),循环条件i >= index永远为真,引发死循环。
修复方式:先基于原数组大小移动元素,再扩容更新数组大小:
int old_size = *s; // 从原数组末尾开始向前移动元素,避免覆盖 for(size_t i = old_size; i > index; i--){ arr[i] = arr[i-1]; } // 扩容并更新数组大小 (*s) = old_size + 1; arr = (int*)realloc(arr, (size_t)(*s) * sizeof(int));
3. main函数的未初始化变量
main中int *arr;和int s;均未初始化:
arr未初始化直接传给realloc,虽然realloc(NULL, ...)等价于malloc,但属于不良编码习惯,建议初始化为NULL。s未初始化时,*s是随机垃圾值,直接执行(*s) = (*s)+1会导致未定义行为,必须初始化为0(表示初始数组为空)。
修复后的main函数片段:
int main(){ int input=0; int *arr = NULL; // 初始化空指针 int s = 0; // 初始数组大小为0 size_t index; scanf("%d", &input); switch(input){ // 其余逻辑保持不变 } }
总结
这些问题均属于典型的数组越界访问和未初始化变量导致的内存错误,修复后Valgrind的报错会消失,程序的内存操作也会变得安全合规。
内容的提问来源于stack exchange,提问作者Heat
相关产品推荐
相关产品推荐

