Чтение онлайн

ЖАНРЫ

Язык программирования Си. Издание 3-е, исправленное

Ритчи Деннис М.

Шрифт:

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

Как особый выделен случай инициализации массива символов. Последний можно инициализировать с помощью строкового литерала; символы инициализируют элементы массива в том порядке, как они заданы в строковом литерале. Точно так же, с помощью литерала из расширенного набора символов (A2.6), можно инициализировать массив типа wchar_t. Если размер массива не известен, то он определяется числом

символов в строке, включая и завершающий NULL-символ; если размер массива известен, то число символов в строке, не считая завершающего NULL-символа, не должно превышать его размера.

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

В первой версии языка не позволялось инициализировать объединения. Правило "первого элемента" не отличается изяществом, однако не требует нового синтаксиса. Стандарт ANSI проясняет еще и семантику не инициализируемых явно объединений.

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

Например

int x[] = { 1, 3, 5 };

объявляет и инициализирует x как одномерный массив с тремя элементами, поскольку размер не был указан, а список состоит из трех инициализаторов.

float y[4][3] = {

{ 1, 3, 5 },

{ 2, 4, 6 },

{ 3, 5, 7 },

};

представляет собой инициализацию с полным набором фигурных скобок: 1, 3 и 5 инициализируют первую строку в массиве у[0], т. е. y[0][0], у[0][1] и y[0][2]. Аналогично инициализируются следующие две строки: y[1] и y[2]. Инициализаторов не хватило на весь массив, поэтому элементы строки y[3] будут нулевыми. В точности тот же результат был бы достигнут с помощью следующего объявления:

float у[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 };

Инициализатор для y начинается с левой фигурной скобки, но для y[0] скобки нет, поэтому из списка будут взяты три элемента. Аналогично по три элемента будут взяты для y[1], а затем и для y[2]. В

float у[4][3] = {

{ 1 }, { 2 }, { 3 }, { 4 }

};

инициализируется первый столбец матрицы y, все же другие элементы остаются нулевыми.

Наконец,

char msg[] = "Синтаксическая ошибка в строке %s\n";

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

A8.8. Имена типов

В ряде случаев возникает потребность в применении имени типа данных (например при явном приведении к типу, в указании типов параметров внутри объявлений функций, в аргументе оператора sizeof). Эта потребность реализуется с помощью имени типа, определение которого синтаксически почти совпадает с объявлением объекта того же типа. Оно отличается от объявления лишь тем, что не содержит имени объекта.

имя-типа:

список-спецификаторов-квалификаторов
абстрактный-объявительнеоб

абстрактный-объявитель:

указатель

указательнеоб собственно-абстрактный-объявитель

собственно-абстрактный-объявитель:

( абстрактный-объявитель )

собственно-абстрактный-объявительнеоб [ константное-выражениенеоб ]

собственно-абстрактный-объявительнеоб ( список-типов-параметровнеоб )

Можно указать одно-единственное место в абстрактном объявителе, где мог бы оказаться идентификатор, если бы данная конструкция была полноценным объявителем. Именованный тип совпадает с типом этого "невидимого идентификатора". Например

intint *int *[3]int (*)[]int *int (*[])(void)

соответственно обозначают типы int, "указатель на int", "массив из трех указателей на int", "указатель на массив из неизвестного количества int", "функция неизвестного количества параметров, возвращающая указатель на int", "массив неизвестного количества указателей на функции без параметров, каждая из которых возвращает int".

А8.9. Объявление typedef

Объявления, в которых спецификатор класса памяти есть typedef, не объявляют объектов - они определяют идентификаторы, представляющие собой имена типов. Эти идентификаторы называются typedef– именами.

typedef-имя:

идентификатор

Объявление typedef приписывает тип каждому имени своего объявителя обычным способом (см. A8.6.). С этого момента typedef– имя синтаксически эквивалентно ключевому слову спецификатора типа, обозначающему связанный с ним тип. Например, после

typedef long Blockno, *Blockptr;

typedef struct { double r, theta; } Complex;

допустимы следующие объявления:

Blockno b;

extern Blockptr bp;

Complex z, *zp;

b принадлежит типу long, bp– типу "указатель на long"; z– это структура заданного вида, a zp– принадлежит типу "указатель на такую структуру".

Объявление typedef не вводит новых типов, оно только дает имена типам, которые могли бы быть специфицированы и другим способом. Например, b имеет тот же тип, что и любой другой объект типа long.

typedef– имена могут быть перекрыты другими определениями во внутренней области видимости, но при условии, что в них присутствует указание типа. Например

extern Blockno;

не переобъявляет Blockno, а вот

Поделиться с друзьями: