Листинг 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 изменил эту ситуацию, введя составные литералы. Литералы — это константы, которые не являются символическими.
Например, 5 — литерал типа int, 81.3— литерал типа double, 1У — литерал типа char, a "elephant" — строковый литерал. В комитете, разрабатывающем стандарт С99, пришли к соглашению, что было бы удобно иметь составные литералы, которые могли бы представлять содержимое массивов и структур.
Для массивов составной литерал выглядит подобно списку инициализации массива, который предварен именем типа, заключенным в круглые скобки. Например, вот обычное объявление массива:
int diva[2] = {10, 20};
А вот составной литерал, который создает неименованный массив, содержащий те же два значения int:
(int [2]){10, 20} // составной литерал
Обратите внимание, что имя типа — это то, что остается после удаления diva из предыдущего объявления, т.е. int [2].
Точно так же, как размер массива можно не указывать во время инициализации именованного массива, его можно опускать в составном литерале, и компилятор подсчитает количество присутствующих элементов:
(int[]){50, 20, 90} // составной литерал с тремя элементами
Поскольку эти составные литералы не имеют имени, нельзя просто создать их в одном операторе и затем использовать их позже. Вместо этого они должны каким-то образом применяться при создании. Один из способов предусматривает использование указателя для отслеживания ячейки памяти. То есть вы можете поступить пример но так:
int * ptl;
Читать дальше