函数局部变量validTugboatCount出现随机异常行为求助
拖船排序函数中变量值异常的排查与解决
问题描述
编写程序计算拖船与主船的距离并按远近排序,同时移除位置无效的拖船时,sortTugboats函数内的局部变量validTugboatCount出现异常:
- 循环统计有效拖船数后,变量值正确(例如4);
- 调用
mergeSort后,变量值变为随机垃圾值; - 在循环后添加
printf输出该变量,值又能保持正确。
尝试统一使用long long int参数后问题仍存在,需排查根本原因。
相关代码片段
初始代码
void sortTugboats(tugboat * unsorted, long long int tugboatCount){ long long int validTugboatCount = 0; for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validTugboatCount++; } // validTugboatCount 此时值正确,比如4 tugboat validUnsorteds[validTugboatCount]; // 数组大小为4 for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validUnsorteds[i] = unsorted[i]; } mergeSort(validUnsorteds, 0, validTugboatCount-1); // 此处validTugboatCount变为随机值,比如140733193388031 unsorted = validUnsorteds; }
添加printf后的代码
void sortTugboats(tugboat * unsorted, long long int tugboatCount){ long long int validTugboatCount = 0; for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validTugboatCount++; } // validTugboatCount 此时值正确,比如4 printf("%lld\n", validTugboatCount); // 输出4 tugboat validUnsorteds[validTugboatCount]; // 数组大小为4 for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validUnsorteds[i] = unsorted[i]; } mergeSort(validUnsorteds, 0, validTugboatCount-1); // validTugboatCount 值保持4 }
问题根源分析
数组越界写入破坏栈内存
第二个循环遍历的是所有拖船数tugboatCount,但validUnsorteds数组的大小是有效拖船数validTugboatCount(必然小于等于tugboatCount)。当i超过validTugboatCount-1时,对validUnsorteds[i]的赋值会越界,直接覆盖栈上的其他变量内存(恰好是validTugboatCount的存储位置),导致其值被篡改。printf的“伪修复”原理
添加printf后,栈的布局被改变:printf的调用会在栈上分配额外空间,使得越界写入的位置不再覆盖validTugboatCount的内存。这只是巧合掩盖了问题,并未真正修复数组越界的根本错误。额外问题:局部数组无法传递到外部
unsorted = validUnsorteds;仅修改了函数内的局部指针,不会影响外部传入的指针。且validUnsorteds是栈上的局部数组,函数结束后会被销毁,外部无法安全访问该数组内容。
修复方案
1. 修正数组填充逻辑
使用独立的索引变量填充有效拖船数组,避免越界:
int idx = 0; for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validUnsorteds[idx++] = unsorted[i]; }
2. 改用动态内存分配
栈上的变长数组(VLA)存在大小限制且函数结束后销毁,改用堆内存分配解决内存生命周期问题:
tugboat* sortTugboats(tugboat * unsorted, long long int tugboatCount){ long long int validTugboatCount = 0; for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validTugboatCount++; } // 动态分配内存 tugboat* validUnsorteds = malloc(sizeof(tugboat) * validTugboatCount); if(!validUnsorteds) return NULL; // 处理内存分配失败情况 int idx = 0; for(int i = 0; i < tugboatCount; i++){ if(!unsorted[i].isInvalid) validUnsorteds[idx++] = unsorted[i]; } mergeSort(validUnsorteds, 0, validTugboatCount-1); return validUnsorteds; // 返回动态分配的数组,外部调用者需负责用free释放内存 }
3. 检查mergeSort实现
确保mergeSort内部没有数组越界访问的逻辑,避免进一步破坏栈内存。
内容的提问来源于stack exchange,提问作者C͝͡e̷͢pt̡̕i̴̸͘u͜͠͝m
相关产品推荐
相关产品推荐

