Ошибка сегментации shmat() с 2d-массивом

Попытка выделить 2d массив в разделяемой памяти. Выполнение возвращает ошибку сегментации во время присваивания (я думаю). Должен ли я выполнять задания по-другому? Это мой код:

...
#define KEYSM 46378 
#define X 10
#define Y 10

int main(){
 int i, j;
 int shm_id;
 int **addressArray;

 if ((shm_id = shmget(KEYSM, sizeof(int[X][Y]), IPC_CREAT | 0666)) == -1){
   perror("shmget");
   exit(-1);
 }

 if ((addressArray = (int **)shmat(shm_id, NULL, 0)) == (int **)-1){
   perror("shmat");
   exit(-1);
 }

 for(i = 0; i < X; i++){
   for(j = 0; j < Y; j++){
      if (i % 2 != 0)
         addressArray[i][j] = -1;
      else
         addressArray[i][j] = 0;
   }
 }
...
}

В коде есть несколько проблем еще до того, как он скомпилируется: отсутствие ) в строке shmat, необъявленные i и j и , вместо ; во втором for. Тогда у вас есть 2 логические проблемы: if в циклах бесполезен, вы все равно перезаписываете значение, а int **addressArray не является двумерным массивом int (*addressArray)[Y] для этого можно использовать.

mch 16.12.2020 11:08

Спасибо за ваш ответ. Я сделал несколько ошибок, написав код здесь. Я не хотел копировать весь свой код, поэтому решил переписать его здесь, не проверяя на компиляторе, работает ли он. Так что спасибо, что избавились от моих опечаток.

hawk 16.12.2020 11:15

После исправления опечаток это связано с: stackoverflow.com/questions/36890624/malloc-a-2d-array-in-c Неважно, откуда блок памяти: malloc или shmat

mch 16.12.2020 11:21

TLDR: int **addressArray; не является «двумерным массивом», что бы вам ни говорили. Смотрите Правильное размещение многомерных массивов для хорошего объяснения.

Andrew Henle 16.12.2020 12:22

А использование двух строк, таких как addressArray = shmat(shm_id, NULL, 0); if ( addressArray == -1 ) ..., предотвращает создание ошибок, подобных той, что была в исходном коде. Втиснуть присваивание в оператор if — плохая идея, подверженная ошибкам, и вы уже видели, почему.

Andrew Henle 16.12.2020 12:24
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
5
144
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Segfault — это ошибка времени выполнения, но ваш код даже не должен компилироваться, посмотрите на этот оператор (круглые скобки отсутствуют):

if ( ( addressArray = ( int** ) shmat ( shm_id, NULL, 0 ) == ( int** ) -1 )

А если это задание провалится? Завершает ли perror процесс? Нет. Но вы по-прежнему получаете доступ к массиву ниже. Скорее всего источник ошибки seg.

Как указал МЧ:

// i is not declared
for(i = 0; i < X; i++){
    // j is not declared, after j < Y, use semicolon instead of comma
    for(j = 0; j < Y, j++){
        // if the result is not zero you're doing an assignment
        if (i % 2 != 0)
            addressArray[i][j] = -1;
        // but immediately after you assign a zero, 
        // previous statement -> useless
        // 'else' is missing here
        addressArray[i][j] = 0;
    }
}

Хм, да, на самом деле ошибка вызвана приоритетом оператора == над =. ОП, вероятно, не понял ошибку компилятора и применил некоторые вредные приведения, чтобы скрыть ее.

Lundin 16.12.2020 10:59

Вы правы, я добавил скобки и вызов выхода, но все равно возвращает segfault.

hawk 16.12.2020 11:04
Ответ принят как подходящий

Ваша проблема заключается в - (вашем?) - непонимании разницы истинного 2D-массива и указателя → указателя → косвенного значения.

Когда вы определяете int **a, это интерпретируется как указатель на другой указатель, который затем ссылается на int. Присвоение указателя, полученного из функции распределения, такой как malloc или shmat, такому двойному указателю, то, что касается семантики C, он ожидает, что это выделение памяти будет содержать дополнительные указатели. Поэтому, если вы выполняете двойное разыменование и там нет действительного указателя, он рухнет на лицо.

Этому недоразумению способствует тот факт, что в C вы можете правильно написать int a[X][Y]; и разыменовать его с помощью a[i][j]. Ключевым моментом для понимания этого является то, что первая «половина», то есть та, что с массивом, определенным таким образом, a[i]… распадается на int* указатель, который указывает на 0-й элемент в i «столбце». Другая половина …[j] затем разыменовывает этот неявно «появляющийся» указатель.

Многомерные массивы в C обманчивы, и я настоятельно не рекомендую их использовать таким образом. Кроме того, вам будет трудно правильно реализовать определенные отступы и выравнивание строк с ними, не прыгая с какой-то действительно раздражающей арифметики.

Гораздо проще просто явно записать вычисления, с дополнительным преимуществом точного контроля заполнения и выравнивания.

Предположим, мы хотим создать 2D-массив int, который должен быть выровнен по размерам long long.

size_t const array_height = ...;
size_t const array_width = ...;
size_t const alignment = sizeof(long long);
size_t const row_size   = array_width * sizeof(int);
size_t const row_stride =
        alignment * ((row_size + alignment-1) / alignment);
size_t const array_size = array_height * row_stride;

int const shm_id = shmget(KEYSM, array_size, IPC_CREAT | 0666);
if ( 0 > shm_id ){
    perror("shmget");
    exit(-1);
}

int *const array = shmat(shm_id, NULL, 0);
if ( (void*)-1 == array ){
    perror("shmat");
    exit(-1);
}

for(size_t j = 0; j < array_height; ++j){
    int *const row = array + j * row_stride;
    for(size_t i = 0; i < array_width;  ++i){
        row[i] = (i % 2) ? -1 : 0;
    }
}

Другие вопросы по теме