Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Массивы и указатели 403
Квалификатор const в С и C++
В С и C++ квалификатор const используется похожим, но не идентичным образом. Одно из отличий состоит в том, что C++ позволяет применять целочисленное значение const для объявления размера массива, в то время как язык С является более ограничивающим. Второе отличие заключается в том, что язык C++ обладает более строгими правилами присваивания указателей:
const int у; const int * р2 = &у; int * p1;
p1 = р2; // ошибка в C++, возможное предупреждение в С
В C++ не разрешено присваивать указатель const указателю, не являющемуся const. В С это присваивание возможно, но попытка использования p1 для изменения у ведет к неопределенному поведению.
Функции и многомерные массивы
Если вы намерены создавать функции, которые обрабатывают двумерные массивы, то должны достаточно хорошо понимать указатели, чтобы делать подходящие объявления для аргументов функций. В самом теле функции обычно можно обойтись записью в виде массива.
Давайте напищем функцию для взаимодействия с двумерными массивами. Одна из возможностей предусматривает использование цикла for для применения функции обработки одномерных массивов к каждой строке двумерного массива. Другими ело вами, можно предпринять примерно такие действия:
int junk [3] [4] = { {2, 4,5, 8 }, {3,5,6,91, {12,10,8,6) );
int i, j;
int total = 0;
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);
Причина в том, что первый комплект квадратных скобок указывает на объявление именно указателя, тогда как остальные квадратные скобки описывают типы объектов данных, на которые ссылается указатель, как демонстрируется в следующем эквивалентном прототипе:
int sum4d(int (*ar) [12] [20] [30], int rows); // ar - указатель
Здесь ar указывает на массив размером 12x20x30 со значениями типа int.
Массивы переменной длины
Вы могли уже заметить странность в функциях, имеющих дело с двумерными массивами: количество строк можно описать с помощью параметра функции, но количество столбцов встроено в функцию. Например, взгляните на такое определение:
Предположим, что были объявлены следующие массивы:
Функцию sum2d() можно применять с любым из этих массивов:
tot = sum2d(arrayl, 5); // суммирование элементов массива 5x4
tot = sum2d(array2, 100); // суммирование элементов массива 100 х 4
tot = sum2d(arrауЗ, 2); // суммирование элементов массива 2x4
Это объясняется тем, что количество строк передается в параметре rows, представляющем собой переменную. Однако если нужно просуммировать массив размером 6x5, придется использовать новую функцию, в которой параметр COLS должен быть определен как 5. Такое поведение является результатом того факта, что для указания размерности массива необходимо применять константы; таким образом, COLS нельзя заменить переменной. Если вы действительно хотите создать одну функцию, которая будет работать с двумерным массивом любого размера, это можно сделать, но придет ся приложить немало труда. (Вы должны передать массив как одномерный и заставить функцию вычислять, где начинается каждая строка.) Более того, этот прием недоста-
Читать дальшеИнтервал:
Закладка: