在 C 中制作二维数组的最佳方法是什么

What is the best way to make 2 dimensional array in C

我想在 C 中创建一个二维数组。

我知道 1 种方法。

#include <stdlib.h>

void    my_func(int **arr)
{
        printf("test2: %d\n", arr[0][1]);
}

int     main(void)
{
        const int row = 3;
        const int col = 4;

        int **arr = (int **)malloc(sizeof(int *) * 3);
        arr[0] = (int *)malloc(sizeof(int) * 4);
        arr[1] = (int *)malloc(sizeof(int) * 4);
        arr[2] = (int *)malloc(sizeof(int) * 4);

        arr[0][0] = 1;
        arr[0][1] = 2;
        arr[0][2] = 3;
        arr[0][3] = 4;
        arr[1][0] = 3;
        arr[1][1] = 4;
        arr[1][2] = 5;
        arr[1][3] = 6;
        arr[2][0] = 5;
        arr[2][1] = 6;
        arr[2][2] = 7;
        arr[2][3] = 8;

        printf("test1: %d\n", arr[0][1]);

        my_func(arr);

}

在这种情况下,数组可以很好地作为参数传递给函数。 但它不是那么漂亮。 如果数组有很多值(例如 20*20),我需要逐行输入每个值。

所以我搜索了一下,找到了一种方法来制作这样的数组。

#include <stdio.h>

void    my_func(int **arr)
{
        printf("test2: %d", arr[0][1]);
}

int     main(void)
{
        const int row = 3;
        const int col = 4;

        int arr[row][col] = {
                {1,2,3,4},
                {3,4,5,6},
                {5,6,7,8}
        };
        printf("test1: %d", arr[0][1]);

        my_func(arr);
}

简洁明了,不会累死我。 但是当数组传递给函数时出了点问题。 而且编译的时候有如下警告

test_2D_array.c:20:11: warning: incompatible pointer types passing 'int [3][4]' to
      parameter of type 'int **' [-Wincompatible-pointer-types]
                my_func(arr);
                        ^~~
test_2D_array.c:3:20: note: passing argument to parameter 'arr' here
void    my_func(int **arr)
                      ^
1 warning generated.

甚至函数也无法访问数组参数。存在分段错误。

所以我想知道制作数组的最佳方法,它可以作为参数传递给任何函数,并且比我的第一个代码更简单。

感谢您的阅读。

函数可以声明为

void my_func(int arr[][4])
{
    printf("test2: %d", arr[0][1]);
}

请注意,您不必指定第一个维度的大小。

这个

int **arr = (int **)malloc(sizeof(int *) * 3);

不是二维数组的声明或分配

这里创建了一个元素类型为int *的一维数组。然后一维数组的每个元素依次指向一个分配的元素类型为int.

的一维数组

二维数组的声明

    const int row = 3;
    const int col = 4;

    int arr[row][col] = {
            {1,2,3,4},
            {3,4,5,6},
            {5,6,7,8}
    };

不正确。可变长度数组(并且您声明了可变长度数组)可能未在声明中初始化。

你可以改写

    enum { row = 3, col = 4 };

    int arr[row][col] = {
            {1,2,3,4},
            {3,4,5,6},
            {5,6,7,8}
    };

当这样的数组被传递给一个函数时,它被隐式转换为指向其类型 int ( * )[col].

的第一个元素的指针

您可以通过以下方式将其传递给具有可变长度数组类型参数的函数

void    my_func( size_t row, size_t col, int arr[row][col] )
{
        printf("test2: %d", arr[0][1]);
}

或者如果将枚举的定义放在函数声明之前

    enum { row = 3, col = 4 };

那么函数也可以这样声明

void    my_func( int arr[][col], size_t row )
{
        printf("test2: %d", arr[0][1]);
}

这是一个展示三种不同方法的演示程序。第一个数组是用数组大小​​的编译时常量定义的。创建可变长度数组时的第二个。第三个是动态分配指向一维数组指针的一维数组。

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

enum { row = 3, col = 4 };

