You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用pointer to pointer访问二维数组触发Segmentation fault的原因与解决

为什么二级指针无法正确访问二维数组的非第一行元素?

这是个很典型的C语言类型不匹配问题,咱们一步一步拆解:

先看你的代码和运行结果:

代码:

#include <stdio.h>
int myfunction(double **U) {
    printf("%f\n", U[0][0]); //正确打印U[0][0]
    printf("%f\n", U[0][1]); //正确打印U[0][1]
    printf("%f\n", U[1][0]); //触发"Segmentation fault (core dumped)"
    return 0;
}
int main(void){
    double U[3][4] = {{10, 1, 0, 0}, {2, 6, 0, 0}, {4, 3, 5, 0}};
    double **pU = U;
    myfunction(&pU);
    return 0;
}

运行输出:

10.000000
1.000000
Segmentation fault (core dumped)

为什么只能访问第一行?

问题核心是二维数组和double **(二级指针)的内存模型完全不匹配:

  • 你声明的double U[3][4]是连续存储的二维数组,在内存里它是12个double值紧密排列的:10,1,0,0,2,6,0,0,4,3,5,0。它的实际类型是double[3][4],把它直接赋值给double **pU属于非法类型转换——如果开启了高等级编译警告,编译器会明确提示你这一点。
  • 而double **的本质是「指向指针的指针」,它期望的内存结构是:先有一个指针数组,数组里每个元素都是指向某一行double数组的指针,然后double **指向这个指针数组的首地址。

那前两个printf能正常工作纯属巧合:

  • 你把&pU传给myfunction(这里又多了一层指针,&pU是double ***类型,却被当成double **使用),函数里的U[0]实际取到的是pU的值,也就是原数组的首地址&U[0][0],所以U[0][0]和U[0][1]能正确访问数组前两个元素。
  • 但访问U[1][0]时,U[1]会尝试取U指针往后偏移一个double *大小的地址上的内容(通常是8字节),并把它当成指针——但这个地址里的内容其实是数组的第二个元素1.0,把浮点数1.0转换成指针地址显然是无效的,访问它自然触发段错误。

怎么修改才能正确访问所有元素?

有两种常用解决方案,根据你的需求选择:

方案1:使用指向数组的指针(最直接,适合固定列数的二维数组)

修改函数参数类型,让它接受一个指向4列double数组的指针,完美匹配原二维数组的类型:

#include <stdio.h>
// 参数是指向4列double数组的指针
int myfunction(double (*U)[4]) {
    printf("%f\n", U[0][0]);
    printf("%f\n", U[0][1]);
    printf("%f\n", U[1][0]); // 现在可以正确打印2.000000
    printf("%f\n", U[2][2]); // 也能访问第三行第三列的5.000000
    return 0;
}
int main(void){
    double U[3][4] = {{10, 1, 0, 0}, {2, 6, 0, 0}, {4, 3, 5, 0}};
    // U会隐式转换成指向第一行数组的指针,直接传递即可
    myfunction(U);
    return 0;
}

方案2:用指针数组适配二级指针(适合动态行或列数不固定的场景)

如果你一定要用double **作为函数参数,需要先创建一个指针数组,把二维数组每一行的首地址存进去,再将这个指针数组传给函数:

#include <stdio.h>
int myfunction(double **U) {
    printf("%f\n", U[0][0]);
    printf("%f\n", U[0][1]);
    printf("%f\n", U[1][0]); // 正确打印2.000000
    return 0;
}
int main(void){
    double U[3][4] = {{10, 1, 0, 0}, {2, 6, 0, 0}, {4, 3, 5, 0}};
    // 创建指针数组,存储每一行的首地址
    double *rows[] = {U[0], U[1], U[2]};
    double **pU = rows;
    // 直接传递pU,它是标准的double**类型
    myfunction(pU);
    return 0;
}

总结

永远记住:C语言中二维数组≠二级指针,它们的内存模型完全不同。如果是固定大小的二维数组,优先用指向数组的指针传递;如果需要动态结构,再用二级指针配合指针数组实现。

内容的提问来源于stack exchange,提问作者A. A. Pedersen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:10:28