所以我正在编写一个代码作为递归的练习。其目的是通过递归替换具有最大元素的数组的最后一个元素,按升序对整数数组进行排序。我不断得到分段错误错误,无法找出问题所在。这是代码。
#include <stdio.h>
#define N 10
void selection_sort(int array[], int length);
int main (void)
{
int array[N];
int i;
printf("Enter a series of integrs: ");
for(i = 0; i < N; i ++)
{
scanf("%d", &array[i]);
}
selection_sort(array, N);
printf("In sorted order: ");
for(i = 0; i < N; i ++)
{
printf("%d ", array[i]);
}
printf("\n");
return 0;
}
void selection_sort(int array[], int length)
{
int max = array[0];
int temp;
int i;
int maxPlace;
if (length < 2)
{
return;
}
for (i = 1; i < length; i ++)
{
if (array[i] > max)
{
max = array[i];
maxPlace = i;
}
}
temp = array[length - 1];
array[length - 1] = max;
array[maxPlace] = temp;
selection_sort(array, length - 1);
}
答案 0 :(得分:4)
因为maxPlace
可能未初始化。而且因为您输入的输入不正确,所以即使用户只输入1,您也总会得到N
个元素。
这是说明我如何追踪这一点的说明。通常情况下,我会使用Valgrind跟踪一个段错误,它会告诉我有问题的行,但是目前在OS X上已经破坏了。所以这是打印和演绎的老式方式。
首先,如果您离开已分配内存的末尾,-fsanitize=address
编译器标志将导致运行时失败,例如使用未初始化的变量。这通常可以在发生时记录错误,而不是在路上发生。它还会告诉你它发生了什么功能。
$ make
cc -fsanitize=address -Wall -Wshadow -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g `pkg-config --cflags glib-2.0` -c -o test.o test.c
cc `pkg-config --libs glib-2.0` -lssl -lcrypto -fsanitize=address test.o -o test
$ ./test
Enter a series of integrs: 5
ASAN:DEADLYSIGNAL
=================================================================
==80879==ERROR: AddressSanitizer: SEGV on unknown address 0x7ffee6679358 (pc 0x0001095a7cac bp 0x7ffee6659330 sp 0x7ffee66592b0 T0)
#0 0x1095a7cab in selection_sort (/Users/schwern/tmp/./test+0x100001cab)
#1 0x1095a78db in main (/Users/schwern/tmp/./test+0x1000018db)
#2 0x7fff73819114 in start (/usr/lib/system/libdyld.dylib+0x1114)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/Users/schwern/tmp/./test+0x100001cab) in selection_sort
==80879==ABORTING
Abort trap: 6
现在我知道它在selection_sort()
。我可以开始添加调试打印语句来缩小范围。那个for
循环是可疑的,也许你正在离开阵列,所以我从那开始。我也想知道你是否有进攻,所以我已经打印出来了。
puts("Entering loop");
for (i = 1; i < length; i ++)
{
printf("i: %d\n", i);
if (array[i] > max)
{
max = array[i];
maxPlace = i;
}
puts("Loop next");
}
puts("Leaving loop");
temp = array[length - 1];
array[length - 1] = max;
array[maxPlace] = temp;
puts("Recursing");
selection_sort(array, length - 1);
试试......
$ ./test
Enter a series of integrs: 5
Entering loop
i: 1
Loop next
i: 2
Loop next
i: 3
Loop next
i: 4
Loop next
i: 5
Loop next
i: 6
Loop next
i: 7
Loop next
i: 8
Loop next
i: 9
Loop next
Leaving loop
ASAN:DEADLYSIGNAL
不,你没有走出阵列。但你也没有递归。所以它必须在循环之后的几行代码中。好吧,标记那些。没什么好看的,当范围很小时,数字很好。
puts("1");
temp = array[length - 1];
puts("2");
array[length - 1] = max;
puts("3");
array[maxPlace] = temp;
运行那个......
$ ./test
Enter a series of integrs: 5
Entering loop
i: 1
Loop next
i: 2
Loop next
i: 3
Loop next
i: 4
Loop next
i: 5
Loop next
i: 6
Loop next
i: 7
Loop next
i: 8
Loop next
i: 9
Loop next
Leaving loop
1
2
3
ASAN:DEADLYSIGNAL
现在我知道它在3
之后和recursing
之前。这意味着它是array[maxPlace] = temp;
。好的,maxPlace
中的内容是什么?
puts("1");
temp = array[length - 1];
puts("2");
array[length - 1] = max;
printf("maxPlace: %d\n", maxPlace);
array[maxPlace] = temp;
运行那个......
$ ./test
Enter a series of integrs: 5
Entering loop
i: 1
Loop next
i: 2
Loop next
i: 3
Loop next
i: 4
Loop next
i: 5
Loop next
i: 6
Loop next
i: 7
Loop next
i: 8
Loop next
i: 9
Loop next
Leaving loop
1
2
maxPlace: 32766
ASAN:DEADLYSIGNAL
maxPlace
是32766意味着它可能包含垃圾。现在我知道什么变量是问题我可以看看它是如何声明,初始化和设置发现它永远不会被初始化的情况:如果列表按降序排序。
但我只输了一个数字,5! if (length < 2)
不应该抓住那个吗?不,因为无论您阅读了多少输入,您总是在N
元素上进行迭代。
printf("Enter a series of integrs: ");
for(i = 0; i < N; i ++)
{
scanf("%d", &array[i]);
}
如果我输入5
然后点击ctrl-d
结束输入,则scanf
只会设置array[0] = 5
。但循环将继续以1到9运行。scanf
将失败,因为stdin
已关闭。数组的其余部分将是未初始化的。
您正在排序N
个元素,而不是读取的数字。因此,无论是否初始化,您都将对10个元素进行排序。
你很幸运他们碰巧是0。
$ ./test
Enter a series of integrs: 5
In sorted order: 0 0 0 0 0 0 0 0 0 5
相反,您应该阅读N
或直到scanf
失败,以先到者为准。这也可以保护您免受垃圾输入。并且只能对读取的整数进行排序和打印,而不是数组的最大容量。
int main (void)
{
int array[N];
int num_ints;
printf("Enter a series of integrs: ");
for(num_ints = 0; num_ints < N; num_ints++)
{
if( scanf("%d", &array[num_ints]) < 1 ) {
break;
}
}
selection_sort(array, num_ints);
printf("In sorted order: ");
for(int i = 0; i < num_ints; i ++)
{
printf("%d ", array[i]);
}
printf("\n");
return 0;
}