void output1( int a[][col], size_t row )
{
    for ( size_t i = 0; i < row; i++ )
    {
        for ( size_t j = 0; j < col; j++ )
        {
            printf( "%d ", a[i][j] );
        }
        putchar( '\n' );
    }
}

void output2( size_t row, size_t col, int a[row][col] )
{
    for ( size_t i = 0; i < row; i++ )
    {
        for ( size_t j = 0; j < col; j++ )
        {
            printf( "%d ", a[i][j] );
        }
        putchar( '\n' );
    }
}

void output3( int **a, size_t row, size_t col )
{
    for ( size_t i = 0; i < row; i++ )
    {
        for ( size_t j = 0; j < col; j++ )
        {
            printf( "%d ", a[i][j] );
        }
        putchar( '\n' );
    }
}


int     main(void)
{
        int arr1[row][col] = 
        {
                {1,2,3,4},
                {3,4,5,6},
                {5,6,7,8}
        };

        output1( arr1, row );
        putchar( '\n' );

        const size_t row = 3, col = 4;

        int arr2[row][col];

        memcpy( arr2, arr1, row * col * sizeof( int ) );

        output2( row, col, arr2 );
        putchar( '\n' );

        int **arr3 = malloc( row * sizeof( int * ) );

        for ( size_t i = 0; i < row; i++ )
        {
            arr3[i] = malloc( col * sizeof( int ) );
            memcpy( arr3[i], arr1[i], col * sizeof( int ) );
        }

        output3( arr3, row, col );
        putchar( '\n' );

        for ( size_t i = 0; i < row; i++ )
        {
            free( arr3[i] );
        }

        free( arr3 );
} 

程序输出为

1 2 3 4 
3 4 5 6 
5 6 7 8 

1 2 3 4 
3 4 5 6 
5 6 7 8 

1 2 3 4 
3 4 5 6 
5 6 7 8 

注意函数 output2 可以与数组 arr1 一起使用,就像它与数组 arr2.

一起使用一样

它需要一个看起来很有趣的类型转换,但我是这样做的:

#include <stdio.h>

void my_func(int **arr, int cols)
{
    int (*matrix)[cols] = arr;
    printf("test2: %d\n", matrix[0][1]);
}

int main(void)
{
        const int row = 3;
        const int col = 4;

        int arr[3][4] = {
                {1,2,3,4},
                {3,4,5,6},
                {5,6,7,8}
        };
        printf("test1: %d\n", arr[0][1]);

        my_func(arr, col);
}

IDEOne Link

假设没有动态分配

1   #include <stdio.h>
  1
  2 void func(int *arr, int row, int col) {
  3     int i, j;
  4
  5     for (i = 0; i < row * col; i++) {
  6         if (i && (i % col == 0))
  7             printf("\n");
  8         printf("%d ", arr[i]);
  9     }
 10
 11     printf("\n");
 12 }
 13
 14 int main(int argc, char *argv[]) {
 15     // can be this
 16     int arr1[] = {
 17         1,2,3,  // row 0
 18         4,5,6   // row 1
 19     };
 20
 21     // or this way
 22     int arr2[2][3] = {
 23         {0,1,2},  // row 0
 24         {4,5,6}   // row 1
 25     };
 26
 27     func(arr1, 2, 3);
 28     func((int*)arr2, 2, 3);
 29     return 0;
 30 }
~

首先,您不能初始化可变大小的二维数组,如 'Vlad from Moscow' 在他的回答中提到的那样。 相反,您只需指定第二个维度的大小,将第一个维度留空。 其次,您的 my_func(int **arr) 期望 pointer to pointer to int 而您只是传递数组的地址,这就是编译器抛出不兼容错误的原因。

您的固定代码将如下所示:

#include <stdio.h>

void    my_func(int **arr)
{
        printf("test2: %d", arr[0][1]);
}

int     main(void)
{
        int arr[][4] = {1,2,3,4,
                        3,4,5,6,
                        5,6,7,8};
        int *p = (int *)arr;
        int **p1 = &p;
        printf("test1: %d", arr[0][1]);

        my_func(p1);
}

现在 const int row = 3const int column = 4 没有用了,所以您可以删除它们。