如何在C中给予一个结构体一个指向矩阵第一个元素的指针,然后使用该指针打印同一矩阵的不同元素?

2cmtqfgy  于 2022-12-11  发布在  其他
关注(0)|答案(3)|浏览(109)

我想在C语言中有一个结构体,它有维度和一个指向矩阵第一个元素的指针,然后用这个指针打印出同一个矩阵的不同元素,但是它不打印任何东西,并且在我试图编译代码时给出一个警告。
代码:

#include <stdio.h>

typedef struct Matrix
{
    int height; // matrix height, first dim
    int width; // matrix width, second dim
    int** firstE; // first matrix elem
} matrix;

int main()
{
    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; //example of two-dimensional array
    matrix matrix_1 = {3,3,m1};
    
    printf("%d\n",**(matrix_1.firste));     //should output 1
    printf("%d\n",**(matrix_1.firste + 1)); //should output 4
    printf("%d\n",*(*(matrix_1.firste)+1)); //should output 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}}; //example of two-dimensional array
    
    printf("%d\n",**(m1)); //should output 1
    printf("%d\n",**(m1 + 1)); //should output 4
    printf("%d\n",*(*(m1)+1)); //should output 2
    
    return 0;
}
wsewodh2

wsewodh21#

这是一个很常见的误解在C.数组的指针在不是一个二维数组。
在你的例子中,你需要把指向int数组的指针赋给一个指向int的指针数组:

int main(void)
{
    int *m1[3] = {(int[]){1,2,3},(int[]){4,5,6},(int[]){7,8,9}}; //example of two-dimensional array
    matrix matrix_1 = {3,3,m1};
    
    printf("%d\n",**(matrix_1.firstE));     //should output 1
    printf("%d\n",**(matrix_1.firstE + 1)); //should output 4
    printf("%d\n",*(*(matrix_1.firstE)+1)); //should output 2
    
    return 0;
}

https://godbolt.org/z/vMM5aaqc9
作为旁注:对大小使用size_t而不是int

e5nszbig

e5nszbig2#

指针和数组有着密切的关系,但它们是完全不同的东西。因此,尽管你可以形成指针数组或数组的数组,但它们也是不同的东西。C 2D数组属于后一种--数组的数组。对应的指针类型是指向数组的指针,而不是指向指针的指针,这正是你的错误信息所告诉你的。
我们可以编写struct Matrix,以便您提供的初始化能够正常工作,但如果printf语句中的访问也能正常工作,则需要struct Matrix中定义的矩阵具有固定宽度。例如:

typedef struct Matrix
{
    int height;       // matrix height, first dim
    int width;        // mostly irrelevant
    int (*firstE)[3]; // first matrix row
} matrix;

// ...

    int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; //example of two-dimensional array
    matrix matrix_1 = {3,3,m1};

但是,对于您所考虑的内容,您可能需要一个指向第一行的第一个元素的 single 指针。这将要求您手动执行索引计算:

typedef struct Matrix
{
    int height; // matrix height, first dim
    int width; // matrix width, second dim
    int *firstE; // first element
} matrix;

int main()
{
    int m1[3][3] = { { 1, 2, 3 },
                     { 4, 5, 6 },
                     { 7, 8, 9 } }; //example of two-dimensional array
    matrix matrix_1 = { 3, 3, m1[0] };
    
    printf("%d\n",*(matrix_1.firstE + matrix_1.width * 0 + 0)); //should output 1
    printf("%d\n",*(matrix_1.firstE + matrix_1.width * 1 + 0)); //should output 4
    printf("%d\n",*(matrix_1.firstE + matrix_1.width * 0 + 1)); //should output 2
    
    return 0;
}

这显示了每种情况下的完整索引计算,当然您可以简化每种情况。但是在实践中,为了清楚起见并降低出错的风险,我希望您编写一个宏或函数来获取元素:

#define MATRIX_ELEMENT(m, r, c) ((m).firstE[(m).width * (r) + (c)])

// ...

    printf("%d\n", MATRIX_ELEMENT(matrix_1, 0, 0)); //should output 1
    printf("%d\n", MATRIX_ELEMENT(matrix_1, 1, 0)); //should output 4
    printf("%d\n", MATRIX_ELEMENT(matrix_1, 0, 1)); //should output 2

您也可以指定:

MATRIX_ELEMENT(matrix_1, 1, 1) = 42;

但是,请注意,该宏对指定矩阵的表达式求值两次,如果该表达式有任何副作用,这将是一个问题。我看不出在类似函数的宏中有什么方法可以避免这种情况--您需要使用实际的函数,它将从本质上解决该问题:

int matrix_element(matrix *m, size_t r, size_t c) {
    return m->firstE[m->width * r + c];
}

// ...

    printf("%d\n", matrix_element(matrix_1, 0, 0)); //should output 1
    printf("%d\n", matrix_element(matrix_1, 1, 0)); //should output 4
    printf("%d\n", matrix_element(matrix_1, 0, 1)); //should output 2

在这种情况下,您需要一个单独的函数来存储元素。
第三,您可以将一个(单个)函数和一个宏结合起来,以避免副作用问题,同时也避免了对多个函数的需要:

int *matrix_element_p(matrix *m, size_t r, size_t c) {
    return m->firstE + m->width * r + c;
}

#define MATRIX_ELEMENT(m, r, c) (*matrix_element_p(m, r, c))

// ...
    MATRIX_ELEMENT(matrix_1, 1, 1) = 42;

    printf("%d\n", MATRIX_ELEMENT(matrix_1, 0, 0)); //should output 1
    printf("%d\n", MATRIX_ELEMENT(matrix_1, 1, 0)); //should output 4
    printf("%d\n", MATRIX_ELEMENT(matrix_1, 0, 1)); //should output 2
    printf("%d\n", MATRIX_ELEMENT(matrix_1, 1, 1)); //should output 42
hujrc8aj

hujrc8aj3#

问题是int[3][3]矩阵的元素是int[3]数组。因此成员的类型必须是指向此数组的指针。meber类型必须是int(*)[3]。不幸的是,内部数组的大小是固定的。解决方法是使用指向不完整数组类型int(*)[]的指针。不完整类型的缺点是它们不能被取消引用。因此,最好通过使用指向VLA的指针来重构原始类型。

#include <stdio.h>

typedef struct Matrix
{
    int height; // matrix height, first dim
    int width; // matrix width, second dim
    int (*arr)[]; // first matrix row
} matrix;

void print_matrix(matrix m) {
  int (*mat)[m.width] = m.arr;
  for (int y = 0; y < m.height; ++y) {
   for (int x = 0; x < m.width; ++x)
    printf("%d ", mat[y][x]);
   puts("");
  }
}

int main() {
  int m1[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; //example of two-dimensional 
  matrix m = { 3, 3, m1 };
  print_matrix(m);
}

它编译时没有警告,工作正常。请参阅godbolt

相关问题