Язык Си - руководство для начинающих
Шрифт:
zippo == &zippo[0][0]
А на что указывает pri + 1? На zippo[0][l], т.е. на 1-ю строку 2-го столбца? Или на zippo[l][0], элемент, находящийся во второй строке первого столбца? Чтобы ответить на поставленный вопрос, нужно знать, как располагается в памяти двумерный массив. Он размещается, подобно одномерным массивам, занимая последовательные ячейки памяти. Порядок элементов определяется тем, что самый правый индекс массива изменяется первым, т. е. элементы массива располагаются
zippo[0][0] zippo[0][1] zippo[1][0] zippo[1][1] zippo[2][0]
...
Сначала запоминается первая строка, за ней вторая, затем третья и т. д. Таким образом в нашем примере:
pri == &zippo[0][0] /* 1-я строка, 1 столбец */
pri + 1 == &zippo[0][1] /* 1-я строка, 2 столбец */
pri + 2 == &zippo[1][0] /* 2-я строка, 1 столбец */
pri + 3 == &zippo[1][1] /* 2-я строка, 2 столбец */
Получилось? Хорошо, а на что указывает pri + 5? Правильно, на zippo[2][l].
Мы описали двумерный массив как массив массивов. Если zippo является именем нашего двумерного массива, то каковы имена четырех строк, каждая из которых является массивом из двух элементов? Имя первой строки zippo[0], имя четвертой строки zippo[3]; вы можете заполнить пропущенные имена. Однако имя массива является также указателем на этот массив в том смысле, что оно ссылается на первый его элемент. Значит,
zippo[0] == &zippo[0][0]
zippo[1] == &zjppo[1][0]
zippo[2] == &zippo[2][0]
zippo[3] == &zippo[3][0]
Это свойство является более, чем новшеством. Оно позволяет использовать функцию, предназначенную для одномерного массива, для работы с двумерным массивом! Вот доказательство (хотя мы надеемся, что теперь вы бы поверили нам и так) использования двумерного массива в нашей программе нахождения среднего значения:
/* одномерная функция, двумерный массив */
main
{
static int junk[3][4] = {
{2, 4, 6, 8},
{100, 200, 300, 400},
{10, 40, 60, 90} };
int row;
for(row = 0; row < 3; row ++)
printf(" Среднее строки %d равно %d.\n", row, mean(junk[row],4));
/* junk [row] - одномерный массив ИЗ четырех элементов */
}
/*
int mean(array,n)
int array[ ], n;
{
int index;
long sum;
if(n > 0) {
for(index = 0, sum = 0; index < n; index++)
sum += (long)array[index];
return((int)(sum/n)); }
else {
printf(" Нет массива. \n");
return(0); }
}
Результат работы программы:
Cреднее строки 0 равно 5.
Cреднее строки 1 равно 250.
Cреднее строки 2 равно 50.
Функции и многомерные массивы
Предположим, что вы хотите иметь функцию, работающую с двумерным массивом, причем со всем целиком, а не с частями. Как вы запишите определения функции и ее описания? Подойдем к этому более конкретно и скажем, что нам нужна функция, управляющая массивом junk[ ][ ] в нашем последнем примере. Пусть функция main выглядит так:
/* junk в main */
main
{
static int junk[3][4] = {
{2, 4, 5, 8},
{100, 200, 300, 400}
{10, 40, 60, 90} };
stuff(junk);
}
Функция stuff использует в качестве аргумента junk, являющийся указателем на весь массив. Как написать заголовок функции, не зная, что делает stuff?
Попробуем написать:
stuff(junk) int junk[ ];
или
stuff(junk) int junk[ ][ ];
Нет и нет. Первые два оператора еще будут работать некоторым образом, но они рассматривают junk как одномерный массив, состоящий из 12 элементов. Информация о расчленении массива на строки отсутствует.
Вторая попытка ошибочна, потому что хотя оператор и указывает что junk является двумерным массивом, но нигде не говорится, из чего он состоит. Из шести строк и двух столбцов? Из двух строк и шести столбцов? Или из чего-нибудь еще? Компилятору недостаточно этой информации. Ее дают следующие операторы: