Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

книги / Язык Си

..pdf
Скачиваний:
6
Добавлен:
20.11.2023
Размер:
7.64 Mб
Скачать

//размер памяти, выделяемой под //структурную переменную

s_all = sizeof(studl);

printf(M%d\n%d",s,s_all); getch();

return 0;

}

Результат на экране:

29

32

Поскольку сумма полей структуры дает 29 байт, а память вы­ деляется кратно 4 или 8, то под studl выделяется 32 байта.

Задание шаблона структуры и объявление переменных может производиться и в одном операторе:

struct student

{char name[20];

int kurs;

char group[5];

} studl, stud2;

Здесь одновременно задается структура с именем student и объявляются переменные studl и studl.

Нельзя инициализировать поля структуры внутри определе­ ния структуры.

struct student

{char паше[20]=ПИванов М.С.М; //ОШИБКА!

int kurs=l;

//ОШИБКА!

char group[5];

};

Доступ к элементу {полю) структуры осуществляется с по­ мощью операции «точка» (.). Например,

strcpy(siudl.паше, "Иванов М.С.");

или

siudl.name = "Иванов М.С.";

Если мы хотим напечатать содержимое поля group перемен­ ной studl структуры student, мы должны написать

printf("%s",stud2.group);

11.1.1. Массивы структур

Структуры, как и переменные другого типа, могут объеди­ няться в массивы. Чтобы объявить массив структур, надо сначала задать шаблон структуры, а затем объявить массив:

struct student {char name[30]; int semestr; int ocenka[5];

};

student Group[15];

