Читать интересную книгу Язык Си - руководство для начинающих - M. УЭИТ

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 66 67 68 69 70 71 72 73 74 ... 98

    количество осадков за все годы */

for(year = 0, subtot = 0; year < YRS; year++)

subtot += rain[year][month];

printf(" %4.lf ", subtot/YRS); }

printf(" n");

}

РИС. 12.4. Метеорологическая программа.

ГОД КОЛИЧЕСТВО ОСАДКОВ (дюймы)

1970 50.6

1971 41.9

1972 28.6

1973 32.3

1974 37.8

Среднегодовое количество осадков составляет 38.2 дюйма.

ЕЖЕМЕСЯЧНОЕ КОЛИЧЕСТВО:

Янв. Фев. Mар. Апр. Mай. Июн. Июл. Авг.      Ceнт. OКТ. Нояб. Дек.

7.8   7.2    4.1   3.0    2.1    0.8   1.2    0.3         0.5    1.7    3.6     6.l

В этой программе следует отметить два основных момента: инициализацию и вычисления. Инициализация сложнее, поэтому мы сначала рассмотрим вычисления.

Чтобы найти общее количество осадков за год, мы не изменяем year, а заставляем переменную month пройти все свои значения. Так выполняется внутренний цикл for, находящийся в первой части программы. Затем мы повторяем процесс для следующего значения year. Это внешний цикл первой части программы. Структура вложенного цикла, подобная описанной, подходит для работы с двумерным массивом. Один цикл управляет одним индексом, а второй цикл - другим.

Вторая часть программы имеет такую же структуру, но теперь мы изменяем year во внутреннем цикле, a month во внешнем. Помните, что при однократном прохождении внешнего цикла внутренний цикл выполняется полностью. Таким образом, программа проходит в цикле через все годы, прежде чем изменится месяц, и дает нам общее количество осадков за пять лет для первого месяца, затем общее количество за пять лет для второго месяца и т. д.

Инициализация двумерного массива

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

     Мы могли бы опустить все внутренние скобки и оставить только две самые внешние. До тех пор пока мы будем давать правильное количество входных данных, результат будет тем же самым. Однако, если данных меньше, чем нужно, массив заполняется последовательно (не обращается внимание на разделение по строкам), пока не кончатся все данные. Затем оставшимся элементам будут присвоены нулевые значения. См. рис. 12.5.

РИС. 12.5. Два метода инициализации массива.

     Все, что мы сказали о двумерных массивах, можно распространить и на трехмерные массивы и т. д. Трехмерный массив описывается следующим образом:

int solido[10][20][30];

     Вы можете представить его в виде десяти двумерных массивов (каждый 20х30), поставленных друг на друга, или в виде массива из массивов. То есть это массив из 10 элементов, и каждый его элемент также является массивом. Все эти массивы в свою очередь имеют по 20 элементов, каждый из которых состоит из 30 элементов. Преимущество этого второго подхода состоит в том, что можно довольно просто перейти к массивам большей размерности, если окажется, что вы не можете представить наглядно четырехмерный объект! Мы же останемся верны двум измерениям.

УКАЗАТЕЛИ И МНОГОМЕРНЫЕ МАССИВЫ

     Как создать указатели для многомерных массивов? Чтобы найти ответ на этот вопрос, рассмотрим несколько примеров.

Предположим, что у нас есть описания

int zippo[4][2];  /* массив типа int

                из 4 строк и 2 столбцов */

int *pri;    /* указатель на целый тип */

Тогда на что pri = zippo; указывает? На первый столбец первой строки:

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 является двумерным массивом, но нигде не говорится, из чего он состоит. Из шести строк и двух столбцов? Из двух строк и шести столбцов? Или из чего-нибудь еще? Компилятору недостаточно этой информации. Ее дают следующие операторы:

stuff(junk)

int junk[ ][4];

Они сообщают компилятору, что массив следует разбить на строки по четыре столбца. Массивы символьных строк являются особым случаем, так как у них нулевой символ в каждой строке сообщает компилятору о конце строки. Это разрешает описания, подобные следующему:

1 ... 66 67 68 69 70 71 72 73 74 ... 98
На этом сайте Вы можете читать книги онлайн бесплатно русская версия Язык Си - руководство для начинающих - M. УЭИТ.
Книги, аналогичгные Язык Си - руководство для начинающих - M. УЭИТ

Оставить комментарий