C. Бочков - Язык программирования Си для персонального компьютера
Во втором примере объявляется переменная типа объединение с именем Jack. Список объявлений элементов содержит три объявления: указателя а на значение типа char, переменной b типа char и массива ж из 20 элементов типа float. Тип объединения не поименован тегом. Память, выделяемая переменной jack, равна памяти, необходимой для хранения массива f, поскольку это самый длинный элемент объединения.
Объявление массива
Синтаксис:
[<спецификация типа]> <описатель> [<константное выражение>];
[<спецификация типа]> <описатель> [];
Квадратные скобки, следующие за описателем, являются элементом языка Си, а не признаком необязательности синтаксической конструкции.
Массив позволяет хранить как единое целое последовательность переменных одинакового типа. Объявление массива определяет тип элементов массива и его имя. Оно может определять также число элементов в массиве. Переменная типа массив участвует в выражениях как константа - указатель на значение заданного спецификацией типа. Если спецификация типа опущена, предполагается тип int.
Объявление массива может иметь одну из двух синтаксических форм, указанных выше. Квадратные скобки, следующие за <описателем>, являются признаком типа массив. Если <описатель> представляет собой идентификатор (имя массива), то объявляется массив элементов специфицированного типа. Если же <описатель> представляет собой более сложную конструкцию (см. раздел 3.3.1), то каждый элемент массива имеет тип, заданный совокупностью <спецификации типа> и оставшейся части описателя. Это может быть любой тип, кроме типов void и функция. Таким образом, элементы массива могут иметь базовый, перечислимый, структурный тип, быть объединением, указателем или, в свою очередь, массивом.
Константное выражение, заключенное в квадратные скобки, определяет число элементов в массиве. Индексация элементов массива начинается с нуля. Таким образом, последний элемент массива имеет индекс на единицу меньше, чем число элементов в массиве.
Во второй синтаксической форме константное выражение в квадратных скобках опущено. Эта форма может быть использована, если в объявлении массива присутствует инициализатор, либо массив объявляется как формальный параметр функции, либо данное объявление является ссылкой на объявление массива где-то в другом месте программы. Однако для многомерного массива может быть опущена только первая размерность.
Многомерный массив, или массив массивов, объявляется путем задания последовательности константных выражений в квадратных скобках, следующей за описателем:
<спецификация типа> <описатель> [<константное выражение>] {<константное выражение>]…;
Каждое константное выражение в квадратных скобках определяет число элементов в данном измерении массива, поэтому объявление двумерного массива содержит два константных выражения, трехмерного — три и т. д.
Массиву выделяется память, которая требуется для размещения всех его элементов. Элементы массива с первого до последнего размещаются в последовательных ячейках памяти, по возрастанию адресов. Между элементами массива в памяти разрывы отсутствуют. Элементы многомерного массива запоминаются построчно. Например, массив, представляющий собой матрицу размером две строки на три столбца
char а[2][3]
будет храниться следующим образом: сначала в памяти запоминаются три элемента первой строки, затем три элемента второй строки. При таком методе хранения последний индекс массива меняется быстрее предпоследнего. Для доступа к отдельному элементу массива используется индексное выражение, которое описано в разделе 4.2.5 "Индексные выражения".
Примеры.
/* пример 1 */
int scores[10], game:
/* пример 2 */
float matrix[10][15];
/* пример 3 */
struct {
float х, у;
} complex[100];
/* пример 4 */
char *name[20];
В первом примере объявляется переменная типа массив с именем scores из 10 элементов типа int. Переменная с именем game объявлена как простая переменная целого типа.
Во втором примере объявляется двумерный массив с именем matrix. Строго говоря, matrix представляет собой массив, состоящий из 10 элементов, каждый из которых является массивом из 15 элементов типа float.
В третьем примере объявляется массив структур типа complex. Он состоит из 100 элементов. Каждый элемент массива представляет собой структуру, содержащую два элемента типа float.
В четвергом примере объявлен массив указателей. Массив содержит 20 элементов, каждый из которых является указателем на значение типа char.
Объявление указателя
Указатель — это переменная, предназначенная для хранения адреса объекта некоторого типа. Указатель на функцию содержит адрес точки входа в функцию.
Синтаксис:
[<спецификация типа]> *<описатель>;
Объявление указателя специфицирует имя переменной-указателя и тип объекта, на который может указывать эта переменная. Спецификация типа может задавать базовый, перечислимый, пустой, структурный тип или тип объединение. Если спецификация типа опущена, предполагается тип int.
Если <описатель> представляет собой идентификатор (имя указателя), то объявляется указатель на значение специфицированного типа. Если же <описатель> представляет собой более сложную конструкцию (см. раздел 3.3.1), то тип объекта, на который указывает указатель, определяется совокупностью оставшейся части описателя и спецификации типа. Указатель может указывать на значения базового, перечислимого типа, структуры, объединения, массивы, функции, указатели.
Специальное применение имеют указатели на тип void. Указатель на void может указывать на значения любого типа. Однако для выполнения операций над указателем на void либо над указуемым объектом, необходимо явно привести тип указателя к типу, отличному от void. Например, если объявлена переменная i типа int и указатель р на тип void
int i;
void *p;
то можно присвоить указателю р адрес переменной i
p = &i;
но изменить значение указателя нельзя. В СП ТС нельзя также получить значение указуемого объекта по операции косвенной адресации (в СП MSC в этом случае выдается предупреждающее сообщение).
р++; /* недопустимо */
(int *)р++; /* допустимо */
j = *p; /* недопустимо в СП ТС */
Можно объявить функцию с типом возвращаемого значения указатель на void. Ее значение может быть присвоено указателю на тот тип, который требуется.
Переменная, объявленная как указатель, хранит адрес памяти. Размер памяти, требуемый для адреса, и формат этого адреса зависит от компьютера и реализации компилятора языка Си. Указатели на один и тот же тип данных не обязательно имеют одинаковый размер и формат, поскольку эти параметры зависят от выбранной модели памяти. Кроме того, существуют модификаторы near, far, huge, специфицирующие формат указателя. Объявления, использующие эти модификаторы, рассмотрены в разделе 3.3.3.4.
Указатель на структуру, объединение или перечислимый тип может быть объявлен до того, как этот тип определен, однако указатель не должен использоваться до определения этого типа. Указатель при этом объявляется посредством использования тега структуры, объединения или перечислимого типа (см. ниже пример 4). Такие объявления допускаются, поскольку компилятору языка Си не требуется знать размер структуры или объединения, чтобы распределить память под указатель.
В стандартном включаемом файле stdio.h определена константа с именем NULL. Она предназначена для инициализации указателей. Гарантируется, что никакой программный объект никогда не будет иметь адрес NULL.
Примеры.
char *message;/* пример 1 */
im *аrrау1 [10]; /* пример 2 */
int (*pointer1)[10];/* пример 3 */
struct list *next, *previous; /* пример 4 */
struct list {/* пример 5 */
char *token;
int *count;
struct list *next;
} line;
struct id {/* пример 6 */
unsigned int id_no;
struct name *pname;
} record;
В первом примере объявляется указатель с именем message. Он указывает на значения типа char.
Во втором примере объявлен массив указателей с именем array1. Массив состоит из 10 элементов. Каждый элемент представляет собой указатель на значения типа int.