简体   繁体   English

在 C 中实现快速排序的分段错误

[英]Segmentation fault implementing quicksort in C

I am trying to execute the Quick Sort code mentioned in the book Data Structures Using C by Reema Thareja.我正在尝试执行 Reema Thareja 的使用 C 的数据结构一书中提到的快速排序代码。

The issue is that I cannot get the sorted array as output.问题是我无法将排序数组作为 output。 Instead, when I add the elements in the array, the output screen disappears, and on running the code again I get the following:相反,当我在数组中添加元素时,output 屏幕消失了,再次运行代码时,我得到以下信息:

输出

I am using the Turbo C++ Version: 3.2 Compiler我正在使用 Turbo C++ 版本:3.2 编译器

#include <stdio.h>
#include <conio.h>
void quicksort(int arr[],int l,int r);
void main()
{
    int arr[10],l,r,i,n;
    printf("Enter Array size: ");
    scanf("%d",&n);
    printf("Enter Elements: ");
    for(i=0;i<n;i++)
    {
        scanf("%d",&arr[i]);
    }
    quicksort(arr,0,n-1);
    printf("The Sorted Array is: ");
    for (i = 0; i < n; i++)
    {
        printf("%d",arr[i]);
    }
    getch();
}
int partition(int arr[],int l,int r)
{
    int left,right,temp,loc,flag;
    loc=left=l;
    right=r;
    flag=0;
    while(flag!=1)
    {
        while((arr[loc]<=arr[right]) && loc!=right)
        {
            right--;
        }
        if(loc==right)
        {
            flag=1;
        }
        else if(arr[loc]>arr[right])
        {
            temp=arr[loc];
            arr[loc]=arr[right];
            arr[right]=temp;
            loc=right;
        }
        if(flag!=1)
        {
            while((arr[loc]>=arr[left])&& (loc!=left))
            {
                left++;
            }
            if(loc==left)
            {
                flag=1;
            }
            else if(arr[loc]<arr[left])
            {
                temp=arr[loc];
                arr[loc]=arr[left];
                arr[left]=temp;
                loc=left;
            }
        }
    }
    return loc;
}
void quicksort(int arr[],int l,int r)
{
    int loc;
    if(l!=r)
    {
        loc=partition(arr,l,r);
        quicksort(arr,l,loc-1);
        quicksort(arr,loc+1,r);
    }
}

Consider this function:考虑这个 function:

void quicksort(int arr[], int l, int r)
{
    int loc;
    if(l!=r)
    {
        loc=partition(arr,l,r);
        quicksort(arr,l,loc-1);
        quicksort(arr,loc+1,r);
    }
}

Here, our base case is l==r .在这里,我们的基本情况是l==r But if we add a print statement (and some spacing)但是如果我们添加一个打印语句(和一些间距)

void quicksort(int arr[], int l, int r)
{
    if (l != r)
    {
        printf("left: %d, right: %d\n", l, r);
        fflush(stdout);
      //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

        int loc = partition(arr, l, r);
        quicksort(arr, l, loc - 1);
        quicksort(arr, loc + 1, r);
    }
}

and call it with并调用它

int arr[] = {4, 8, 1, 4, 5, 1, 8, 5, 7};
int arr_len = 9;
quicksort(arr, 0, arr_len - 1);

we get the following output:我们得到以下 output:

left: 0, right: 8
left: 0, right: 1
left: 0, right: -1
exited, segmentation fault

Whoops: left was 0 and right was -1 and we called partition(arr, 0, -1);哎呀: left是0, right是-1,我们称之为partition(arr, 0, -1); which immediately does an out of bounds memory access with the statement arr[right] => arr[-1] .它立即使用语句arr[right] => arr[-1]进行越界 memory 访问。

if (l < r) was probably the intent here: if (l < r)可能是这里的意图:

void quicksort(int arr[], int l, int r)
{
    if (l < r)
    {
        int loc = partition(arr, l, r);
        quicksort(arr, l, loc - 1);
        quicksort(arr, loc + 1, r);
    }
}

which enables us to correctly establish the base case for recursion.这使我们能够正确地建立递归的基本情况。


Beyond this bug, I recommend using space between operators, selecting meaningful names and avoiding unnecessary variables.除了这个错误,我建议在运算符之间使用空格,选择有意义的名称并避免不必要的变量。 An example of this is the beginning of the partition function.这方面的一个例子是partition function 的开头。 As written, it's:如所写,它是:

int partition(int arr[],int l,int r)
{
    int left,right,temp,loc,flag;
    loc=left=l;
    right=r;
    flag=0;
// ...

But l and r are just being reassigned to left and right and then go unused for the remainder of the function.但是lr只是被重新分配给left ,然后right未用于 function 的其余部分。 Writing it like:像这样写:

int partition(int arr[], int left, int right)
{
    int temp;
    int loc = left;
    int flag = 0;
// ...

is clearer, but even here, we should move tmp (used for swaps) out to a separate function or at least scope it to the block where it's used to avoid stale value bugs.更清楚,但即使在这里,我们也应该将tmp (用于交换)移到单独的 function 或至少 scope 到用于避免陈旧值错误的块中。 We should #include <stdbool.h> because that's what int flag actually is (or use early returns to eliminate the variable altogether) and improve the loc variable name (it's actually the pivot we're partitioning the integers on):我们应该#include <stdbool.h>因为这实际上是int flag (或使用早期返回来完全消除变量)并改进loc变量名称(实际上是我们正在对整数进行分区的 pivot):

int partition(int arr[], int left, int right)
{
    int pivot = left;
    bool flag = false; // or remove this completely in favor of `return`
// ...

This is much cleaner.这干净多了。

Also, void main should be int main and use an explicit return 0 .此外, void main应该是int main并使用显式return 0 I recommend using a modern compiler and development environment and turning on all warnings:我建议使用现代编译器和开发环境并打开所有警告:

gcc quicksort.c -Wall -Wextra -Werror -O2 -std=c99 -pedantic

This reveals unused variables in main , among other things, and generally reduces pain points.这揭示了main中未使用的变量等,并且通常会减少痛点。

Also, I recommend readinghow to debug small programs which will give you the tools (both conceptual and software) necessary to walk through and reason about programs to localize errors.另外,我建议阅读如何调试小程序,这将为您提供必要的工具(概念和软件),以了解程序以定位错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM