带有二维数组的分段错误 shmat()

Segmentation fault shmat() with 2d array

正在尝试在共享内存中分配二维数组。分配期间执行 returns 分段错误(我认为)。我应该用另一种方式做作业吗?这是我的代码:

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

段错误是运行时错误,但您的代码甚至不应该编译,请查看以下语句(缺少括号):

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

如果任务失败怎么办? perror 是否终止进程?没有。但是您仍然可以访问下面的数组。很可能是段错误的来源。

正如 mch 指出的那样:

// 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;
    }
}

你的问题在于 - (你的?) - 对真正的二维数组和指针→指针→值间接的区别的误解。

当您定义一个 int **a 时,它被解释为指向另一个指针的指针,然后该指针引用一个 int。将从 mallocshmat 等分配函数获得的指针分配给这样的双指针,然后就 C 的语义而言,它期望此内存分配包含更多指针。因此,如果您执行双重取消引用,并且那里没有有效的指针,它就会掉下来。

这种误解因以下事实而进一步加深,即在 C 中您可以有效地编写 int a[X][Y]; 并使用 a[i][j] 取消引用它。理解这一点的关键见解是,第一个“一半”,即具有这样定义的数组的 a[i]… 衰减为 int* 指针,指向 [=19 中的第 0 个元素=]“列”。另一半 …[j] 然后取消引用这个隐式“出现”的指针。

C 中的多维数组具有欺骗性,我强烈反对这样使用它们。此外,您将很难正确地使用它们实现特定的填充和行对齐,而不跳过一些非常烦人的算法。

到目前为止,只需明确地写下计算结果就更容易了,而且还可以精确控制填充和对齐。

假设我们要创建一个 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;
    }
}