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

如何在C语言中为结构体赋予矩阵首元素指针并打印矩阵元素?

C语言结构体存储二维数组指针的类型不匹配问题

问题说明

我尝试定义一个包含矩阵维度和首元素指针的结构体,通过该指针打印矩阵元素,但编译时出现类型不匹配警告,程序也无预期输出。

错误代码

#include <stdio.h>

typedef struct Matrix
{
    int height; // 矩阵行数,第一维度
    int width; // 矩阵列数,第二维度
    int** firstE; // 矩阵首元素指针
} matrix;


int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; // 示例二维数组
    matrix matrix_1 = {3,3,m1};
    
    printf("%d\n",**(matrix_1.firste));     // 预期输出1
    printf("%d\n",**(matrix_1.firste + 1)); // 预期输出4
    printf("%d\n",*(*(matrix_1.firste)+1)); // 预期输出2
    
    return 0;
}

编译警告

.\example.c:14:32: warning: initialization of 'int **' from incompatible pointer type 'int (*)[3]' [-Wincompatible-pointer-types]
   14 |         matrix matrix_1 = {3,3,m1};

我的疑惑

我认为这段代码应该能运行,因为直接操作二维数组的代码可以正常输出预期结果,我原本期望将m1作为int**类型传入结构体:

#include <stdio.h>

int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; // 示例二维数组
    
    printf("%d\n",**(m1)); // 输出1
    printf("%d\n",**(m1 + 1)); // 输出4
    printf("%d\n",*(*(m1)+1)); // 输出2
    
    return 0;
}

问题根源

1. 指针类型不匹配

二维数组名m1的类型是int [3][3],当它被用作表达式时,会隐式转换为指向一维数组的指针,也就是int (*)[3](指向包含3个int元素的数组的指针)。而你结构体里的firstE是int**类型,这是指向int指针的指针,两者完全不是一回事:

  • int (*)[3]指向的是连续存储的一维数组,m1+1会直接跳过3个int的内存长度,指向二维数组的下一行。
  • int**指向的是一个指针数组,每个元素是指向独立int数组的指针,内存布局是先存指针,再存各自的int数组,和二维数组的连续存储完全不同。

把m1(int (*)[3])赋值给int**类型的变量,属于类型不兼容,编译警告就是因此产生。运行时解引用这个不匹配的指针会触发未定义行为,导致无预期输出。

2. 拼写错误

你代码里结构体成员是firstE(大写E),但printf语句里写的是firste(小写e)——C语言区分大小写,这会导致编译器报错找不到该成员,也是程序无法正常运行的原因之一。


解决方案

方案一:修改结构体指针类型为指向数组的指针

直接将结构体里的int** firstE改为指向一维数组的指针,这样可以直接匹配二维数组的类型:

#include <stdio.h>

typedef struct Matrix
{
    int height;
    int width;
    int (*firstE)[3]; // 指向包含3个int的数组的指针
} matrix;

int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    matrix matrix_1 = {3,3,m1};
    
    // 修正拼写错误为firstE
    printf("%d\n", **(matrix_1.firstE));     // 输出1
    printf("%d\n", **(matrix_1.firstE + 1)); // 输出4
    printf("%d\n", *(*(matrix_1.firstE)+1)); // 输出2
    
    return 0;
}

如果需要支持任意宽度的矩阵,可以使用可变长度数组(VLA)实现更灵活的写法:

#include <stdio.h>

// 用void*存储指针,使用时再转换为对应类型
typedef struct Matrix
{
    int height;
    int width;
    void* firstE;
} matrix;

int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    matrix matrix_1 = {3,3,m1};
    
    // 转换为指向对应宽度数组的指针
    int (*p)[matrix_1.width] = matrix_1.firstE;
    printf("%d\n", **p);
    printf("%d\n", **(p+1));
    printf("%d\n", *(*p+1));
    
    return 0;
}

方案二:手动构建指针数组适配int**类型

如果你一定要用int**,可以创建一个临时指针数组,让每个指针指向二维数组的一行:

#include <stdio.h>

typedef struct Matrix
{
    int height;
    int width;
    int** firstE;
} matrix;

int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
    int* rows[3];
    // 让每个指针指向二维数组的一行
    for(int i=0; i<3; i++){
        rows[i] = m1[i];
    }
    
    matrix matrix_1 = {3,3,rows};
    printf("%d\n", **(matrix_1.firstE));
    printf("%d\n", **(matrix_1.firstE + 1));
    printf("%d\n", *(*(matrix_1.firstE)+1));
    
    return 0;
}

这种方式需要额外的指针数组存储行地址,不如方案一高效,仅在必须使用int**的场景下考虑。


内容的提问来源于stack exchange,提问作者Ace_Orca

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 22:40:39