您的位置:首页 > 其它

一个由快速排序引发的段错误

2015-05-20 16:42 405 查看
  今天在实现一个查找功能的时候,需要用到排序,因为用的是C开发,就把自己之前写的快速排序算法直接拿来用了。代码如下:

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);//继续处理右边的 ,这里是一个递归的过程
}


  虽然问题解决了,但是我还是不知道确切的出错原因,希望知道答案的大牛能解答一下。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: