Лекции / lezione6
.htmlПеречислимый тип. Структуры. Объединения Лекция 6. Перечислимый тип. Структуры. Объединения 1. Перечислимый тип Перечислимый тип задаёт тип, который является подмножеством целого типа. Объявление переменной перечислимого типа задаёт имя переменной и определяет список именованных констант, называемый списком перечисления:
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); // перечисления } 2. Структуры Структура позволяет объединить в одном объекте совокупность значений, которые могут иметь различные типы. Однако в языке С реализован очень ограниченный набор операций над структурами как единым целым: передача функции в качестве аргумента, возврат в качестве значения функции, получение адреса. Можно присваивать одну структуру другой, если они имеют одинаковый тип. Объявление структуры задает имя структурного типа и/или последовательность объявлений переменных, называемых элементами структуры. Эти элементы могут иметь различные типы.
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; Две структуры являются разными типами, даже если у них одинаковые члены. 2.1. Пример Вводим массив структур и осуществляем поиск по любой совокупности параметров.
#include <stdio.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);
}
3. Объединения Объединение позволяет в разные моменты времени хранить в одном объекте значения разных типов. В процессе объявления объединения с ним ассоциируется набор типов значений, которые могут храниться в данном объединении. В каждый момент времени объединение может хранить значение только одного типа из набора. Контроль над тем, какого типа значение хранится в данный момент в объединении, возлагается на программиста.
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);
}
Содержание