Перечислимый тип задаёт тип, который является подмножеством целого типа.
Объявление переменной перечислимого типа задаёт имя переменной и определяет список именованных констант, называемый списком перечисления:
enum [<тег>] {<список перечисления>} <описатель> [, <описатель> ...];
enum <тег> <описатель> [, <описатель> ...];
Тег предназначен для различения нескольких перечислимых типов, объявленных в одной программе.
Список перечисления содержит одну или более конструкций вида:
<идентификатор> [= <константное выражение>]
Конструкции в списке разделяются запятыми. Каждый идентификатор именует элемент списка перечисления. По умолчанию, если не задано константное выражение, первому элементу присваивается значение 0, следующему элементу – значение 1 и т.д.
Запись = <константное выражение> изменяет умалчиваемую последовательность значений. Элемент, идентификатор которого предшествует записи = <константное выражение>, принимает значение, задаваемое этим константным выражением. Константное выражение должно иметь тип int и может быть как положительным, так и отрицательным. Следующий элемент списка получает значение, равное <константное выражение> + 1, если только его значение не задаётся явно другим константным выражением.
В списке перечисления могут содержаться элементы, которым сопоставлены одинаковые значения, однако каждый идентификатор в списке должен быть уникальным. Кроме того, идентификатор элемента списка перечисления должен быть отличным от идентификаторов элементов всех остальных списков перечислений, а также от других идентификаторов.
enum Weekdays {SA, SU, MO, TU, WE, TH, FR}; | |
enum Weekdays {SA, SU = 0, MO, TU, WE, TH, FR}; | // SA и SU имеют одинаковое значение |
void main() | |
{ enum Weekdays d1 = SA, d2 = SU, d3 = WE, d4; |
|
d4 = 2; | // Ошибка! |
d4 = d1 + d2; | // Ошибка! |
d4 = (enum Weekdays)(d1 + d2); | // Можно, но результат |
d4 = (enum Weekdays)(d1 - d2); | // может не попасть |
d4 = (enum Weekdays)(TH * FR); | // в область определения |
d4 = (enum Weekdays)(WE / TU); | // перечисления |
} |
Структура позволяет объединить в одном объекте совокупность значений, которые могут иметь различные типы. Однако в языке С реализован очень ограниченный набор операций над структурами как единым целым: передача функции в качестве аргумента, возврат в качестве значения функции, получение адреса. Можно присваивать одну структуру другой, если они имеют одинаковый тип.
Объявление структуры задает имя структурного типа и/или последовательность объявлений переменных, называемых элементами структуры. Эти элементы могут иметь различные типы.
struct [<тег>] {<список объявлений элементов>} <описатель> [, <описатель> ...];
struct <тег> <описатель> [, <описатель> ...];
Тег предназначен для различения нескольких структур, объявленных в одной программе.
Список объявлений элементов представляет собой последовательность из одного или более объявлений переменных. Каждая переменная, объявленная в этом списке, называется элементом структуры. Особенность синтаксиса объявлений элементов структуры состоит в том, что они не могут содержать спецификаций класса памяти и инициализаторов. Элементы структуры могут иметь базовый тип, либо быть массивом, указателем, объединением или структурой.
struct | |
{ char str[50]; | |
int a, b; | // Объявляем структуру, не задавая тег |
} s; | // и сразу же объявляем переменную |
struct S | |
{ char str[50]; | |
int a, b; | |
}; | // Объявляем структуру с тегом S |
struct S s; | // Объявляем переменную |
Элемент структуры не может быть структурой того же типа, в которой он содержится. Однако он может быть указателем на тип структуры, в которую он входит. Размер указателя стандартный, поэтому компилятор знает, сколько памяти потребуется под указатель. Для работы с указателем надо знать размер типа, на который он указывает, но к моменту работы с указателем структура будет полностью объявлена, и, следовательно, размер её будет известен.
Идентификаторы элементов структуры должны различаться между собой. Идентификаторы элементов разных структур могут совпадать.
Для инициализации структуры, как и других составных типов, надо записать список инициализаторов через запятую в фигурных скобках.
struct S s = {"Str", 0, 1}; | // Используем тег S, объявленный в предыдущем примере |
Выбор элемента структуры осуществляется с помощью одной из следующих конструкций:
<переменная> . <идентификатор элемента структуры>
<указатель> -> <идентификатор элемента структуры>
Выражение выбора элемента позволяет получить доступ к элементу структуры. Выражение имеет значение и тип выбранного элемента.
struct S s, *p = &s; | // Объявляем переменную s и указатель p, в который заносим адрес переменной s |
s.a = 10; | |
p->b = 20; |
Две структуры являются разными типами, даже если их объявления полностью совпадают.
Вводим массив структур и осуществляем поиск по любой совокупности параметров.
#include <sspanio.h>
#include <string.h>
#include <conio.h>
struct S // Объявляем структуру, состоящую
{ char str[21]; // из строки и целого числа
int a;
};
struct S s[10]; // Объявляем массив структур
void main(int argc, char *argv[])
{ int n, a, i, check = 0; // Переменная а содержит число, которое будет сравниваться с полем структуры а.
// Переменная check указывает, нужно ли использовать этот параметр для поиска.
char str[21] = ""; // Переменная str содержит строку, которая будет сравниваться с полем структуры str.
// Если переменная str содержит пустую строку, этот параметр не используется для поиска.
FILE *in, *out;
char ans;
if (argc < 3)
{ printf("Too few arguments.\n"); return; }
if ((in = fopen(argv[1], "r")) == NULL)
{ printf("It is impossible to open file '%s'.\n", argv[1]);
return;
}
if ((out = fopen(argv[2], "w")) == NULL)
{ printf("It is impossible to open file '%s'.\n", argv[2]);
fclose(in); return;
}
for (n = 0; !feof(in); n++)
fscanf(in, "%s%d", s[n].str, &s[n].a);
fclose(in);
printf("Use Str for search? "); ans = getche();
if (ans == 'y' || ans == 'Y')
{ printf("\nInput string for search: "); scanf("%s",str); }
printf("Use A for search? "); ans = getche();
if (ans == 'y' || ans == 'Y')
{ check = 1; printf("\nInput A: "); scanf("%d", &a); }
for (i = 0; i < n; i++)
if ((!*str || strcmp(str, s[i].str) == 0) && // Данное условие проверяет содержимое структуры на равенство
(!check || a == s[i].a)) // параметрам поиска, учитывая необходимость сравнения с этим параметром
fprintf(out, "%-30s %3d\n", s[i].str, s[i].a);
fclose(out);
}
Объединение позволяет в разные моменты времени хранить в одном объекте значения разных типов. В процессе объявления объединения с ним ассоциируется набор типов значений, которые могут храниться в данном объединении. В каждый момент времени объединение может хранить значение только одного типа из набора. Контроль над тем, какого типа значение хранится в данный момент в объединении, возлагается на программиста.
union [<тег>] {<список объявлений элементов>} <описатель> [, <описатель> ...];
union <тег> <описатель> [, <описатель> ...];
Тег предназначен для различения нескольких объединений, объявленных в одной программе.
Память, которая выделяется переменной типа объединение, определяется размером наиболее длинного элемента объединения. Все элементы объединения размещаются в одной и той же области памяти с одного и того же адреса. Значение текущего элемента объединения теряется, когда другому элементу объединения присваивается значение.
#include <stdio.h> void main() { union { float f; long int i; } u; printf("Input float number: "); scanf("%f", &u.f); printf("Internal: %08x\n\n", u.i); } |