
Лаба 5 / Лабораторная_работа_№5_Токарев_0421
.docxМИНОБРНАУКИ РОССИИ
Санкт-Петербургский государственный
электротехнический университет
«ЛЭТИ» им. В.И. Ульянова (Ленина)
Кафедра Электротехнологической и преобразовательной техники
отчет
по лабораторной работе № 5
по дисциплине «Информационные технологии»
Тема: Составные типы данных
Студент гр. 0421 |
|
Токарев А.А. |
Преподаватель |
|
Чмиленко Ф.В. |
Санкт-Петербург
2021
Цель работы: исследование составных типов данных языков С и С++.
Задания:
Перечисления
Одномерные массивы
Многомерные массивы
Структуры
Объединения
Дополнительные задания:
Инструкция цикла range based for
Инициализация полей структуры
Применение структурных привязок (structured bindings)
Ход работы:
Задание 1.
Разработаем программу, в которой определим перечисляемый тип данных Color, создадим переменную этого типа и выведем её значение на консоль. Также выведем на консоль с помощью оператора sizeof() размер, который занимает в памяти перечисляемый тип данных:
#include <stdio.h>
#include <iostream>
using namespace std;
enum Color {Red, Orange, Yellow, Green, Blue, Dark_Blue, Violet};
int main()
{
system("chcp 1251");
system("cls");
Color a = Blue;
cout << "Переменная a равна: " << a << endl;
cout << "Размер перечисляемого типа данных равен: " << sizeof(Color) << " байт(а)"<< endl;
system("pause");
return 0;
}
Рисунок 1 – Результат работы программы, демонстрирующей пример работы с перечисляемым типом данных
По умолчанию в перечисляемом типе данных при отсутствии явной инициализации элементов первому элементу присваивается значение 0, следующему – 1, и т.д. Так как переменной а присвоено значение Blue, котрое по счету в имеющемся перечисляемом типе данных, в котором ни одного элемента явно не инициализировано, имеет порядковый номер 5, то значение переменной а будет равно четырем.
Дополним программу примером с явной инициализацией констант перечисляемого типа и использованием инструкции switch. Сделаем так, чтобы программа по введенной цифре с клавиатуры выводила соответствующий ей цвет радуги. В случае, если цвета с такой цифрой нет, программа выдает ошибку и просит еще раз ввести номер цвета:
#include <stdio.h>
#include <iostream>
using namespace std;
enum Color {Red = 1, Orange = 2, Yellow = 3, Green = 4, Blue = 5, Dark_Blue = 6, Violet = 7};
int main()
{
system("chcp 1251");
system("cls");
int b;
M1: cout << "Введите номер цвета радуги (от 1 до 7)" << endl;
cin >> b;
switch(b)
{
case(Red):
cout << "Этому номеру соответствует красный цвет!" << endl;
break;
case(Orange):
cout << "Этому номеру соответствует оранжевый цвет!"<< endl;
break;
case(Yellow):
cout << "Этому номеру соответствует желтый цвет!"<< endl;
break;
case(Green):
cout << "Этому номеру соответствует зеленый цвет!"<< endl;
break;
case(Blue):
cout << "Этому номеру соответствует голубой цвет!"<< endl;
break;
case(Dark_Blue):
cout << "Этому номеру соответствует синий цвет!"<< endl;
break;
case(Violet):
cout << "Этому номеру соответствует фиолетовый цвет!" << endl;
break;
default:
cout << "Ошибка!Цвета с таким номером в радуге нет!" << endl;
goto M1;
}
system("pause");
return 0;
}
Рисунок 2 – Результат работы программы, дополненной явной инициализацией констант перечисляемого типа и инструкцией switch
Задание 2.
Разработаем программу, в которой создадим и частично инициализируем одномерный массив. Далее через цикл while организуем вывод на консоль значения элемента массива, индекс которого задается с клавиатуры. Также предусмотрим случай некорректно заданного индекса и выход из цикла по вводу буквы z:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int mas[12] = {0, 1, 2, 3, 4}; //зададим массив размером в 12 символов, явно инициализируем первые 5 символов
int i;
system("chcp 1251");
system("cls");
while(true)
{
cout << "Введите индекс элемента массива(для выхода введите z): " << endl;
cin >>i;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (i >= 0 && i < 12) //проверка индекса массива на корректность
{
cout << "Значение элемента массива с индексом " << i << " равно " << mas[i] << endl;
}
else
{
cout << "Ошибка! Индекс элемента массива задан некорректно!" << endl;
}
}
return 0;
}
Рисунок 3 – Результат работы программы, демонстрирующей работу с одномерными массивами
Если с клавиатуры ввести индекс элемента массива, который является неинициализированным, то мы на выходе получим 0, т.к. по умолчанию неинициализированным членам массива присваивается именно значение 0.
Дополним программу циклом for, с помощью которого прибавим к каждому элементу массива 2:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int mas[12] = {0, 1, 2, 3, 4}; //зададим массив размером в 12 символов, явно инициализируем первые 5 символов
int i;
system("chcp 1251");
system("cls");
for (i = 0; i < 12; i++)
{
mas[i] += 2;
}
while(true)
{
cout << "Введите индекс элемента массива(для выхода введите z): " << endl;
cin >>i;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (i >= 0 && i < 12) //проверка индекса массива на корректность
{
cout << "Значение элемента массива с индексом " << i << " равно " << mas[i] << endl;
}
else
{
cout << "Ошибка! Индекс элемента массива задан некорректно!" << endl;
}
}
system("pause");
return 0;
}
Рисунок 4 – Результат работы программы, дополненной циклом for
Задание 3.
Разработаем программу, в которой создадим и инициализируем двухмерный массив. Далее через цикл while организуем вывод на консоль значения элемента массива, два индекса которого задаются с клавиатуры. Также предусмотрим случай, когда какой-нибудь из индексов задан некорректно и выход из цикла по вводу буквы z:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int mas[3][3] = {{1, 3, -2}, {-2, 2, 0}, {-1, 3, 4}}; //зададим массив размерностью 3х3
int i, j;
system("chcp 1251");
system("cls");
while(true)
{
M1:cout << "Введите первый индекс элемента массива(для выхода введите z): " << endl;
cin >> i;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (i < 0 || i >= 3)
{
cout << "Ошибка!Индекс элемента массива задан некорректно!" << endl; //проверка первого индекса массива на корректность
goto M1;
}
cout << "Введите второй индекс элемента массива(для выхода введите z): " << endl;
cin >> j;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (j < 0 || j >= 3)
{
cout << "Ошибка!Индекс элемента массива задан некорректно!" << endl; //проверка второго индекса массива на корректность
}
else
{
cout << "Значение элемента с индексами " << i << " , " << j << " равно " << mas[i][j] << endl;
}
}
return 0;
}
Рисунок 5 – Результат работы программы, демонстрирующей работу с двухмерными массивами
Дополним нашу программу конструкцией из двух вложенных циклов for, с помощью которой посчитаем сумму всех элементов массива:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int mas[3][3] = {{1, 3, -2}, {-2, 2, 0}, {-1, 3, 4}}; //зададим массив размерностью 3х3
int i, j;
int sum = 0;
system("chcp 1251");
system("cls");
for (i = 0; i < 3; i++)
{
for (j = 0; j < 3; j++)
{
sum += mas[i][j];
}
}
cout << "Сумма элементов массива равна " << sum << endl;
while(true)
{
M1:cout << "Введите первый индекс элемента массива(для выхода введите z): " << endl;
cin >> i;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (i < 0 || i >= 3)
{
cout << "Ошибка!Индекс элемента массива задан некорректно!" << endl; //проверка первого индекса массива на корректность
goto M1;
}
cout << "Введите второй индекс элемента массива(для выхода введите z): " << endl;
cin >> j;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (j < 0 || j >= 3)
{
cout << "Ошибка!Индекс элемента массива задан некорректно!" << endl; //проверка второго индекса массива на корректность
}
else
{
cout << "Значение элемента с индексами " << i << " , " << j << " равно " << mas[i][j] << endl;
}
}
system("pause");
return 0;
}
Рисунок 6 – Результат работы программы, дополненной конструкцией из двух вложенных циклов for
Задание 4.
Разработаем программу, в которой определим структуру, внутри которой используется 3 встроенных типа данных. Создадим переменные данного типа. Продемонстрируем инициализацию полей структуры и заполнение полей с помощью ввода с клавиатуры. Также определим с помощью оператора sizeof() размер, занимаемый структурой и размер, занимаемый одним из элементов структуры:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
system("chcp 1251");
system("cls");
struct Grades {int oc_1; int oc_2; int oc_3; float sred;}; // структура, содержащая три оценки студента(целые числа)
// и их среднее арифметическое(вещественное число)
Grades grades;
Grades grades_student_1;
grades.oc_1 = 2; // явная инициализация элементов структуры
grades.oc_2 = 3;
grades.oc_3 = 5;
cout << "Размер структуры grades равен " << sizeof(grades) << " байт(а)" << endl;
cout << "Размер элемента структуры grades.oc_1 равен " << sizeof(grades.oc_1) << " байт(а)" << '\n' << endl;
cout << "Введите первую оценку: " << endl; // ввод элементов структуры с клавиатуры
cin >> grades_student_1.oc_1;
cout << "Введите вторую оценку: " << endl;
cin >> grades_student_1.oc_2;
cout << "Введите третью оценку: " << endl;
cin >> grades_student_1.oc_3;
grades_student_1.sred = static_cast<double>(grades_student_1.oc_1 + grades_student_1.oc_2 + grades_student_1.oc_3) / 3;
//вычисление среднего арифметического трех оценок с помощью приведения типов
cout << "Средний балл студента равен: " << grades_student_1.sred << endl; //вывод элемента структуры
system("pause");
return 0;
}
Рисунок 7 – Результат работы программы, демонстрирующей примеры работы со структурами
Структура grades занимает в памяти 16 байт, т.к. состоит из трех элементов типа int и одной переменной типа float, занимающих в памяти по 4 байта и имеющих параметр выравнивания, равный четырем.
Расширим нашу программу, добавив еще несколько структур в которых поля расположены в другом порядке (упорядоченно и неупорядоченно относительно размеров типов данных). Определим с помощью оператора sizeof() размеры этих структур. Чтобы наглядно показать различия в размещении данных в структуре, будем использовать оператор alignof():
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
system("chcp 1251");
system("cls");
struct Grades {int oc_1; int oc_2; int oc_3; float sred;}; // структура, содержащая три оценки студента(целые числа)
// и их среднее арифметическое(вещественное число)
struct Data_1 {short a; char b; float c;}; // структура, упорядоченная по размеру типа данных
struct Data_2 {short a; float b; char c;}; // структура, неупорядоченная по размеру типа данных
Data_1 data_1;
Data_2 data_2;
Grades grades;
Grades grades_student_1;
grades.oc_1 = 2; // явная инициализация элементов структуры
grades.oc_2 = 3;
grades.oc_3 = 5;
cout << "Размер структуры grades равен " << sizeof(grades) << " байт(а)" << endl;
cout << "Размер элемента структуры grades.oc_1 равен " << sizeof(grades.oc_1) << " байт(а)" << '\n' << endl;
cout << "Введите первую оценку: " << endl; // ввод элементов структуры с клавиатуры
cin >> grades_student_1.oc_1;
cout << "Введите вторую оценку: " << endl;
cin >> grades_student_1.oc_2;
cout << "Введите третью оценку: " << endl;
cin >> grades_student_1.oc_3;
grades_student_1.sred = static_cast<double>(grades_student_1.oc_1 + grades_student_1.oc_2 + grades_student_1.oc_3) / 3;
//вычисление среднего арифметического трех оценок с помощью приведения типов
cout << "Средний балл студента равен: " << grades_student_1.sred << endl; //вывод элемента структуры
cout << "Размер структуры, упорядоченной по размеру типа равен " << sizeof(Data_1) << " байт(а)" << endl;
cout << "Размер структуры, неупорядоченной по размеру типа равен " << sizeof(Data_2) << " байт(а)" << endl;
cout << "Параметр выравнивания типа char равен " << alignof(char) << endl;
cout << "Параметр выравнивания типа short равен " << alignof(short) << endl;
cout << "Параметр выравнивания типа float равен " << alignof(float) << endl;
system("pause");
return 0;
}
Рисунок 8 – Результат работы программы, демонстрирующей параметры выравнивания различных типов данных
Итак, в программе создаются две структуры: Data_1 и Data_2, которые состоят из одних и тех же элементов, но расположенных внутри структуры по-разному. На количество памяти, занимаемое структурой, влияет расположение типов данных внутри структуры. Располагая данные внутри структуры, необходимо учитывать такое свойство данных, как параметр выравнивания. Параметр выравнивания определяет, в каких ячейках памяти могут хранится те или иные данные. Например, параметр выравнивания, равный четырем, говорит о том, что данные могут хранится в ячейках, чей порядковый номер кратен четырем:0,4,8,12, и т.д.
Структуры будут занимать разное количество памяти, таким образом, в первой структуре, которая занимает меньше места, данные хранятся так: тип данных short занимает нулевой и первый байт, тип данных char занимает второй байт, тип данных float занимает с четвертого по седьмой байты. Таким образом, вся структура занимает в памяти 8 байт.
Вторая же структура неупорядочена: тип данных short занимает нулевой и первый байт, тип данных float занимает с четвертого по седьмой байты, тип данных char занимает восьмой байт. Но параметр выравнивания структруры будет равен четырем, соответственно, у нас останется еще три байта (с девятого по одиннадцатый), которые не будут содержать никаких данных, но при этом будут занимать место в памяти. Поэтому вторая структура будет занимать 12 байт в памяти.
Задание 5.
Создадим программу, в которой определим сложный тип данных – объединение, внутри которого используется несколько встроенных типов. Создадим переменную данного типа и реализуем заполнение её полей, выводя информацию о значении всех полей объединения. Также определим размер объединения с помощью оператора sizeof():
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
system("chcp 1251");
system("cls");
union Union{ short a; double b; long c;};
Union data;
data.a = 2;
cout << "Первый элемент объединения равен " << data.a << endl;
data.b = 5.23;
cout << "Второй элемент объединения равен " << data.b << endl;
data.c = -3;
cout << "Первый элемент объединения равен " << data.a << endl;
cout << "Второй элемент объединения равен " << data.b << endl;
cout << "Третий элемент объединения равен " << data.c << endl;
cout << "Объединение Union занимает в памяти " << sizeof(Union) << " байт(а)" << endl;
system("pause");
return 0;
}
Рисунок 9 – Результат работы программы, демонстрирующей работу с объединениями.
Объединение Union в памяти будет занимать такое же количество памяти, сколько занимает его наибольший по размеру элемент – 8 байт. При этом элементы объединения занимают в памяти одно и то же место, поэтому их нельзя использовать одновременно.
Дополнительное задание 1.
Для программы, созданной в задании 2, допишем программный код, демонстрирующий применение инструкции range based for для вывода каждого элемента массива mas:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
int mas[12] = {0, 1, 2, 3, 4}; //зададим массив размером в 12 символов, явно инициализируем первые 5 символов
int i;
system("chcp 1251");
system("cls");
for (i = 0; i < 12; i++)
{
mas[i] += 2;
}
for (int el : mas)
{
cout << el << endl; //вывод всех элементов массива с помощью цикла range based for
}
while(true)
{
cout << "Введите индекс элемента массива(для выхода введите z): " << endl;
cin >>i;
if (getchar() == 'z') // выход из цикла по вводу в консоль символа z
{
break;
}
if (i >= 0 && i < 12) //проверка индекса массива на корректность
{
cout << "Значение элемента массива с индексом " << i << " равно " << mas[i] << endl;
}
else
{
cout << "Ошибка! Индекс элемента массива задан некорректно!" << endl;
}
}
system("pause");
return 0;
}
Рисунок 10 – Результат работы программы, демонстрирующий применение инструкции range based for
Дополнительное задание 2.
Допишем для программы, созданной в задании 4, пример, показывающий инициализацию полей структуры прямо в структуре:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
system("chcp 1251");
system("cls");
struct Grades {int oc_1; int oc_2; int oc_3; float sred;}; // структура, содержащая три оценки студента(целые числа)
// и их среднее арифметическое(вещественное число)
struct Data_1 {short a; char b; float c;}; // структура, упорядоченная по размеру типа данных
struct Data_2 {short a; float b; char c;}; // структура, неупорядоченная по размеру типа данных
struct Grades_1 {int oc_1 = 2; int oc_2 = 3; int oc_3 = 5; float sred = static_cast<float>(oc_1 + oc_2 + oc_3) / 3;};
Data_1 data_1;
Data_2 data_2;
Grades grades;
Grades grades_student_1;
Grades_1 grades_1;
grades.oc_1 = 2; // явная инициализация элементов структуры
grades.oc_2 = 3;
grades.oc_3 = 5;
cout << "Размер структуры grades равен " << sizeof(grades) << " байт(а)" << endl;
cout << "Размер элемента структуры grades.oc_1 равен " << sizeof(grades.oc_1) << " байт(а)" << '\n' << endl;
cout << "Введите первую оценку: " << endl; // ввод элементов структуры с клавиатуры
cin >> grades_student_1.oc_1;
cout << "Введите вторую оценку: " << endl;
cin >> grades_student_1.oc_2;
cout << "Введите третью оценку: " << endl;
cin >> grades_student_1.oc_3;
grades_student_1.sred = static_cast<float>(grades_student_1.oc_1 + grades_student_1.oc_2 + grades_student_1.oc_3) / 3;
//вычисление среднего арифметического трех оценок с помощью приведения типов
cout << "Средний балл студента равен: " << grades_student_1.sred << endl; //вывод элемента структуры
cout << "Размер структуры, упорядоченной по размеру типа равен " << sizeof(Data_1) << " байт(а)" << endl;
cout << "Размер структуры, неупорядоченной по размеру типа равен " << sizeof(Data_2) << " байт(а)" << endl;
cout << "Параметр выравнивания данных типа char равен " << alignof(char) << endl;
cout << "Параметр выравнивания данных типа short равен " << alignof(short) << endl;
cout << "Параметр выравнивания данных типа float равен " << alignof(float) << endl;
cout << "Параметр выравнивания структуры Data_1 равен " << alignof(Data_1) << endl;
cout << "Параметр выравнивания структуры Data_2 равен " << alignof(Data_2) << endl;
cout << "Значения полей структуры, инициализированных прямо в структуре равны: " << endl;
cout << grades_1.oc_1 << endl;
cout << grades_1.oc_2 << endl;
cout << grades_1.oc_3 << endl;
cout << grades_1.sred << endl;
system("pause");
return 0;
}
Рисунок 11 – Результат работы программы, демонстрирующей пример явной инициализации полей структуры прямо в этой структуре
Дополнительное задание 3.
Перепишем программу, созданную в задании 4, так, чтобы использовать в ней пример с созданием массива структур и дальнейшим перебором внутри него с помощью цикла range based for. Для удобства работы с полями структуры будем использовать структурные привязки:
#include <stdio.h>
#include <iostream>
using namespace std;
int main()
{
system("chcp 1251");
system("cls");
float max = 0;
struct Grades {char surname [20]; int oc_1; int oc_2; int oc_3; float sred = static_cast<float>(oc_1 + oc_2 + oc_3) / 3 ;}; // структура, содержащая фамилию студента, его три оценки (целые числа)
// и их среднее арифметическое(вещественное число)
Grades grades_mas [3]; // создание массива из трех структур типа Grades
grades_mas[0] = {"Иванов", 2, 3, 5}; // явная инициализация структур в массиве
grades_mas[1] = {"Петров", 4, 2, 5};
grades_mas[2] = {"Сидоров", 4, 4, 5};
for (auto i : grades_mas)
{
auto [sname, oc1, oc2, oc3, sr] = i; // использование структурных привязок для массива структур grades_mas
cout << "Первая оценка студента c фамилией " << sname << " равна " << oc1 << endl;
cout << "Вторая оценка студента c фамилией " << sname << " равна " << oc2 << endl;
cout << "Третья оценка студента c фамилией " << sname << " равна " << oc3 << endl;
cout << "Средний балл студента с фамилией " << sname << " равен " << sr << endl;
if (sr > max)
{
max = sr;
}
}
cout << "Наибольший средний балл равен: " << max << endl;
system("pause");
return 0;
}
Рисунок 12 – Результат работы программы, демонстрирующей применение массива структур, перебора по нему с помощью цикла range based for и структурных привязок
Выводы:
В данной лабораторной работе были изучены составные типы данных, такие как перечисления, массивы (одномерные и двухмерные), структуры, объединения.
Каждому из элементов перечисления по умолчанию присваивается целочисленное значение в зависимости от его позиции в списке перечисления. По умолчанию, первому элементу присваивается значение 0, а каждому следующему – на 1 больше, чем предыдущему. Перечисления удобно использовать, например, в тех случаях, когда переменные создаваемого типа могут принимать заранее известное конечное (и, как правило, небольшое) множество значений, и для удобочитаемости кода.
Массивы представляют собой объединение нескольких элементов одного типа. Неинициализированные элементы массива принимают значение 0, если массив глобальный и неопределенное значение, если массив локальный. Массивы могут быть одно- и двухмерными. В случае, если массив двухмерный, он представляет собой таблицу m х n, где m – число строк, а n – число столбцов. Массивы удобно использовать в случае, если у нас есть большое количество данных одного типа.
Структура, в отличии от массива, является набором элементов разных типов. Соответственно, структуры удобно использовать в том случае, когда у нас есть большое количество упорядоченных данных разных типов. На количество памяти, занимаемое структурой, влияет расположение типов данных внутри структуры. Располагая данные внутри структуры, необходимо учитывать такое свойство данных, как параметр выравнивания. Параметр выравнивания определяет, в каких ячейках памяти могут хранится те или иные данные.
Объединения отличаются от структур тем, что все его поля располагаются по одному и тому же адресу, соответственно, в памяти объединение занимает меньше места. Это удобно, когда у нас есть ограничение по памяти и нет необходимости одновременного вывода нескольких полей объединения.
Также в данной лабораторной работе были изучены некоторые возможности языка С++, которые появились в последних его редакциях. Например, цикл range based for, который упрощает работу со всеми элементами массива. Помимо этого, была изучена возможность инициализации полей структуры прямо в самой структуре и структурные привязки, укорачивающие код и упрощающие синтаксис при работе с массивами структур.