for (1=0; i < 3; i++)
total += sum(junk[i], 4); // junk[i] - одномерный массив
Вспомните, что если junk — это двумерный массив, то junk [1] — одномерный массив, который можно рассматривать как одну строку в двумерном массиве. В таком случае функция sum() вычисляет промежуточную сумму для каждой строки двумерного массива, а в цикле for выполняется сложение этих промежуточных сумм.
Однако при таком подходе теряется возможность отслеживания информации о строках и столбцах. В этом приложении (суммирование всех значений) данная информация не является важной, но предположим, что каждая строка представляет год, а каждый столбец — месяц. Тогда вам может понадобиться функция, которая суммирует значения в отдельных столбцах. В таком случае функция должна располагать информацией о столбцах и строках. Этого можно достичь, объявив формальный параметр правильного вида, чтобы в функцию можно было корректно передавать массивы. В данной ситуации junk является массивом из трех массивов, содержащих по четыре элемента int. Как обсуждалось ранее, это означает, что junk представляет собой указатель на массив из четырех значений int. Параметр функции такого типа можно объявить следующим образом:
void somefunction ( int (* pt) [4] );
В качестве альтернативы, если (и только если) pt является формальным параметром функции, его можно объявить гак:
void somefunction ( int pt[] [4] );
404 глава 10
Обратите внимание, что первая пара квадратных скобок пуста. Пустые квадратные скобки идентифицируют pt в качестве указателя. Затем переменная подобного рода может использоваться тем же способом, что и junk. Именно это сделано в следующем примере, показанном в листинге 10.17. В листинге демонстрируются три эквивалент ных формы синтаксиса прототипов.
Листинг 10.17. Программа array2d.c

Массивы и указатели 405

Вот как выглядит вывод:
строка 0: сумма =20 строка 1: сумма =24 строка 2: сумма =36 столбец 0: сумма =17 столбец 1: сумма = 19 столбец 2: сумма =21 столбец 3: сумма = 23 Сумма всех элементов = 80
Программа из листинга 10.17 передает функциям в качестве аргументов имя junk, которое является указателем на первый элемент, т.е. подмассив, и символическую константу ROWS, представляющую значение 3, т.е. количество строк. Затем каждая функция трактует ar как массив массивов, содержащих по четыре значения int. Количество столбцов встроено в каждую функцию, но количество с трок остается незаданным. Те же самые функции будут работать, скажем, с массивом 12x4, если для количества строк передать число 12. Дело в том, что rows — это количество элементов, но поскольку каждый элемент является массивом, или строкой, rows превращается в количество строк.
Обратите внимание, что ar применяется в той же манере, как junk в функции main(). Это возможно потому, что ar и junk имеют одинаковый тип: указатель на массив из четырех значений int.
Имейте в виду, что следующее объявление не будет работать должным образом:
int sum2(int ar[][], int rows); // ошибочное объявление
Вспомните, что компилятор переводит форму записи с массивами, в форму записи в стиле указателей. Это означает, например, что ar [1] превращается в ar+ 1. Чтобы компилятор мог оценить такое выражение, он должен знать размер объекта, на который указывает ar. Объявление
int sum2(int ar[][4], int rows); // допустимое объявление
говорит о том, что ar указывает на массив из четырех значений int (следовательно, на объект длиной 16 байтов в нашей системе), поэтому ar+1 означает “добавить 16 байтов к адресу”. В версии с пустыми квадратными скобками компилятор не будет знать, что делать дальше.
Можно также включить размер в дру1ую пару квадратных скобок, как показано ниже, но компилятор его проигнорирует:
int sum2(int ar[3] [4], int rows); // допустимое объявление, 3 игнорируется
Это удобно при использовании typedef (как упоминалось в главе 5 и будет описано в главе 14):

406 глава 10
В общем случае, чтобы объявить указатель, соответствующий Л'-мерному массиву, вы должны задать значения во всех парах квадратных скобок, кроме самой левой:
int sum4d(int ar[][12][20][30], int rows);
Причина в том, что первый комплект квадратных скобок указывает на объявление именно указателя, тогда как остальные квадратные скобки описывают типы объектов данных, на которые ссылается указатель, как демонстрируется в следующем эквивалентном прототипе:
Читать дальше