Эта тема создана мною благодаря вопросу на Stackoverflow
Passing a pointer to a typedef'ed array.
То есть когда тип массив определен с помощью
typedef, то у начинающих программистов вызывает трудности, как правильно объявить соответствующий параметр функции, принимающий массив.
В исходном вопросе тип массива определяется следующим образом
typedef unsigned char multi_array[4][4];
И автор вопроса хочет передать этот массив в функцию, которая выводит на консоль элементы массива.
Он объявляет функцию следующим образом
void print_array(multi_array* arr);
Фактически, параметр функции имеет тип
unsigned char ( * )[4][4].
Так можно передавать массив в функцию, хотя это и не общепринятый способ. Преимущество передачи массива в функцию через указатель на весь массив состоит в том, что в функции можно вычислить размерности элементов массива, не передавая их явно как дополнительные аргументы функции.
Ниже показана демонстрационная программа.
#include <stdio.h>
enum { N = 4 };
typedef unsigned char multi_array[N][N];
void print_array( multi_array *arr )
{
for ( size_t i = 0; i < sizeof( *arr ) / sizeof( **arr ); i++ )
{
for ( size_t j = 0; j < sizeof( **arr ) / sizeof( ***arr ); j++ )
{
printf("%2d ", ( *arr )[ i ][ j ]);
}
printf("\n");
}
}
int main( void )
{
multi_array arr;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
arr[ i ][ j ] = N * i + j;
}
}
print_array( &arr );
}
Вывод программы на консоль:
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
Как видно из программы разыменовывая (и дважды разыменовывая) указатель, объявленный в качестве параметра, мы получаем lvalue на исходный массив. Это позволяет вычислить размерности массива с помощью выражении
sizeof( *arr ) / sizeof( **arr ) и
sizeof( **arr ) / sizeof( ***arr ).
Для обращения к конкретному элементу типа
unsigned char массива нужно использовать выражение
( *arr )[ i ][ j ], так как операция разыменования имеет более низкий приоритет, чем операция индексации. А нам сначала нужно получить сам массив, на который ссылается указатель, и лишь затем применять операцию индексирования.
Однако более общепринятый способ передачи массивов в функции состоит в том, чтобы соответствующий параметр функции объявить как указатель на первый элемент массива. Для заданного в исходном вопросе массива соответствующий параметр будет выглядеть как
char ( *arr )[4].
Этот же параметр можно также записать как исходное объявление массива, то есть в виде
multi_array arr. Компилятор сам приведет это объявление массива к объявлению указателя на его первый элемент.
В этом случае требуется также передавать размерность "внешнего" под-массива, так как внутри функции вычислить его невозможно, так как мы имеем дело с указателем на первый элемент массива. То есть выражение
sizeof( arr ) вернет размерность указателя, а не размер памяти, занимаемый всем массивом.
Ниже приведена соответствующая демонстрационная программа.
#include <stdio.h>
enum { N = 4 };
typedef unsigned char multi_array[N][N];
void print_array( multi_array arr, size_t n )
{
for ( size_t i = 0; i < n; i++ )
{
for ( size_t j = 0; j < sizeof( *arr ) / sizeof( **arr ); j++ )
{
printf("%2d ", arr[ i ][ j ]);
}
printf("\n");
}
}
int main( void )
{
multi_array arr;
for ( size_t i = 0; i < N; i++ )
{
for ( size_t j = 0; j < N; j++ )
{
arr[ i ][ j ] = N * i + j;
}
}
print_array( arr, N );
}
Обратите внимание, что согласно стандарту языка Cфункция
main без параметров должна быть объявлена как
int main( void )
Так же не следует использовать магические числа вроде числа 4, используемого в программе исходного вопроса. Используйте именованные константы.