Ошибка сегментации без параметров в main () - PullRequest
0 голосов
/ 29 июня 2018

У меня есть эта простая программа 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 () на main (int argc, char * argv []), это также работает и в 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 (и другими комбинациями) безрезультатно.

У кого-нибудь есть подсказка? Заранее спасибо

Ответы [ 3 ]

0 голосов
/ 30 июня 2018

не делайте этого:

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]);
    }
}

этот подход не обращается к элементам за пределами массива, работает в два раза быстрее, потому что он не анализирует уже отсортированную часть массива.

0 голосов
/ 08 мая 2019

Если вы так сильно хотите иметь доступ к памяти и, что более важно, изменять память, которая требует использования отрицательной индексации массива, вы должны убедиться, что эта память выделена. Вы можете использовать этот макрос для создания указателя на массив с x-многими байтами вперед и назад.

#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.

0 голосов
/ 30 июня 2018
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, с другой стороны, не должен обеспечивать вас этим заполнением и выделяет именно тот объем памяти, который вам нужен! И, следовательно, когда вы обращаетесь к памяти, которая не выделена, это вызывает ошибку сегментации, и ваша программа падает!

Проверьте эту ссылку о padding, о котором я говорю: - https://en.wikipedia.org/wiki/Buffer_overflow_protection

РЕДАКТИРОВАТЬ: - Я забыл упомянуть об этом, ваша программа работает, когда вы написали main с параметрами, потому что есть место, зарезервированное для argv[], и, к счастью, при доступе к array[j-1] вы должны быть доступ к ячейке памяти, которая доступна вам, например, argv[]. (Опять же, это объяснение очень краткое и в нем много технических аспектов!)

Надеюсь, это поможет :)

...