如何在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
相关产品推荐
相关产品推荐

