Каков наилучший способ сделать 2-мерный массив в C - PullRequest
2 голосов
/ 27 апреля 2020

Я хочу сделать двумерный массив в 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.

, и даже функция не может получить доступ к аргументу массива. Ошибка сегментации.

Поэтому я хочу узнать, как лучше сделать массив, который может быть передан любой функции в качестве аргумента, и менее утомителен, чем мой первый код.

Спасибо за чтение .

Ответы [ 5 ]

2 голосов
/ 27 апреля 2020

Этот

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.

1 голос
/ 27 апреля 2020

Функция может быть объявлена ​​как

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

Обратите внимание, что вам не нужно указывать размер первого измерения.

0 голосов
/ 28 апреля 2020

Во-первых, вы не можете инициализировать двумерный массив с переменным размером, как упомянул в своем ответе «Влад из Москвы». Вместо этого вам просто нужно указать размер вашего второго измерения, оставив первое измерение пустым. Во-вторых, ваш 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 = 3 & const int column = 4, поэтому вы можете удалить их.

0 голосов
/ 28 апреля 2020

Предположим, что нет динамического распределения c.

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 }
~
0 голосов
/ 27 апреля 2020

Требуется забавно выглядящий тип, но я сделал это следующим образом:

#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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...