Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Название:Язык программирования C. Лекции и упражнения (6-е изд.) 2015
- Автор:
- Жанр:
- Издательство:Вильямс
- Год:0101
- ISBN:нет данных
- Рейтинг:
- Избранное:Добавить в избранное
-
Отзывы:
-
Ваша оценка:
Стивен Прата - Язык программирования C. Лекции и упражнения (6-е изд.) 2015 краткое содержание
Язык программирования C. Лекции и упражнения (6-е изд.) 2015 - читать онлайн бесплатно полную версию (весь текст целиком)
Интервал:
Закладка:
Массивы и указатели 407
точно гладко сочетается с подпрограммами на языке FORTRAN, которые позволяют указывать в вызове функции оба измерения. Конечно, FORTRAN можно считать древним языком программирования, но за прошедшие десятилетия эксперты в области численных методов разработали на FORTRAN много удобных библиотек вычислений. Язык С позиционируется как наследник FORTRAN, поэтому возможность преобразования библиотек FORTRAN с минимальными усилиями является весьма полезной.
Такая потребность стала главным мотивом для ввода в стандарт С99 понятия массивов переменной длины, которые позволяют использовать переменные для размерности массива. Например, можно поступить так:
int quarters = 4; int regions = 5;
double sales[regions][quarters]; // массив переменной длины
Как упоминалось ранее, с массивами переменной длины связаны некоторые ограничения. Они должны иметь автоматический класс хранения, а это означает их объявление либо в функции без применения модификаторов класса хранения static или extern (глава 12), либо в виде параметров функции. Кроме того, инициализация в объявлении невозможна. Наконец, в стандарте С11 массивы переменной длины являются необязательной возможностью языка в отличие от С99, где они были обязательными.
НА ЗАМЕТКУ! Массивы переменной длины не изменяют размер
Понятие переменный в массиве переменной длины вовсе не означает возможность изменения длины массива после его создания. Будучи созданным, массив переменной длины сохраняет тот же самый размер. В действительности понятие переменный означает, что при указании размерностей при первоначальном создании массива можно использовать переменные.
Поскольку массивы переменной длины представляют собой новое дополнение языка, их поддержка к настоящему времени пока не завершена. Давайте рассмотрим простой пример, в котором показано, как написать функцию для суммирования содержимого любого двумерного массива значений типа int. Для начала вот объявление функции с аргументом в виде двумерного массива переменной длины:
int sum2d(int rows, int cols, int ar[rows][cols]); //ar - массив переменной длины
Обратите внимание на то, что два первых параметра (rows и cols) применяются в качестве размерностей для объявления параметра типа массива ar. Поскольку в объявлении ar используются rows и cols, в списке параметров они должны быть объявлены до появления ar. Поэтому следующий прототип является ошибочным:
int sum2d(int ar[rows][cols], int rows, int cols); // некорректный порядок
В стандартах С99/С11 утверждается, что имена в прототипе можно опускать, но в этом случае размерности должны быть заменены звездочками:
int sum2d(int, int, int ar[*] [*]); //ar - массив переменной длины, имена не указаны Теперь посмотрите, как определять функцию:
int sum2d(int rows, int cols, int ar[rows][cols])
{
int r;
int c;
int tot = 0;
for (r = 0; r < rows; r++) for (c =0; c < cols; C++) tot += ar [r] [c];
return tot;
}
408 Глава 10
Если не считать нового заголовка функции, то единственное отличие этой функции от ее классической версии на С (листинг 10.17) состоит в том, что константа COLS была заменена переменной cols. Такое изменение стало возможным благодаря присутствию в заголовке функции массива переменной длины. Кроме того, наличие переменных, которые представляют количество строк и столбцов, позволяет применять новую функцию sum2d() с любым размером двумерного массива значений int. Данное утверждение иллюстрируется в листинге 10.18. Однако для компиляции такого кода требуется компилятор С, в котором реализована поддержка массивов переменной длины. Здесь также демонстрируется возможность использования этой функции, основанной на массиве переменной длины, либо с традиционными массивами С, либо с массивом переменной длины.
Листинг 10.18. Программа vararr2d.с
Массивы и указатели 409
Ниже приведен вывод, полученный из этой программы:
Традиционный массив 3x5 Сумма всех элементов =80 Традиционный массив 2x6 Сумма всех элементов = 315 Массив переменной длины 3x10 Сумма всех элементов = 270
Следует отметить, что объявление массива переменной длины в списке параметров определения функции в действительности не приводит к созданию массива. Как в старом синтаксисе, имя массива переменной длины на самом деле является указателем. Это значит, что функция с параметром в виде массива переменной длины фактически работает с данными в исходном массиве и потому имеет возможность модифицировать массив, переданный в качестве аргумента. В следующем фрагменте кода показано, когда объявляется указатель, а когда — действительный массив:
Когда функция twoset() вызывается, как выше в коде, ar становится указателем на thing[0], a temp создается как массив 10x6. Поскольку ar и thing являются указателями на thing [0], то ar [0] [0] обращается к тому же самому месту в данных, что
и thing [0] [0].
Массивы переменной длины также делают возможным динамическое выделение памяти. Это означает, что размер массива можно указывать во время выполнения программы. К обычным массивам С применяется статическое выделение памяти, предполагающее, что размер массив определяется на этапе компиляции. Причина в том, что размеры массива, будучи константами, известны компилятору. Динамическое выделе ние памяти обсуждается в главе 12.
const и размеры массивов
Можно ли использовать символическую константу, определенную с помощью const, при объявлении массива?
const int SZ = 80;
double ar[SZ]; // разрешено?
Для стандарта С90 ответ отрицателен (скорее всего). Размер должен быть задан целочисленным константным выражением, которое может быть комбинацией целочисленных констант, таких как 20, выражений sizeof и нескольких других элементов, ни один из которых не имеет отношения к const. Конкретная реализация может расширять диапазон того, что считается целочисленным константным выражением, тогда можно будет применять символические константы const, но такой код перестанет быть переносимым.
Для стандартов С99/С11 ответ положителен, если массив иначе мог бы быть массивом переменной длины. Следовательно, определение должно делаться для массива с автоматическим классом хранения, объявленного внутри блока.
410 глава 10
Составные литералы
Предположим, что вы хотите передать в функцию значение с помощью параметра int; вы можете передать переменную int, но также константу int, такую как 5. До выхода стандарта С99 положение дел с функцией, принимающей аргумент типа массива, было другим; можно было передавать массив, но отсутствовал эквивалент для константы типа массива. Стандарт С99 изменил эту ситуацию, введя составные литералы. Литералы — это константы, которые не являются символическими.
Читать дальшеИнтервал:
Закладка: