C语言冒泡排序异常:偶发终止、大数组首元素为负,新手求助
问题原因分析
你的程序出现异常终止、首元素变为负数的核心问题是数组越界访问,这是C语言中典型的未定义行为触发点:
- 在
bubble_swap函数的内层循环中,循环条件写为for (j = 0; j < size; j++),当j等于size-1时,j+1就等于size,而数组grades的合法下标范围是0到size-1,此时访问grades[j+1]会读取/修改数组之外的内存区域。 - 这种越界操作会破坏其他内存数据(比如修改到
main函数里的变量或栈内存),导致程序崩溃,或者出现奇怪的数值(比如首元素变成负数)。 - 开头的函数声明(如
void print_grades();)未指定参数类型,不符合C语言规范,可能引发编译警告或潜在调用错误。 - 代码里的
NULL;是无效语句,属于冗余代码,没有任何作用。
修复方案
1. 修正冒泡排序的循环边界(核心修复)
将bubble_swap的内层循环条件改为j < size - 1 - i,既避免数组越界,也是冒泡排序的标准优化(每一轮排序后末尾的i个元素已处于有序状态,无需重复比较):
// 修正后的冒泡排序函数 void bubble_swap(int grades[], int size) { int i, j; for (i = 0; i < size; i++) // 内层循环修正边界,避免越界+减少无效比较 for (j = 0; j < size - 1 - i; j++) { // 直接判断需要交换的情况,去掉冗余else分支 if (grades[j] > grades[j+1]) { swap(&grades[j], &grades[j+1]); } } printf("\nMy sorted grades are:\n"); for (i = 0; i < size; i++) { printf("%i\t", grades[i]); } }
如果仅临时解决越界问题,至少要把内层循环改为j < size - 1,但加上-i能大幅减少不必要的比较操作。
2. 修正函数声明
将开头的函数声明改为带参数类型的形式,与函数定义完全匹配:
void print_grades(int grades[], int size); void average(int grades[], int size); void swap(int *a, int *b); void bubble_swap(int grades[], int size);
3. 移除冗余代码
直接删掉if (grades[j] < grades[j+1])分支里的NULL;语句,该分支无需执行任何操作,简化后逻辑更清晰。
4. 可选效率优化
可以加入交换标记,当某一轮排序未发生交换时,说明数组已经有序,直接提前终止循环,提升排序效率:
void bubble_swap(int grades[], int size) { int i, j; int swapped; // 标记本轮是否发生交换 for (i = 0; i < size; i++) { swapped = 0; for (j = 0; j < size - 1 - i; j++) { if (grades[j] > grades[j+1]) { swap(&grades[j], &grades[j+1]); swapped = 1; } } if (!swapped) // 本轮无交换,数组已完全有序,提前退出 break; } printf("\nMy sorted grades are:\n"); for (i = 0; i < size; i++) { printf("%i\t", grades[i]); } }
关于你的疑问解答
- 不需要改用
long或float数组,问题与数据类型无关,完全是内存越界导致的。 - 增大数组大小只是碰巧让越界访问的内存区域未破坏关键数据,属于侥幸行为,并未解决根本问题,不能依赖。
内容的提问来源于stack exchange,提问作者mrstagg
相关产品推荐
相关产品推荐

