【问题标题】:Pointer to existing 2d array of unknown size?指向现有未知大小的二维数组的指针?
【发布时间】:2016-03-16 11:46:03
【问题描述】:

我有以下几点:

struct matrix {
    int h;
    int w;
    int** data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

这给出了错误“从不兼容的指针类型初始化”。我应该使用什么指针类型?

【问题讨论】:

  • 首先检查m1m2的类型.....
  • 二维数组不是指向指针的指针...
  • @SouravGhosh 我不认为你可以从 typeof() 中得到一个字符串...?
  • @Dimpl 请看 LP 的评论。有时只是在实施之前尝试思考。这会有所帮助。嗯。
  • 二维数组不是指向指针的指针...除了它是。见stackoverflow.com/questions/26454022/…。我问了这个问题,因为该答案没有解决二维数组的所有值都在一个语句中分配的情况。

标签: c arrays pointers


【解决方案1】:

您可能对 C99 的可变长度数组感兴趣。该解决方案没有直接回答您关于如何使用正确键入的data 初始化结构的问题(不能);但是您可以使用简单的指针来存储数组的地址,然后在使用struct matrix 时转换为可变长度数组指针。

用户端只会调用像printFroMat() 这样的函数,它接收struct matrix 类型的单个参数;这些函数内部中的代码(可以说是库实现)将执行一些难看的转换,如所示。 typedef 使强制转换可能更容易理解,因为它演示了声明中的变量名称将去哪里。

请注意,有趣的sizeof(m2)/sizeof(*m2) 等并不是绝对必要的,你可以直接说3。但是sizeof 表达式会自动与实际矩阵大小保持同步,这很快就会成为真正的资产。

您可以将“数组”(实际上:仍然只是地址,但属于已知数组类型)连同它们的维度作为参数传递给函数,并以正常方式对它们进行索引(在printMatrix 中)。示例:

#include<stdio.h>
#include<string.h>


struct matrix {
    int h;
    int w;
    int *data; // first element of matrix
};

int m2[4][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9},
    {10, 11, 12}
};

void printMatrix(int dim1, int dim2, int mat[][dim2] )
{
    printf("Address of matrix: %p\n", (void *)mat);

    for(int i1=0; i1<dim1; i1++)
    {
        for(int i2=0; i2<dim2; i2++)
        {
            printf("%d ", mat[i1][i2]);
        }
        putchar('\n');
    }
}

void printFromMat(struct matrix mat)
{
    printMatrix(mat.h, mat.w, (int (*)[mat.w])mat.data);

    // or:
    typedef int (*mT)[mat.w];
    printMatrix(mat.h, mat.w, (mT)mat.data);
}

int main() 
{

    printMatrix(   sizeof(m2) /sizeof(*m2),   // number of highest-order elements
                   sizeof(*m2)/sizeof(**m2),  // number of second-order elements per highest-order
                   m2  );                     // address of the first sub-array

    struct matrix mat = { sizeof(m2) /sizeof(*m2), sizeof(*m2)/sizeof(**m2), *m2 };

    printFromMat(mat);


    return 0;
}

示例会话:

$ gcc -std=c99 -Wall -o 2d-matrix 2d-matrix.c && ./2d-matrix
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12
Address of matrix: 0x100402020
1 2 3
4 5 6
7 8 9
10 11 12

【讨论】:

  • 感谢您的回答!我将矩阵(或矩阵*,准确地说)作为参数传递。有没有办法进行内联转换?我尝试了 (int(*)[mat.w])mat.data[r][c],但这不起作用。
  • 试试((int(*)[mat.w])(mat.data))[r][c][]. 比演员有 higher precedence。您只想投射mat.data,而不是mat.data[r][c]。也就是说,((int(*)[mat.w])mat.data)[r][c] 应该这样做。
【解决方案2】:

二维数组不是指向指针的指针。

如何使用 void *.

#include <stdio.h>

struct matrix {
    int h;
    int w;
    void *data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

int main(void){
    int i, j;

    int (*matp)[matrix2.w] = matrix2.data;//Back from the void* to pointer to array

    for (i=0; i<matrix2.h; i++){
        for(j=0; j<matrix2.w; j++)
            printf("%d ", matp[i][j]);
        puts("");
    }
    printf("\n");

    return 0;
}

【讨论】:

