一个由快速排序引发的段错误
2015-05-20 16:42
405 查看
今天在实现一个查找功能的时候,需要用到排序,因为用的是C开发,就把自己之前写的快速排序算法直接拿来用了。代码如下:
编译->运行,出现的结果是:Segmentation fault(core dumped)。看到这个报错,我首先想到的是数组越界了,可是不管怎么检查,也没有找到越界的地方。
实在是找不出错误来,于是我就干脆把快排重新写一遍,编译运行成功了。然后一对比,开始我以为我找到原因了,是在代码的第3行:if(left < right)应为if(left <= right),这的确是一个错误,但是却不是导致段错误的原因。因为,即便是没有‘=’,程序也会运行下去的。也就是说,若出现left == right,则在代码的28行这个新的递归中,是会返回来从而结束掉递归的。
到底是哪里有问题?我分享了代码的很多处都没有找到原因,但是,我注意到一个细节:当我传入的数组的元素为5的时候,是会出现Segmentation fault(core dumped)错误,但是当我传入的数组元素为12的时候,却顺利运行。以这一点为突破口,我将传入的数组元素设为了5,然后使用了gdb调试。
传入的原始数组为 83 86 77 15 93,下面是排序的过程:
第一次递归调用后,数组就已经拍好了:15 77 83 86 93,且此时基准数base的位置i为2,left为0。接着进入下一个递归Quick(array,left,i-1);
新的递归中left = 0,right = 1,经过13~25行的排序后,基准数base的位置i为0,left还是为0。程序进入下一个递归Quick(array,left,i-1),注意到递归中传入的第三个参数为i-1,而此时i = 0,所以,递归调用传入的第三个参数实际上是负值。在我的计算机中为4294967295,这个值也是新的递归中right的值。
但是,导致Segmentation fault(core dumped)错误的原因,真的是简单的数组越界吗?我仔细思考了一下觉得有两个原因:
不断递归导致的入栈过程,最终导致栈溢出;
数组越界;
乍一看这里应该是情形2的,因为传入的参数是一个越界值。但是,事实上我使用单步调试的时候,在引用array[4294967295]的时候并没有报错。最终的报错的位置为”Quick(array=0x8048034,left = 100,right=17“,从这一句基本结合上面的越界未报错,基本可以判定应该是栈溢出了。
但是这样的判断还是错的。我写了下面的测试程序:
实验结果显示,直到174544次递归调用,才出现了栈溢出的现象。而我统计快排序中的递归次数,发现在第三次就出现段错误了,这到底是怎么回事?
最终修改过后的程序如下:
虽然问题解决了,但是我还是不知道确切的出错原因,希望知道答案的大牛能解答一下。
static void QuickSort(ElemType *array,int left,int right) { if(left > right) { return; } int i,j; ElemType temp, base; base = array[left]; i = left; j = right; while(i < j) { //顺序很重要,要先从右边开始找 while(array[j] >= base && j > i) { j--; } array[i] = array[j]; while(array[i] <= base && i < j) { i++; } array[j] = array[i]; } //最终将基准数归位 array[i] = base; QuickSort(array,left,i-1);//继续处理左边的,这里是一个递归的过程 QuickSort(array,i+1,right);//继续处理右边的 ,这里是一个递归的过程 }
编译->运行,出现的结果是:Segmentation fault(core dumped)。看到这个报错,我首先想到的是数组越界了,可是不管怎么检查,也没有找到越界的地方。
实在是找不出错误来,于是我就干脆把快排重新写一遍,编译运行成功了。然后一对比,开始我以为我找到原因了,是在代码的第3行:if(left < right)应为if(left <= right),这的确是一个错误,但是却不是导致段错误的原因。因为,即便是没有‘=’,程序也会运行下去的。也就是说,若出现left == right,则在代码的28行这个新的递归中,是会返回来从而结束掉递归的。
到底是哪里有问题?我分享了代码的很多处都没有找到原因,但是,我注意到一个细节:当我传入的数组的元素为5的时候,是会出现Segmentation fault(core dumped)错误,但是当我传入的数组元素为12的时候,却顺利运行。以这一点为突破口,我将传入的数组元素设为了5,然后使用了gdb调试。
传入的原始数组为 83 86 77 15 93,下面是排序的过程:
第一次递归调用后,数组就已经拍好了:15 77 83 86 93,且此时基准数base的位置i为2,left为0。接着进入下一个递归Quick(array,left,i-1);
新的递归中left = 0,right = 1,经过13~25行的排序后,基准数base的位置i为0,left还是为0。程序进入下一个递归Quick(array,left,i-1),注意到递归中传入的第三个参数为i-1,而此时i = 0,所以,递归调用传入的第三个参数实际上是负值。在我的计算机中为4294967295,这个值也是新的递归中right的值。
但是,导致Segmentation fault(core dumped)错误的原因,真的是简单的数组越界吗?我仔细思考了一下觉得有两个原因:
不断递归导致的入栈过程,最终导致栈溢出;
数组越界;
乍一看这里应该是情形2的,因为传入的参数是一个越界值。但是,事实上我使用单步调试的时候,在引用array[4294967295]的时候并没有报错。最终的报错的位置为”Quick(array=0x8048034,left = 100,right=17“,从这一句基本结合上面的越界未报错,基本可以判定应该是栈溢出了。
但是这样的判断还是错的。我写了下面的测试程序:
#include<stdio.h> #include<stdlib.h> static void test(int a); int main(void) { test(0); return 0; } static void test(int a) { int b; b = ++a; printf("This is the %dth recursion.\n",b); test(b); }
实验结果显示,直到174544次递归调用,才出现了栈溢出的现象。而我统计快排序中的递归次数,发现在第三次就出现段错误了,这到底是怎么回事?
最终修改过后的程序如下:
static void QuickSort(ElemType *array,int left,int right) { if(left >= right) { return; } int i,j; ElemType temp, base; base = array[left]; i = left; j = right; while(i < j) { //顺序很重要,要先从右边开始找 while(array[j] >= base && j > i) { j--; } if(i < j) { array[i++] = array[j]; } while(array[i] <= base && i < j) { i++; } if(i < j) { array[j--] = array[i]; } } //最终将基准数归位 array[i] = base; if(i == 0) { return; } QuickSort(array,left,i-1);//继续处理左边的,这里是一个递归的过程 QuickSort(array,i+1,right);//继续处理右边的 ,这里是一个递归的过程 }
虽然问题解决了,但是我还是不知道确切的出错原因,希望知道答案的大牛能解答一下。
相关文章推荐
- WINXP下的一个由AcroRd32Info.exe引发的错误
- 一个空格引发的错误
- 一个分号引发的错误
- 没有空参构造函数引发的一个错误
- 一个=号引发的错误.......
- SpinBox引发的一个错误
- 一个VC编译错误引发的对显示类型转换的思考(static_cast、dynamic_cast和const_cast)
- 一个有关全局变量引发的错误。
- 遇到一个<iostream>引发的非常难缠的连接错误LNK2001
- 关于一个"="与"+="号引发的错误
- 一个null引发的错误
- 记一个iOS开发中cell的重用机制引发的错误
- 一个翻译错误引发的焦虑
- 一个Maven插件引发的错误
- mysql中一个普通ERROR 1135 (HY000)错误引发的血案
- 第一次犯一个括号位置引发的逻辑错误
- 一个逗号引发的问题 js错误
- 一个对象合并的函数引发的错误
- 一个隐式转换引发的执行计划错误
- 一个toLocaleDateString引发的错误