Лекция 8.ppt
- Количество слайдов: 49
ТИПЫ ДАННЫХ, ОПРЕДЕЛЯЕМЫЕ ПРОГРАММИСТОМ. СТРУКТУРЫ
typedef Для объявления имен новых типов данных используется ключевого слова typedef: typedef <имя_типа> <новое_имя>; Новый тип данных не создается, а определяется новое имя существующего типа typedef float balance; balance money; // это вещественная переменная типа balance, другими словами - типа float.
Структуры
Структура - это составной объект, в который входят элементы любых типов, за исключением функций. Для удобства работы с этими данными они сгруппированы под одним именем. При разработке программ структуры помогают в организации хранения и обработке сложных данных, не разобщая их по различным объектам, а группируя в одном. Объекты, входящие в структуру, сами могут быть структурой, т. е. структуры могут быть вложенными.
Как и массив, структура представляет собой совокупность данных (полей), но отличается от него тем, что к ее элементам (компонентам) необходимо обращаться по имени и ее элементы могут быть различного типа. Структуры целесообразно использовать там, где необходимо объединить разнообразные данные, относящиеся к одному объекту.
Как и другие объекты в Си, структуры должны быть определены. Для определения структуры создается некоторый тип, являющийся структурой, а затем, по мере необходимости, определяются переменные этого типа (типа структура). Объявление структуры осуществляется с помощью ключевого слова struct, за которым следует имя, называемое тегом (именем) структуры и списка элементов, заключенных в фигурные скобки.
Тег дает название структуре данного вида и в дальнейшем служит кратким обозначением той части описания структуры, которая заключена в фигурные скобки, то есть является спецификатором. struct adres { char name[30]; char street [40]; char city[20]; char state[3]; }; Объявление завершается точкой с запятой, поскольку объявление структуры - это оператор.
Имя структуры adres идентифицирует структуру данных и является спецификатором типа. На данный момент переменная еще не создана! Определена только форма данных. Для объявления переменной, соответствующей данной структуре, следует написать: struct adres Adres. Info;
Когда объявлена структурная переменная, компилятор автоматически выделяет необходимый участок памяти для размещения всех ее членов. char name[30]; char street [40]; char city[20]; char state[3]; Adres. Info
При объявлении структуры можно одновременно объявить несколько переменных: struct adres { char name[30]; char street[40]; char city[20]; char state[3]; } Adres. Info 1, Adres. Info 2, Adres. Info 3; Если необходима только одна структурная переменная: struct { char name[30]; char street[40]; char city[20]; char state[3]; } Adres. Info;
Не рекомендуется декларировать поле структуры указателем на объект переменной размерности. При декларации структурных переменных возможна их одновременная инициализация. struct adres { char name[30]; char street[40]; char city[20]; } Adres. Info = {“Ivanov I. I. ", “Kozlova”, “ Minsk" }; или adres Adres. Info = {"Ivanov I. I. ", “Kozlova”, “ Minsk" }; Если список инициализации короче, то оставшиеся поля заполняются « 0»
Доступ к компонентам структуры
а) с использованием операции принадлежности (. ) в виде: имя_переменной_структуры. ID_поля или (*указатель_структуры). ID_поля такой способ доступа к элементам структуры работает только в том случае, когда структура не является указателем на структуру. б) при помощи операции косвенной адресации (->) в виде: указатель_структуры -> ID_поля или (&ID_структуры) ->ID_поля
date[1]. day=12; strcpy(att[10]. FIO, ”Ivanov I. I. ”); Доступ по указателю strcpy((per_ptr+10)->FIO, ” Ivanov I. I. ”); или strcpy((*(per_ptr+10))->FIO, ” Ivanov I. I. ”); att[i]. mark=6; (att+i)->mark=6; (*(att+i). mark=6;
Пример 1 #include
do { system("cls"); printf("студент №%dn", rec + 1); puts("введите ФИО студента: "); fflush(stdin); fgets(&att[rec]. FIO[0], 100, stdin); puts("введите оценку по математике"); scanf("%d", &att[rec]. math); puts("введите оценку по английскому языку"); scanf("%d", &att[rec]. eng); puts("введите оценку по физике"); scanf("%d", &att[rec]. phys); puts("введите оценку поведения"); fflush(stdin); fgets(&att[rec]. pov[0], 20, stdin); rec++; puts("прекратить работу? [y/n]"); scanf("%c", &ch); } while (ch == 'n'); Заполнение
for (int i = 0; i < rec; i++){ att[i]. aver = (att[i]. eng + att[i]. math + att[i]. phys) / 3; } Расчет среднего балла for (int i = 0; i < rec; i++){ printf("Средний балл по аттестату %s = %. 2 lf n", att[i]. FIO, att[i]. aver); } _getch(); } Вывод результата на экран
. . . struct school { char FIO[100]; int math; int eng; int phys; char pov[20]; double aver; }; Пример 2 Объявление функций void Inp. Str(int, school*); void Avg. Str(int, school*); void Out. Str(school*); void main(){ school att[30], temp; char ch; setlocale(LC_CTYPE, "Russian"); int i, n;
void Inp. Str(int n, int i, school* stud){ Функция заполнения структур system("cls"); printf("студент №%dn", i + 1); puts("введите ФИО студента: "); fflush(stdin); gets(stud->FIO); puts("введите оценку по математике"); scanf("%d", &stud->math); puts("введите оценку по английскому языку"); scanf("%d", &stud->eng); puts("введите оценку по физике"); scanf("%d", &stud->phys); puts("введите оценку поведения"); fflush(stdin); gets(stud->pov); } Обращение через указатель (косвенная адресация)
void Avg. Str(int n, school* stud){ Функция расчета среднего значения for (int i = 0; i < n; i++){ stud->aver = (stud->eng + stud->math + stud->phys) / 3; } } void Out. Str(school* stud){ Функция вывода на печать printf("Средний балл по аттестату %s = %. 2 lf n", stud->FIO, stud ->aver); }
Копирование структур
Структуры одного типа можно присваивать другу. В этом случае оператор присваивания выполняет поверхностное копирование бит за битом полей переменной-источника и перенесение их в соответствующие поля переменной-цели (обе структуры-переменные имеют одинаковый тип). С членами данных типа указатель могут возникнуть проблемы.
Копирование структур рекомендуется выполнять, используя функцию memcpy, string. h: memcpy(& destptr, & srcptr, sizeof(тип_структуры)); Копирует n байтов из srcptr в destptr и возвращает адрес destpt.
. . . struct school { char FIO[100]; int math; int eng; int phys; char pov[20]; double aver; } stud, univer; Объявление 2 -х переменных типа структуры void Cmp. Str(int n, school * stud, school * univer){ memcpy(univer->FIO, stud->FIO, sizeof(school)); } Копирование поля одной структуры в другую
Вложенные структуры
Элементами структуры могут быть массивы и другие структуры (исключение: тип void и функции).
. . . struct FIO { char name[50]; char surname[50]; }; struct school { FIO date; int math; int eng; int phys; char pov[20]; double aver; } stud; void Inp. Str(int, school*); void Out. Str(school*); void Avg. Str(int, school*); Пример 1 Объявление вложенной структуры Вложенная структура
void main(){ char ch; setlocale(LC_CTYPE, "Russian"); int i, n; puts("Введите кол-во студентов"); scanf("%d", &n); school *stud = new school [n]; Set. Console. CP(1251); Set. Console. Output. CP(1251); for (int i = 0; i < n; i++){ Inp. Str(n, i, stud+i); Avg. Str(n, stud+i); } for (int i = 0; i < n; i++){ Out. Str(stud+i); } _getch(); }
void Inp. Str(int n, int i, school* stud){ system("cls"); printf("студент №%dn", i + 1); puts("введите фамилию студента: "); fflush(stdin); gets(stud->date. surname); puts("введите имя студента: "); fflush(stdin); gets(stud->date. name); puts("введите оценку по математике"); scanf("%d", &stud->math); puts("введите оценку по английскому языку"); scanf("%d", &stud->eng); puts("введите оценку по физике"); scanf("%d", &stud->phys); puts("введите оценку поведения"); fflush(stdin); gets(stud->pov); } Обращение к элементу вложенной структуры
void Avg. Str(int n, school* stud){ for (int i = 0; i < n; i++){ stud->aver = (stud->eng + stud->math + stud->phys) / 3; } } void Out. Str(school* stud){ printf("Средний балл по аттестату %s = %. 2 lf n", stud>date. surname, stud->aver); }
. . . struct FIO { char name[50]; char surname[50]; }; struct school { FIO date; int math; int eng; int phys; char pov[20]; double aver; } stud; Пример 2
void Inp. Str(int); void Out. Str(int); void main(){ setlocale(LC_CTYPE, "Russian"); int pos = 1, n; while (pos > 0 && pos < 3){ system("cls"); puts("Выберите пункт меню: "); puts("-----------------------"); puts("1. Создать список"); puts(“ 2. Показать результат"); puts(“ 3. Выход"); puts("-----------------------"); scanf("%d", &pos);
switch (pos){ case 1: puts("Введите кол-во студентов"); scanf("%d", &n); Inp. Str(n); break; case 2: Out. Str(n); break; default: puts("Выход из программы. "); break; } } _getch(); } void Inp. Str(int n){ FILE *fp; school *stud = new school [n]; Set. Console. CP(1251); Set. Console. Output. CP(1251);
if ((fp = fopen("d: \@Work\Students. txt", "w")) == NULL) { printf("Cannot open file. n"); exit(1); } for (int i = 0; i < n; i++){ system("cls"); printf("студент №%dn", i + 1); puts("введите фамилию студента: "); fflush(stdin); gets(stud->date. surname); puts("введите имя студента: "); fflush(stdin); gets(stud->date. name); puts("введите оценку по математике"); scanf("%d", &stud->math); puts("введите оценку по английскому языку"); scanf("%d", &stud->eng); puts("введите оценку по физике"); scanf("%d", &stud->phys); puts("введите оценку поведения"); fflush(stdin); gets(stud->pov);
fwrite(stud, sizeof(school), 1, fp); } Блочная запись в файл fclose(fp); } void Out. Str(int n){ FILE *fp; school *stud = new school[n]; Блочное чтение из файла if ((fp = fopen("d: \@Work\Students. txt", "r")) == NULL) { printf("Cannot open file. n"); exit(1); } while (fread(stud, sizeof(school), 1, fp)!=NULL){ printf("%s %10 s %5 d %10 d %10 s n", stud->date. surname, stud->date. name, stud->math, stud->eng, stud->phys, stud->pov); } fclose(fp); _getch(); }
Блочный ввод-вывод данных int fread (void *p, int size, int n, FILE *f); считывает n блоков по size байт каждый из файла f в область памяти с указателем p. int fwrite (void *p, int size, int n, FILE *f); записывает n блоков по size байт каждый из области памяти с указателем p в файл f.
Объединения
Объединение - сложный тип данных, позволяющий размещать в одном и том же месте оперативной памяти данные различных типов. Размер оперативной памяти, требуемый для хранения объединений, определяется размером памяти типа, который требует максимального количества байт. Когда используется элемент меньшей длины, чем наиболее длинный элемент объединения, то этот элемент использует только часть отведенной памяти. Все элементы объединения хранятся в одной и той же области памяти, начиная с одного адреса. Для объявления используется специальное слово union.
union
. . . union { char name 1; int number 2; long int number 3; } my. Union; int main() { setlocale(LC_CTYPE, "Rus"); my. Union. name 1 = 'N'; printf("Первое значение: %cn", my. Union. name 1); my. Union. number 2 = 222; printf("Второе значение: %dn", my. Union. number 2); my. Union. number 3 = 22222; printf("Третье значение: %dn", my. Union. number 3); printf("Первое значение: %c", my. Union. name 1); _getch(); } Пример 1
После того, как записали значение в элемент number 3 типа long int , уже невозможно нормально обращаться к элементу name 1. Связано это с тем, что в их общую память уже записано значение long int, а переменная типа char неспособна работать с данными такого объема. Поэтому: . . . printf("Третье значение: %dn", my. Union. number 3); my. Union. name 1 = 'N'; printf("Первое значение: %c", my. Union. name 1); _getch(); }
Перечисления
Перечисления - это набор именованных целочисленных констант, определяющий все допустимые значения, которые может принимать переменная. Перечисления определяются с помощью ключевого слова enum, которое указывает на начало перечисляемого типа. Стандартный вид перечислений следующий: enum ID_типа { список перечислений}; Компилятор последовательно присваивает идентификаторам списка значений целочисленные величины 0, 1, . . . , . При необходимости можно явно задать значение идентификатора, тогда очередные элементы списка будут получать последующие возрастающие значения.
. . . enum level { parking, supermarket, restaurant, boutiques}; void main() { setlocale(LC_ALL, "rus"); level floor = parking; char out='0'; level fl = floor; while (out!='z') { system("cls"); puts( "Нажмите кнопку с номером этажа (от 0 до 3): "); scanf("%d", &fl); switch (fl) { case(parking) : puts("n. Вы спустились в паркинг!!!"); break; Пример 1
case(supermarket) : printf("n. Вы на %d этаже!", supermarket); puts( "n. Здесь находится супермаркет. nn"); break; case(restaurant) : printf("n. Вы на %d этаже!", restaurant); puts("n. Здесь находится ресторан. nn"); break; case(boutiques) : printf("n. Вы на %d этаже!", boutiques); puts("n. Здесь находятся магазины. nn"); break; default: puts("n. Ошибка!"); } puts("Для выхода нажмите 'z' n"); if (_getch() == 'z') break; } }