C语言中通过指针赋值访问二维数组失败,打印触发段错误
int**会触发段错误? 我来帮你把这个问题的来龙去脉讲清楚,顺便给你几种解决办法~
首先先确认你的问题场景:你在函数里定义了一维数组singleArray和二维数组dualArray,用int*接收一维数组后遍历打印完全正常,但把二维数组赋值给int**后遍历就触发了段错误。
核心原因:类型不匹配!
先看一维数组的正常逻辑
int singleArray[]={1,2,3}在内存里是连续存储的3个int值:1 → 2 → 3。当你写int* sa = singleArray时,数组名singleArray会隐式转换为指向第一个元素的指针(类型是int*),和sa的类型完全匹配。遍历sa[i]本质是*(sa + i),也就是从首地址偏移i个int的位置取值,完全合法。
再看二维数组的错误根源
int dualArray[2][2]的内存布局是连续的4个int:1 → 2 → 3 → 4,它的类型是int [2][2]。当你试图把它赋值给int** da时,这里就出现了类型不兼容的问题:
int**是指向int指针的指针,它期望指向的内存里存储的是一个个int*类型的地址;- 但二维数组名
dualArray转换后是指向一维数组的指针(类型是int (*)[2],即指向长度为2的int数组的指针),它指向的内存里直接存储的是int值(也就是1、2这些数据)。
当你用da[i][j]遍历的时候,编译器会解析成*( *(da + i) + j ):先取da+i指向的内容(期望是一个int*地址),然后再偏移j取int值。但实际上da指向的是二维数组的首地址,这里的内容是1和2,把1当作一个内存地址去解引用,自然会访问非法内存,触发段错误。
解决办法
方法1:修改函数参数,匹配二维数组的真实类型
这是最直接、最推荐的方式,让函数参数的类型和二维数组一致。如果列数固定,可以这么写:
void printOutput(int array[][2], int row) { int i = 0, j = 0; for (i = 0; i < row; i++) { for (j = 0; j < 2; j++) { printf("%d ", array[i][j]); } printf("\n"); } } // 调用时直接传dualArray printOutput(dualArray, 2);
如果想支持可变列数(C99及以后标准支持可变长度数组),可以改成:
void printOutput(int row, int col, int array[row][col]) { int i = 0, j = 0; for (i = 0; i < row; i++) { for (j = 0; j < col; j++) { printf("%d ", array[i][j]); } printf("\n"); } } // 调用 printOutput(2, 2, dualArray);
方法2:手动构建指针数组适配int**类型
如果你一定要用int**作为函数参数,可以先创建一个指针数组,让每个元素指向二维数组的每一行,再把这个指针数组传给函数:
// 定义指针数组,每个元素指向dualArray的一行 int* da_ptr[2]; da_ptr[0] = dualArray[0]; da_ptr[1] = dualArray[1]; // 现在da的类型是int**,可以正常传入printOutput int** da = da_ptr; printOutput(da, 2, 2);
方法3:把二维数组当作一维数组访问(原理向)
因为二维数组在内存里是连续存储的,你也可以直接用int*来遍历,本质是跳过二维的语法糖直接操作连续内存:
int* da = (int*)dualArray; printf("二维数组内容:\n"); for (int i = 0; i < 2*2; i++) { printf("%d ", da[i]); if ((i+1) % 2 == 0) printf("\n"); }
总结
记住一个关键点:C语言里的二维数组≠int**指针!一维数组可以隐式转换为int*,但二维数组转换后是指向一维数组的指针,两者的内存语义完全不同,强行赋值必然会导致内存访问错误。
内容的提问来源于stack exchange,提问作者shiva

