我有一个简单的Bubblesort程序,当在macOs上编译时可以正常工作,但是在linux(使用gcc)上编译时,会在运行时出现分段错误。 我很想知道为什么。
#include <stdio.h>
#include "alg_utils.h"
void bubble_sort(int *, int);
int main() {
int array[10] = {5, 10, 77, 1, -2, -61, 18, 14, 57, 7};
bubble_sort(array, 10);
print_array(array, 10);
return 0;
}
void bubble_sort(int *array, int len) {
int i, j;
for (i=0; i < len; i++) {
for (j=0; j < len; j++) {
if (array[j] < array[j-1])
swap(&array[j], &array[j-1]);
}
}
}
在Mac上:
~/Projects/Algorithms: gcc Bubblesort.c
~/Projects/Algorithms: ./a.out
-2 0 1 5 7 10 14 18 57 77%
在Linux上:
root#f95445bcd4e7:~/algos$ gcc Bubblesort.c
root#f95445bcd4e7:~/algos$ ./a.out
Segmentation fault
alg_utils.h 仅具有swap()和print_array()函数的定义。没什么疯狂的。
void print_array(int *, int);
void swap(int *, int *);
void swap(int *a, int *b) {
int temp = *b;
*b = *a;
*a = temp;
}
void print_array(int *array, int len) {
int i;
for (i=0; i < len; i++) {
printf("%4d", array[i]);
}
}
当我用main(int argc,char * argv [])更改main()时,它也可以在Linux上工作。
Linux(带有main(int argc,char * argv [])
root#f95445bcd4e7:~/algos$ gcc Bubblesort.c
root#f95445bcd4e7:~/algos$ ./a.out
-2 1 1 5 7 10 14 18 57 77
所以我想:linux不喜欢main,没有参数...但是那样的简单问候世界运行得很好。
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
所以,我很困惑。它是什么?也许是alg_utils?也许不同的C实现?我尝试使用-std = c99(和其他组合)进行编译无济于事。
有人有任何线索吗?预先谢谢你
答案 0 :(得分:1)
for (i=0; i < len; i++) {
for (j=0; j < len; j++) {
if (array[j] < array[j-1])
swap(&array[j], &array[j-1]);
}
}
在for循环中,您尝试访问array[j-1]
,因此当j=0
的值实际上是在尝试访问不在数组中的内存位置时,该内存位置可能未分配给您会因此而导致分段错误。
现在,C编译器的行为会因操作系统,编译器版本等诸多因素而有所不同。据我所知,Mac OS必须在数组前后保留一些填充,以便即使您访问这些内存位置,程序不会崩溃(再次,我在这里太简短了,还有更多内容!)。另一方面,Linux一定不能为您提供这种填充,而是要分配所需的确切内存量!因此,当您访问未分配的内存时,它会导致分段错误并导致程序崩溃!
检查此链接以了解我正在谈论的填充:-https://en.wikipedia.org/wiki/Buffer_overflow_protection
编辑:-我忘记提及这一点,当您编写带有参数的main时,您的程序可以工作是因为argv[]
保留了一些空间,幸运的是访问{{1 }}您必须访问可供您使用的存储位置,即array[j-1]
。 (同样,此解释非常简短,并且涉及许多技术方面!)
希望这会有所帮助:)
答案 1 :(得分:0)
不要这样做:
for (i=0; i < len; i++) {
for (j=0; j < len; j++) {
if (array[j] < array[j-1])
swap(&array[j], &array[j-1]);
}
}
改为使用此:
for (i=0; i < len; i++) {
for (j=i+1; j < len; j++) {
if (array[i] < array[j])
swap(&array[i], &array[j]);
}
}
这种方法不会访问超出数组限制的元素,因为它不会分析数组中已经排序的部分,所以工作速度快两倍。
答案 2 :(得分:0)
如果您非常想能够访问,更重要的是要修改需要使用负数组索引的内存,则必须确保已分配此内存。您可以使用此宏来创建一个指向数组的指针,该数组具有前后多个字节。
#define ARRAY(type, name, nItems) type _##name##_source[nItems * 2] = {0}, \
*name = _##name##_source + nItems
ARRAY0(char, arr, 4);
arr[-1] = 'h';
arr[0] = 'e';
arr[1] = 'y';
printf("%s\n", &arr[-1]);
如果不分配,则为未定义行为。在大多数情况下,如果不写该内存就可以了,因为该内存肯定仍属于该进程,尤其是使用argc
和argv
时。