Попытка выделить 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;
}
}
...
}
Спасибо за ваш ответ. Я сделал несколько ошибок, написав код здесь. Я не хотел копировать весь свой код, поэтому решил переписать его здесь, не проверяя на компиляторе, работает ли он. Так что спасибо, что избавились от моих опечаток.
После исправления опечаток это связано с: stackoverflow.com/questions/36890624/malloc-a-2d-array-in-c Неважно, откуда блок памяти: malloc или shmat
TLDR: int **addressArray; не является «двумерным массивом», что бы вам ни говорили. Смотрите Правильное размещение многомерных массивов для хорошего объяснения.
А использование двух строк, таких как addressArray = shmat(shm_id, NULL, 0); if ( addressArray == -1 ) ..., предотвращает создание ошибок, подобных той, что была в исходном коде. Втиснуть присваивание в оператор if — плохая идея, подверженная ошибкам, и вы уже видели, почему.



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;
}
}
Хм, да, на самом деле ошибка вызвана приоритетом оператора == над =. ОП, вероятно, не понял ошибку компилятора и применил некоторые вредные приведения, чтобы скрыть ее.
Вы правы, я добавил скобки и вызов выхода, но все равно возвращает segfault.
Ваша проблема заключается в - (вашем?) - непонимании разницы истинного 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;
}
}
В коде есть несколько проблем еще до того, как он скомпилируется: отсутствие
)в строкеshmat, необъявленныеiиjи,вместо;во второмfor. Тогда у вас есть 2 логические проблемы:ifв циклах бесполезен, вы все равно перезаписываете значение, аint **addressArrayне является двумерным массивомint (*addressArray)[Y]для этого можно использовать.