
Лабораторная работа №6 .
Структуры, объединения. Использование структурированных данных в программе.
Цель работы. Изучить синтаксис работы со структурами и объединениями. Уметь использовать структурированные данные в программах.
Теоретическая часть.
Структура — это совокупность переменных, объединенных под одним именем. В отличии от массивов, которые тоже являются совокупностью переменных, в структуре могут переменные могут иметь разные типы. С помощью структур удобно размещать в полях связанные между собой элементы информации. Объявление структуры создает шаблон, который можно использовать для создания ее объектов (то есть экземпляров этой структуры). Переменные, из которых состоит структура, называются полями. (Поля структуры еще называются элементами или членами).
Структуру можно объявить следующими способами.
struct address
{
char street[10];
char city[10];
unsigned long int index;
};
Таким способом создали описание структуры address. С полями street, city, index.
При такой записи мы не объявили не одной переменной, а просто создали описание структуры. Для того чтобы объявить переменную с таким описанием, необходимо записать:
struct address sovremenik;
Создали переменную sovremenik, являющуюся структурой с описанием address. Это значит, что у переменной sovremenik есть поля street, city, index.
Можно объявить переменную (или несколько, или массив) сразу в описании структуры. Синтаксис показан ниже.
struct address1
{
char street[10];
char city[10];
unsigned long int index;
}vsliga ,sovremenik, rolex;
struct
{
char street[10];
char city[10];
unsigned long int index;
}kinoPenza[3];
В этом случае имя описания структуры указывать не обязательно, как в объявлении 3.
Часто удобно использовать ключевое слово typedef при описании структуры, таким образом создается новый тип данных, и при объявлении переменных можно опускать слово struct. Например так:
typedef struct
{
char street[10];
char city[10];
unsigned long int index;
}address; // создали собственный тип данных address
address sovremenik; // создали переменную с типом address
address[3] kinoPenza; // создали массив переменных с типом address
Доступ к членам структуры.
Доступ к отдельным членам структуры осуществляется с помощью оператора . (который обычно называют оператором точка или оператором доступа к члену структуры). Например, в следующем выражении полю index в уже объявленной переменной-структуре sovremenik присваивается значение почтового индекса, равное 440008:
sovremenik.index = 440008;
Значению city присваивается значение Penza
char city[5] = {'P','e','n','z','a'};
int i =0;
while(i < 5){
sovremenik.city[i]= city[i];
i++;
}
Полями структуры могут быть другие структуры.
Например созданная ранее структура address может быть полем другой структуры:
Typedef struct // создаем свой тип адрес
{
char street[10];
char city[5];
unsigned long int index;
}address;
typedef struct{ // создаем свой тип студент
char name[10];
address adr;
}student;
student alex; // создаем переменную с типом студент
Тогда чтобы получить доступ к индексу во вложенной структуре используется два оператора .
alex.adr.index = 440049;// обращаемся к полю вложенной структуры
Присваивание структур
Информация, которая находится в одной структуре, может быть присвоена другой структуре того же типа при помощи единственного оператора присваивания. Нет необходимости присваивать значения каждого члена в отдельности. Как выполняется присваивание структур.
Например, так
alex.adr = sovremenik;
Указатель на структуру:
Как и на любой другой тип данных в Си у экземпляра структуры можно узнать адрес расположения в памяти, т.е. получить указатель на экземпляр структуру.
student* pointerStudent; // объявляем указатель на структуру типа студент
pointerStudent = &alex; // указатель указывает на alex
Указатели на структуры в Си широко распространены, поэтому присутствует специальный оператор доступа к полям структуры, через указатель на структуру. ->
address alexAdress = pointerStudent-> adr;// доступ к полю adr, через
// указатель на структуру.
Объединения.
Объединение — это объект, который в данный момент может содержать любой из нескольких членов. Т.е. описывает общее место в памяти для всех своих членов. Размер объединения равен размеру наибольшего члена.Объединение можно использовать для экономии памяти, или для представления одного значения в разных типах переменных. Для того чтобы описать объединение используется ключевое слово union. Описание и использование объединения похоже на описание структуры, например.
// описание объединения, размер 32 бита.
union bit32{
int int_value;
char char_massive[4];
short int short_massive[2];
float float_value;
};
// создание переменной
union bit32 myUnion;
Доступ до полей с помощью оперетора «.»
printf("%d \n",sizeof(myUnion));// размер переменной myUnion в байтах
myUnion.int_value = 0x11223344; // присваиваем значение одному из полей
// в других полях появилось этоже значение.
for(i = 0; i < 4; i++){
printf("%x \n",myUnion.char_massive[i]); // выведет 44 33 22 11
}
for(i = 0; i < 2; i++){
printf("%x \n",myUnion.short_massive[i]);// выведет 3344 1122
}
printf("%e \n",myUnion.float_value);// выведет 1.279534e-028.
Практическая часть.
1. Создать и инициализировать структуру для хранения отметок в зачетной книжке за семестр. С обязательными полями – фамилия, оценки за 3 экзамена, и с любым количеством дополнительных полей.
2. Создать и инициализировать массив из 3, созданных ранее структур.
3. Вывести на экран фамилию того студента, у кого средняя оценка за экзамены, ближе всего к средней по группе (из 3 человек).
4. Вывести фамилии в порядке увеличения оценки за экзамены по первому предмету.
5. Сделать инициализацию массива структур из пункта 2, с помощью ввода данных с клавиатуры. Повторить пункты 3-4.
Пример кода программы:
#include <stdio.h>
#include <math.h>
#include <ctype.h>
enum {
TAU,
Informatika,
NumberExamsSubject,
};
enum {
NumberStudents = 3,
};
typedef struct{
char name[40];
unsigned char examsMark[NumberExamsSubject];
float meanExamsMark;
}recordBook;
void main(void){
// для корректной работы printf и scanf
setvbuf(stdin, NULL, _IONBF, 0);
setvbuf(stdout, NULL, _IONBF, 0);
// Инициализация в тексте программы
recordBook students[NumberStudents] = {
{"Иванов", {4,4}},
{"Петров", {5,5}},
{"Сидоров", {3,4}}
};
// инициализация с помощью клавиатуры
int i = 0;
int j = 0;
for(i = 0; i < NumberStudents; i++){
printf("Введите фамилию %d студента \n", i+1 );
scanf("%s", students[i].name);
for(j = 0; j < NumberExamsSubject;j++ ){
printf("Введите оценку %d студента за %d предмет\n", i+1, j+1 );
scanf("%d", &students[i].examsMark[j]);
}
}
// Нахождение средней оценки по экзаменам
for(i = 0; i < NumberStudents; i++){
int summa = 0;
for(j = 0; j < NumberExamsSubject;j++ ){
summa += students[i].examsMark[j];
}
students[i].meanExamsMark = (float)summa/NumberExamsSubject;
}
// Нахождение средней оценки по группе
float meanMarkGroup = 0;
for(i = 0; i < NumberStudents; i++){
meanMarkGroup += students[i].meanExamsMark;
}
meanMarkGroup = meanMarkGroup/NumberStudents;
// Нахождение студента с оценкой самой близкой к средней
float difference = 0;
float min_difference = fabs(meanMarkGroup - students[0].meanExamsMark);// начальная разница
int student_index = 0;
for(i = 1; i < NumberStudents; i++){
difference = fabs(meanMarkGroup - students[i].meanExamsMark);
if(difference < min_difference){
min_difference = difference;
student_index = i;
}
}
printf(" Cтудент с самой близкой к средней оценкой - %s",students[student_index].name);
}
Варианты заданий.
Вариант 1. 1.Описать структуру с именем student, содержащую следующие поля: • name – фамилия; • group – номер группы (целое число); • marks – успеваемость, оценки (массив из пяти элементов). 2. Написать программу, выполняющую следующие действия :
• инициализацию массива massiveStudents, состоящий из 3 структур типа student в тексте программы; • ввод с клавиатуры данных в массив massiveStudents, состоящий из 3 структур типа student; • вывод на дисплей фамилий и номеров групп для всех студентов, включенных в массив, если средний балл студента больше 4,0; • если таких нет, вывести соответствующее сообщение. Вариант 2 1. Описать структуру с именем student, содержащую следующие поля: • name – фамилия; • group – номер группы (целое число); • marks – успеваемость, оценки (массив из пяти элементов).
2. Написать программу, выполняющую следующие действия :
• инициализацию массива massiveStudents, состоящий из 3 структур типа student в тексте программы;
• ввод с клавиатуры данных в массив massiveStudents, состоящий из 3 структур типа student;
• вывод на дисплей фамилий и номеров групп для всех студентов, имеющих оценки 4 и 5; • если таких нет, вывести соответствующее сообщение. Вариант 3 1. Описать структуру с именем student, содержащую следующие поля: • name – фамилия; • group – номер группы (целое число); • marks – успеваемость, оценки (массив из пяти элементов).
2. Написать программу, выполняющую следующие действия :
• инициализацию массива massiveStudents, состоящий из 3 структур типа student в тексте программы;
• ввод с клавиатуры данных в массив massiveStudents, состоящий из 3 структур типа student;
• вывод на дисплей фамилий и номеров групп для всех студентов, имеющих хотя бы одну оценку 2; • если таких студентов нет, вывести соответствующее сообщение.