  • 我无法理解int (*matp)[matrix2.w] = matrix2.data; 发生了什么,但它确实有效!我以前从未见过用括号括起来的变量名。
  • 我认为这是最不差的版本。缺点是您必须在数组指针和 void 指针之间进行强制转换,并且 void 指针不是类型安全的。我开始写一个答案,它通过宏创建了一个带有 VLA 的结构,但它的可读性要差得多。另一种选择是一些指针数组解决方案,但这也不漂亮。
  • @Dimpl 它创建一个数组指针,指向大小为w 的一维数组。然后对这种指针类型使用指针算法来访问二维数组中的每个数组。 matp[i][j] 的意思是“给我数组i,然后在那个数组中给我项目j”。
  • @Lundin 谢谢。我倾向于使用 int* 进行声明,使用 *matp 进行取消引用,所以有点搞混了。
  • 也许宏可以用于矩阵指针声明,以使代码更通用。 #define declare_matrix_ptr(name, matrix) int(*name)[matrix.w] = matrix.data 不漂亮,但错别字的机会较少。
【解决方案3】:

正如您所声明的,矩阵不是指向指针的指针。使用一个简单的指针来指向它的元素。

#include <stdio.h>

struct matrix {
    int h;
    int w;
    int* data;
};

int m1[2][2] = {
    {1, 2},
    {3, 4}
};

int m2[3][3] = {
    {1, 2, 3},
    {4, 5, 6},
    {7, 8, 9}
};

struct matrix matrix1 = {2, 2, &m1[0][0]};
struct matrix matrix2 = {3, 3, &m2[0][0]};

int main(int argc, char **argv)
{
   int i, j;

   for (i=0; i<matrix2.h; i++)
      for(j=0; j<matrix2.w; j++)
         printf("%d ", matrix2.data[(i*matrix2.h)+j]);

    printf("\n");
}

编辑

要回答评论,您可以使用如下复合文字。这样你就可以通过[i][j]访问它了

#include <stdio.h>

struct matrix {
    int h;
    int w;
    int** data;
};

int *m2[3] = {
    (int[]){1, 2, 3},
    (int[]){4, 5, 6},
    (int[]){7, 8, 9}
};

struct matrix matrix2 = {3, 3, m2};

int main(int argc, char **argv)
{
    int i, j;

    for (i=0; i<matrix2.h; i++)
        for(j=0; j<matrix2.w; j++)
            printf("%d ", matrix2.data[i][j]);

    printf("\n");
}

【讨论】:

  • 这是令人满意的,虽然不是最优的,因为我更喜欢使用 [i][j] 而不是 [(i*3)+j]。
  • 谢谢,这很好。在我的应用程序中,我只访问 1 个库函数中的矩阵,所以 Peter A. Schneider 的回答效果更好,但如果可以的话,我也会接受这个解决方案。
【解决方案4】:

你不能像这样初始化结构

struct matrix matrix1 = {2, 2, m1};
struct matrix matrix2 = {3, 3, m2};

因为没有从int ( * )[2]int ( * )[3] 类型到int ** 类型的转换

我建议为数组的副本动态分配内存。

该方法可以如下所示,如演示程序中所示

#include <stdlib.h>
#include <stdio.h>

struct matrix 
{
    size_t h;
    size_t w;
    int **data;
};

int m1[2][2] = 
{
    { 1, 2 },
    { 3, 4 }
};

int m2[3][3] = 
{
    { 1, 2, 3 },
    { 4, 5, 6 },
    { 7, 8, 9 }
};

struct matrix init( size_t h, size_t w, int a[h][w] )
{
    struct matrix matrix = { 0 };

    matrix.data = malloc( h * sizeof( int * ) );

    if ( matrix.data )
    {
        matrix.h = h;
        matrix.w = w;
        for ( size_t i = 0; i < h; i++ ) 
        {            
            matrix.data[i] = malloc( w * sizeof( int ) );
            if ( matrix.data[i] )
            {                
                for ( size_t j = 0; j < w; j++ ) matrix.data[i][j] = a[i][j];
            }
        }
    }        

    return matrix;
}

int main( void ) 
{
    struct matrix matrix1 = init( 2, 2, m1 );
    struct matrix matrix2 = init( 3, 3, m2 );

    for ( size_t i = 0; i < matrix1.h; i++ )
    {
        for ( size_t j = 0; j < matrix1.w; j++ ) printf( "%d ", matrix1.data[i][j] );
        printf( "\n" );
    }
    printf( "\n" );

    for ( size_t i = 0; i < matrix2.h; i++ )
    {
        for ( size_t j = 0; j < matrix2.w; j++ ) printf( "%d ", matrix2.data[i][j] );
        printf( "\n" );
    }
    printf( "\n" );

    // free allocated arrays of matrix1 and matrix2
}    

程序输出是

1 2 
3 4 

1 2 3 
4 5 6 
7 8 9 

您还需要编写一个函数来释放为结构分配的内存。

编译器必须支持变长数组。

【讨论】:

  • 这有点涵盖它,但我正在寻找一个浅拷贝。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-26
相关资源
最近更新 更多