книги / Язык Си
..pdf//размер памяти, выделяемой под //структурную переменную
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;
Переменные можно объявлять одновременно с заданием шаб лона объединения: