Структура — это совокупность переменных, объединенных под одним именем. С помощью структур удобно размещать в смежных полях связанные между собой элементы информации. Объявление структуры создает шаблон, который можно использовать для создания ее объектов (то есть экземпляров этой структуры). Переменные, из которых состоит структура, называются членами. (Члены структуры еще называются элементами или полями.)
Как правило, члены структуры связаны друг с другом по смыслу. Например, элемент списка рассылки, состоящий из имени и адреса логично представить в виде структуры. В следующем фрагменте кода показано, как объявить структуру, в которой определены поля имени и адреса. Ключевое слово struct сообщает компилятору, что объявляется (еще говорят, «декларируется») структура.
struct addr
{
char name[30];
char street[40];
char city[20];
char state[3];
unsigned long int zip;
};
Обратите внимание, что объявление завершается точкой с запятой, потому что объявление структуры является оператором. Кроме того, тег структуры addr идентифицирует эту конкретную структуру данных и является спецификатором ее типа.
В данном случае на самом деле никакая переменная не создается. Всего лишь определяется вид данных. Когда вы объявляете структуру, то определяете агрегатный тип, а не переменную. И пока вы не объявите переменную этого типа, то существовать она не будет. Чтобы объявить переменную (то есть физический объект) типа addr, напишите следующее:
struct addr addr_info;
В этом операторе объявлена переменная типа addr, которая называется addr_info. Таким образом, addr описывает вид структуры (ее тип), a addr_info является экземпляром (объектом) этой структуры.
Когда объявляется переменная-структура, компилятор автоматически выделяет количество памяти, достаточное, чтобы разместить все ее члены. На рис. 7.1 показано, как addr_info размещена в памяти; в данном случае предполагается, что целые переменные типа long занимают по 4 байта.
+------------------------------------------+
|Name (имя) 30 байт |
+------------------------------------------+
+-------------------------------------------------+
|Street (улица) 40 байт |
+-------------------------------------------------+
+-----------------------------------+
|City (город) 20 байт |
+-----------------------------------+
+---------------------+
|State (штат) 3 байта |
+---------------------+
+----------------------------+
|Zip (код) 4 байта |
+----------------------------+
Рис. 7.1. Расположение в памяти структуры addr_info
Одновременно с объявлением структуры можно объявить одну или несколько переменных. Например,
struct addr {
char name[30];
char street[40];
char city[20];
char state[3];
unsigned long int zip;
} addr_info, binfo, cinfo;
определяет тип структуры, называемый addr, и объявляет переменные этого типа addr_info, binfo и cinfo. Важно понимать, что каждая переменная-структура содержит собственные копии членов структуры. Например, поле zip в binfo отличается от поля zip в cinfo. Изменения в zip из binfo не повлияют на содержимое поля zip, находящегося в cinfo.
Если нужна только одна переменная-структура, то тег структуры является лишним. В этом случае наш пример объявления можно переписать следующим образом:
struct {
char name[30];
char street[40];
char city[20];
char state[3];
unsigned long int zip;
} addr_info;
В этом случае объявляется одна переменная с именем addr_info, причем ее поля указаны в структуре, которая предшествует этому имени.
Общий вид объявления структуры такой:
struct тег {
тип имя-члена;
тип имя-члена;
тип имя-члена;
.
.
.
} переменные-структуры;
причем тег или переменные-структуры могут быть пропущены, но только не оба одновременно.
Доступ к членам структуры
Доступ к отдельным членам структуры осуществляется с помощью оператора . (который обычно называют оператором точка или оператором доступа к члену структуры). Например, в следующем выражении полю zip в уже объявленной переменной-структуре addr_info присваивается значение ZIP-кода, равное 12345:
addr_info.zip = 12345;
Этот отдельный член определяется именем объекта (в данном случае addr_info), за которым следует точка, а затем именем самого этого члена (в данном случае zip). В общем виде использование оператора точка для доступа к члену структуры выглядит таким образом:
имя-объекта.имя-члена
Поэтому, чтобы вывести ZIP-код на экран, напишите следующее:
printf("%d", addr_info.zip);
Будет выведен ZIP-код, который находится в члене zip переменной-структуры addr_infо.
Точно так же в вызове gets() можно использовать массив символов addr_infо.name:
gets(addr_info.name);
Таким образом, в начало name передается указатель на символьную строку.
Так как name является массивом символов, то чтобы получить доступ к отдельным символам в массиве addr_info.name, можно использовать индексы вместе с name. Например, с помощью следующего кода можно посимвольно вывести на экран содержимое addr_info.name:
for(t=0; addr_info.name[t]; ++t)
putchar(addr_info.name[t]);
Обратите внимание, что индексируется именно name (а не addr_info). Помните, что addr_info — это имя всего объекта-структуры, a name — имя элемента этой структуры. Таким образом, если требуется индексировать элемент структуры, то индекс необходимо указывать после имени этого элемента.
Присваивание структур
Информация, которая находится в одной структуре, может быть присвоена другой структуре того же типа при помощи единственного оператора присваивания. Нет необходимости присваивать значения каждого члена в отдельности. Как выполняется присваивание структур, показывает следующая программа:
#include <stdio.h>
int main(void)
{
struct {
int a;
int b;
} x, y;
x.a = 10;
y = x; /* присваение одной структуры другой */
printf("%d", y.a);
return 0;
}
После присвоения в y.a будет храниться значение 10.