Этот оператор создаст массив из 15 переменных типа student. К любому элементу такого массива можно обратиться через ин­ декс: Group[Q\, Group[1], Group[2] и т.д.

Пример. Оценки по информатике для трех человек группы РКТ-10.

#include<stdio.h>

#include<conio.h>

struct Informatika {char *name;

int ocenka;

};

main()

{int i;

//создаем массив на трех студентов

Informatika RKT_10[3];

//заполняем поля элементов массива

=

4;

RKT_10 [0] .name=MIvanov";

RKT_10[0].ocenka

RKT_10 [1] .name=MPetrov";

RKT_10[1].ocenka

=

3;

RKT_10 [2] .naIne=,, idorov";

RKT_10 [2].ocenka

=

5;

// печатаем массив for(i=0;i<3;i++)

printf("%s %d\n",RKT_10[i].name, RKT_10[i].ocenka) ;

getch(); return 0;

}

Результат на экране:

Ivanov: 4

Petrov: 3

Sidorov: 5

При объявлении структурных переменных им сразу можно задавать значения.

Informatika RKT_10[]={{"Ivanov", 4},

{"Petrov",3}, {"Sidorov",5}};

Если объявлены две переменные структурного типа с одина­ ковым шаблоном, то можно сделать присваивание:

Studl = Stud2;

при этом произойдет побитовое копирование каждого поля одной переменной в соответствующее поле другой переменной.

В то же время нельзя использовать операцию присваивания = для переменных структурного типа, шаблоны которых описаны под разными именами, пусть даже совсем идентично.

Пример. Ошибочное копирование переменных структурного типа.

#include<stdio.h>

#include<conio.h>

struct

 

RKT__10

{char name[30];

int

kurs;

struct

 

EMS_10

{char name[30];

int

kurs;

};

 

 

int main()

{RKT_10

a={1Ivanov",1},b;

EMS_10

c;

b=a;

 

//ПРАВИЛЬНО!

c=a;

 

//ОШИБКА!

getch();

return

0;

}

 

 

Как видно, поля структур RKT10 и EMS_10 совсем одинако­ вы, но все же это разные структуры, и попытка копирования с = а приводит к ошибке, поскольку с - переменная структурного типа EMS_10, а а - переменная структурного типа RKT10.

11.1.2. Передача структур функциям

Переменная структурного типа может быть глобальной пере­ менной, локальной переменной или параметром функции.

Пример. Передача в функцию структурной переменной.

#include<conio.h>

#include<stdio.h>

struct Birthday {signed day; signed month; signed year;

};

void my_print(Birthday); //прототип функции

main()

{Birthday Ivanov;

Ivanov.day=l0; Ivanov.month=l; Ivanov.year=l987; my__print (Ivanov) ; getch();

return 0;

}

void my_print(Birthday student)

{

printf("%3d%2d%5dM, student.day,

student, month, student.year);

}

В функцию также можно передавать отдельные поля струк­ турной переменной.

Пример. Передача в функцию полей структурной перемен­

ной.

#include<conio.h>

#include<stdio.h> struct Birthday {signed day;

signed month; signed year;

};

void my_print (signed, signed, signed) ;

main()

{Birthday Ivanov;

Ivanov.day=l0;

Ivanov.month=l;

Ivanov.year=1987;

my_print (Ivanov, day, Ivanov .month, Ivanov.year);

getch(); return 0;

}

void my_print(signed day, signed month, signed year)

{

printf("%3d%2d%5d", day,month,year);

}

Если структурная переменная, переданная в функцию, изме­ нила там свое значение, то при выходе из функции стек будет очищен, и сделанные изменения будут потеряны (так же как и для обычной переменной).

Пример. Передача в функцию структурной переменной по значению.

#include<conio.h>

#include<stdio.h>

struct Birthday {signed day; signed month; signed year;

void init(Birthday);

//прототип функции

int main() {Birthday Ivanov;

init(Ivanov);

printf (f,%3d%2d%5d" ,Ivanov.day, Ivanov .month, Ivanov.year);

getch(); return 0;

//функция инициализации структурной //переменной

void init(Birthday а) {a.day=10;

а.month=l;

а.year=1987;

}

Результат на экране:

1 2 5 6

1

Чтобы не потерять при выходе из функции сделанные в ее па­ раметрах изменения, их надо передавать по ссылке. Изменим в примере прототип функции

void init (Birthday &) ; // прототип функции

и заголовок функции

void init(Birthday &а) {а .day=10;

а.month=l;

а.уеаг=1987;

}

Результат на экране:

10 1 1987

При передаче структурной переменной по значению все эле­ менты структуры копируются в стек. Если структура простая и содержит мало элементов, то это не так страшно. Если же в функ­ цию передается структурный массив большого размера, у которого поля элементов содержат также большие массивы, то на копиро­ вание в стек уже требуется заметно больше времени, кроме того, стек может переполниться. При передаче по ссылке в стек зано­ сится только адрес структуры, при этом копирования структуры не происходит. Таким образом, передача структур по ссылке может использоваться для экономии времени выполнения программы и вычислительных ресурсов.

Также в языке Си можно создать указатель на структуру:

struct student {char name[30]; int semestr; int ocenka[5];

} ;

student *RKT; //указатель.

Пример. Использование указателя структурного типа.

#include<conio.h>

#include<stdio.h>

struct Book {char *autor; char *title; signed year;

};

void my_print(Book*);

//прототип функции

main()

структурного типа

{Book *Cpp; //указатель

(*Cpp).autor=MBjarne Straustrup";

(*Cpp).title=MThe C++ programming language"; (*Cpp).year=1985;

my_print(Cpp); return 0;

}

void my_print(Book *Cpp)

{printf("%s %s %d",Cpp->autor,Cpp->title, Cpp->year);

getch();

Для обращения к полю указателя на структуру удобнее ис­ пользовать операцию «стрелка» (->), как это было сделано в теле функции ту_print, т.е. вместо (*Cpp).autor мы можем использо­ вать Cpp->autor. Этот способ обычно и применяется.

В качестве полей структуры можно использовать другие ра­ нее объявленные структуры и массивы структур.

Пример. Использование структуры в качестве поля другой структуры.

#include<conio.h>

#include<stdio.h>

struct Birthday {signed day; signed month; signed year;

};

struct Student

{char *name; Birthday birth; int mark;

};

void my_print (Student []) ; //прототип функции

main()

{Student RKT[3];

RKT[0].name="Ivanov";

RKT[0].birth.day=10; RKT[0] .birth.month=l; RKT[0].birth.year=1987; my_print(RKT); getch();

return 0;

void my_print(Student RKT[]) {printf("%s%3d%2d%5d", RKT[0].name,

RKT [0].birth.day, RKT[0].birth.month, RKT[0].birth.year);

}

В данном примере для описания студента мы ввели структу­ ру Student с полями *пате {имя), birth {день рождения), mark {оценка). В свою очередь, у поля birth есть свои поля: day {день), month {месяц), year {год).

name

day

RKT[i] birth month

year

mark

Таким образом, для описания сложного объекта гораздо удобнее использовать структуры, чем, например, множество раз­ ных массивов.

11.2. Объединения

Объединения находятся в «близком родстве» со структурами. Они определяются с помощью служебного слова union. С их по­ мощью можно размещать в памяти несколько переменных разного типа. Создается объединение так же, как и структура, например

union my_type

{int i; char ch;

long double a;

};

Под данное объединение место в памяти пока не выделено, для этого нужно создать переменную, например

my_type X;

Переменные можно объявлять одновременно с заданием шаб­ лона объединения: