Передача двумерного массива в функцию - PullRequest
0 голосов
/ 19 февраля 2019

Мне удалось придумать следующие способы отправки 2-го массива в функцию:

#include <stdio.h>

# define NUM_TWO_DIM_ROWS 3
# define NUM_TWO_DIM_COLS 5

void iterate_two_dim(int[][NUM_TWO_DIM_COLS]);
void iterate_two_dim1(int (*)[NUM_TWO_DIM_COLS]);
void iterate_two_dim2(int *);

int main() {

    int two_dim[][NUM_TWO_DIM_COLS] = { //note the second dimension needs to be specified to resolve expression like two_dim[1]
                        {1,2,3,4,5},    // second dimension tells how many integers to move the two_dim pointer
                        {6,7,8,9,10},
                        {11,12,13,14,15}
                    };

    iterate_two_dim(two_dim);
    iterate_two_dim1(two_dim);
    iterate_two_dim2(*two_dim);


}

void iterate_two_dim(int two_dim[][NUM_TWO_DIM_COLS]) { //function parameter uses array notation
    printf("Two dim array passed using array notation\n" );
    for(int row = 0; row < NUM_TWO_DIM_ROWS; row++) {
        for(int col = 0; col < NUM_TWO_DIM_COLS; col++) {
            printf("two_dim[%d][%d] = %-4d  ", row,col, two_dim[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

void iterate_two_dim1(int (*two_dim)[NUM_TWO_DIM_COLS]) { //function parameter uses pointer notation
    printf("Two dim array passed using pointer notation\n" );
    for(int row = 0; row < NUM_TWO_DIM_ROWS; row++) {
        for(int col = 0; col < NUM_TWO_DIM_COLS; col++) {
            printf("two_dim[%d][%d] = %-4d  ", row,col, two_dim[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

void iterate_two_dim2(int *two_dim) { //function parameter uses pointer notation
    printf("Two dim array passed using pointer notation\n" );
    char buffer[100];
    for(int count = 0; count < NUM_TWO_DIM_ROWS * NUM_TWO_DIM_COLS; count++) {
            if(count > 0 && count % NUM_TWO_DIM_COLS == 0 )
                printf("\n");
            snprintf(buffer, 40, "two_dim[%d] = %2d", count, two_dim[count] );
            printf("%-20s", buffer );
        }
        printf("\n");
}

Любые другие способы, которые можно придумать для этого кода, где объявлен массив two_dimи инициализирован как показано?

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Четвертый способ - передать типизированный указатель на весь массив, как я упоминал в комментарии.Я не тестировал код, но вы поймете идею.Обратите внимание, что *two_dim_ptr - это весь 2D-массив, а sizeof(*two_dim_ptr) - это число всех элементов, умноженное на int (это один из немногих случаев, когда выражение массива не уменьшаетсяна указатель).

**two_dim_ptr - это первый элемент двумерного массива, одномерный массив с NUM_TWO_DIM_COLS элементами.Следовательно, sizeof(*two_dim_ptr)/sizeof(**two_dim_ptr) вычисляет количество строк.

***two_dim_ptr - первый элемент первой строки, здесь int;Следовательно, sizeof(**two_dim_ptr)/sizeof(***two_dim_ptr) вычисляет количество элементов в строке.

Вычисление границ индекса с использованием размера элементов имеет преимущество в обслуживании, которое не нужно изменять коду, если вы измените тип элемента илипостоянные имена.Недостатком является то, что его сложнее читать.

void iterate_two_dim_p(int (*two_dim_ptr)[NUM_TWO_DIM_ROWS][NUM_TWO_DIM_COLS]) { //function parameter is pointer to array of specific size
    printf("True pointer to two dim array passed\n" );
    for(int row = 0; row < sizeof(*two_dim_ptr)/sizeof(**two_dim_ptr); row++) {
        for(int col = 0; col < sizeof(**two_dim_ptr)/sizeof(***two_dim_ptr); col++) {
            printf("two_dim_ptr[%d][%d] = %-4d  ", row,col, two_dim_ptr[row][col] );
        }
        printf("\n");
    }
    printf("\n");
}

Вы бы назвали его с помощью iterate_two_dim_p(&two_dim);, то есть вы берете адрес всего массива. (ПозицияАргументом для оператора адреса является еще один случай, когда массивы не распадаются. Результатом является правильно введенный адрес двумерного массива, а не только адрес его первой строки. Конечно, все адреса численно идентичны, потому что адрес составногоtype - это адрес его первого элемента, правила, которое применяется рекурсивно, так что (size_t)&two_dim == (size_t)two_dim && (size_t)two_dim == (size_t)*two_dim. Разница в типах.)

0 голосов
/ 19 февраля 2019

Пути 1 и 2 - это одинаковые (и правильные).Аргумент массив типа настраивается на аргумент типа указатель на тип , т. Е. int[][NUM_TWO_DIM_COLS] становится int (*two_dim)[NUM_TWO_DIM_COLS] после корректировки.


Способ 3 неверен.Вы получаете доступ к массиву за пределами.Компилятору разрешено учитывать, что указатель указывает на первый элемент массива NUM_TWO_DIM_COLS, и выполнять проверку границ по этой границе.

C11 Приложение J.2 перечисляет это как неопределенное поведение:

Индекс массива выходит за пределы диапазона, даже если объект явно доступен с данным индексом (как в выражении lvalue a[1][7] с учетом объявления int a[4][5]) (6.5.6).

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