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

Кашина_СП_ЛБ9

.docx
Скачиваний:
0
Добавлен:
22.09.2026
Размер:
701 Кб
Скачать

Министерство науки и высшего образования Российской Федерации Федеральное государственное бюджетное образовательное учреждение высшего образования

«Владимирский государственный университет

имени Александра Григорьевича и Николая Григорьевича Столетовых» (ВлГУ)

Колледж инновационных технологий и предпринимательства

КАФЕДРА ФИЗИКИ И ПРИКЛАДНОЙ МАТЕМАТИКИ

Лабораторная работа № 9

по дисциплине «Системное программирование»

на тему: «Обработка исключений»

Выполнил

студент группы ИПсп-123

Кашина Д. А.

Принял

Красильщикова В. В.

Владимир, 2026

Цель работы: освоение возможностей языка C++ по обработке исключительных ситуаций.

Задание:

4. Описать в заголовочном файле person.h тип структуры Person для хранения данных о человеке (фамилия, имя, возраст, пол). Этот файл подключать в обеих программах лабораторной работы.

Написать программу для ввода списка людей и сохранения его в файл.

a. В главной функции создать одномерный массив People структур Person. Размер массива вводит пользователь. Заполнить массив в диалоговом режиме.

b. Описать функцию save(), получающую в качестве параметров массив людей и имя файла. Функция должна сохранять список людей в указанный файл. Формат файла выбрать самостоятельно. Функция ничего не возвращает.

c. Вызвать функцию save() в главной функции, передав туда заполненный массив людей и имя файла, вводимое пользователем.

Написать программу для чтения списка людей из файла и сортировки этого списка.

a. Описать функцию load(), получающую в качестве параметра имя файла и возвращающую массив структур Person.

b. Описать функцию sort(), получающую в качестве параметра массив структур Person и сортирующую его по сочетанию двух свойств: фамилия+имя. Сортировка должна менять не локальную копию массива, а массив в области видимости функции, вызвавшей функцию sort(). Функция sort() ничего не возвращает.

c. В главной функции с использованием функций load() и sort() организовать чтение массива людей из файла и сортировку. Вывести результат.

В обеих программах предусмотреть генерацию (оператор throw) и обработку (оператор try) исключительных ситуаций, связанных с событиями различных типов:

a. ошибки работы с файлами (использовать try);

b. выход за диапазон допустимых значений (использовать throw и try).

Ход работы:

1 задание

Заголовочный файл

#ifndef PERSON_H

#define PERSON_H

#include <string>

using namespace std;

struct Person {

string lastName;

string firstName;

int age;

char gender; // 'M' - мужской, 'F' - женский

};

#endif // PERSON_H

Код программы:

#include <iostream>

#include <fstream>

#include <string>

#include <clocale>

#include <cctype>

#include <windows.h>

#include <limits>

#include "person.h"

using namespace std;

// Функция для проверки, состоит ли строка только из букв (включая русские)

bool isOnlyLetters(const string& str) {

if (str.empty()) return false;

// Проверяем, что в строке нет пробелов и других разделителей

for (char c : str) {

if (isspace(static_cast<unsigned char>(c))) {

return false; // Запрещаем пробелы внутри строки

}

}

for (char c : str) {

unsigned char uc = static_cast<unsigned char>(c);

// Русские буквы в CP1251: А-Я (192-223), а-я (224-255), Ё (168), ё (184)

bool isRussian = (uc >= 192 && uc <= 255) || uc == 168 || uc == 184;

// Английские буквы

bool isEnglish = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');

// Дефис (только не в начале и не в конце, но это проверим позже)

bool isHyphen = (c == '-');

if (!isRussian && !isEnglish && !isHyphen) {

return false;

}

}

// Проверка, что дефис не в начале и не в конце

if (str[0] == '-' || str[str.length() - 1] == '-') {

return false;

}

// Проверка, что нет двух дефисов подряд

for (size_t i = 0; i < str.length() - 1; ++i) {

if (str[i] == '-' && str[i + 1] == '-') {

return false;

}

}

return true;

}

// Новая функция для проверки имени (разрешены пробелы и дефисы)

bool isValidName(const string& str) {

if (str.empty()) return false;

for (char c : str) {

unsigned char uc = static_cast<unsigned char>(c);

// Русские буквы в CP1251

bool isRussian = (uc >= 192 && uc <= 255) || uc == 168 || uc == 184;

// Английские буквы

bool isEnglish = (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z');

// Пробел (разрешен в имени)

bool isSpace = (c == ' ');

// Дефис

bool isHyphen = (c == '-');

if (!isRussian && !isEnglish && !isSpace && !isHyphen) {

return false;

}

}

// Проверка, что дефис не в начале и не в конце (если есть дефис)

if (str[0] == '-' || str[str.length() - 1] == '-') {

return false;

}

// Проверка, что пробел не в начале и не в конце

if (str[0] == ' ' || str[str.length() - 1] == ' ') {

return false;

}

// Проверка, что нет двух дефисов подряд

for (size_t i = 0; i < str.length() - 1; ++i) {

if (str[i] == '-' && str[i + 1] == '-') {

return false;

}

}

// Проверка, что нет двух пробелов подряд

for (size_t i = 0; i < str.length() - 1; ++i) {

if (str[i] == ' ' && str[i + 1] == ' ') {

return false;

}

}

return true;

}

// Функция для проверки, состоит ли строка только из цифр

bool isOnlyDigits(const string& str) {

if (str.empty()) return false;

// Проверяем, что в строке нет пробелов

for (char c : str) {

if (isspace(static_cast<unsigned char>(c))) {

return false;

}

}

for (char c : str) {

if (!isdigit(static_cast<unsigned char>(c))) {

return false;

}

}

return true;

}

// Очистка буфера ввода

void clearInputBuffer() {

cin.clear();

cin.ignore(10000, '\n');

}

// Функция для безопасного ввода целого числа (одно число, без лишних символов)

int getValidInt(const string& prompt, int minVal, int maxVal) {

string input;

int value;

while (true) {

cout << prompt;

// Считываем всю строку целиком

getline(cin, input);

// Удаляем пробелы в начале и конце

size_t start = input.find_first_not_of(" \t");

if (start == string::npos) {

cout << "Ошибка: Введите число!" << endl;

continue;

}

size_t end = input.find_last_not_of(" \t");

input = input.substr(start, end - start + 1);

// Проверяем, нет ли пробелов внутри строки

if (input.find(' ') != string::npos || input.find('\t') != string::npos) {

cout << "Ошибка: Введите только одно число, без пробелов!" << endl;

continue;

}

// Проверяем, состоит ли строка только из цифр

if (!isOnlyDigits(input)) {

cout << "Ошибка: Введите только цифры!" << endl;

continue;

}

// Преобразуем строку в число (может быть очень большим)

try {

value = stoi(input);

}

catch (const out_of_range&) {

cout << "Ошибка: Число слишком большое!" << endl;

continue;

}

// Проверяем диапазон

if (value < minVal || value > maxVal) {

cout << "Ошибка: Значение должно быть в диапазоне от "

<< minVal << " до " << maxVal << "!" << endl;

continue;

}

break;

}

return value;

}

// Функция для безопасного ввода фамилии (только буквы, дефис, без пробелов)

string getValidSurname(const string& prompt) {

string input;

while (true) {

cout << prompt;

// Считываем всю строку целиком

getline(cin, input);

// Удаляем пробелы в начале и конце

size_t start = input.find_first_not_of(" \t");

if (start == string::npos) {

cout << "Ошибка: Введите фамилию!" << endl;

continue;

}

size_t end = input.find_last_not_of(" \t");

input = input.substr(start, end - start + 1);

// Проверяем, нет ли пробелов внутри строки (фамилия не может содержать пробелы)

if (input.find(' ') != string::npos || input.find('\t') != string::npos) {

cout << "Ошибка: Фамилия не должна содержать пробелов!" << endl;

cout << " Введите одно слово (например: Иванов или Петров-Водкин)" << endl;

continue;

}

// Проверяем, состоит ли строка только из букв и дефиса

if (!isOnlyLetters(input)) {

cout << "Ошибка: Фамилия должна содержать только буквы и дефис!" << endl;

cout << " Разрешены: русские буквы, английские буквы, дефис" << endl;

continue;

}

break;

}

return input;

}

// Функция для безопасного ввода имени (разрешены пробелы и дефисы)

string getValidName(const string& prompt) {

string input;

while (true) {

cout << prompt;

// Считываем всю строку целиком

getline(cin, input);

// Удаляем пробелы в начале и конце

size_t start = input.find_first_not_of(" \t");

if (start == string::npos) {

cout << "Ошибка: Введите имя!" << endl;

continue;

}

size_t end = input.find_last_not_of(" \t");

input = input.substr(start, end - start + 1);

// Проверяем, состоит ли строка только из букв, пробелов и дефисов

if (!isValidName(input)) {

cout << "Ошибка: Имя должно содержать только буквы, пробелы и дефис!" << endl;

cout << " Разрешены: русские буквы, английские буквы, пробел, дефис" << endl;

cout << " Примеры: Анна, Анна-Мария, Анна Павловна" << endl;

continue;

}

break;

}

return input;

}

// Функция для безопасного ввода пола

char getValidGender() {

string input;

char gender;

while (true) {

cout << "Введите пол (М/Ж или M/F): ";

// Считываем всю строку целиком

getline(cin, input);

// Удаляем пробелы

size_t start = input.find_first_not_of(" \t");

if (start == string::npos) {

cout << "Ошибка: Введите пол!" << endl;

continue;

}

size_t end = input.find_last_not_of(" \t");

input = input.substr(start, end - start + 1);

// Проверяем, что введен один символ

if (input.length() != 1) {

cout << "Ошибка: Введите один символ!" << endl;

continue;

}

gender = toupper(static_cast<unsigned char>(input[0]));

// Проверяем, что символ является допустимым

if (gender == 'М' || gender == 'M' || gender == 'Ж' || gender == 'F') {

if (gender == 'M') gender = 'М';

if (gender == 'F') gender = 'Ж';

break;

}

else {

cout << "Ошибка: Пол должен быть 'М' или 'Ж' (или M/F)!" << endl;

}

}

return gender;

}

// Функция для получения имени файла с автоматическим добавлением .txt

string getValidFilename() {

string filename;

while (true) {

cout << "Введите имя файла для сохранения (без расширения): ";

getline(cin, filename);

// Удаляем пробелы в начале и конце

size_t start = filename.find_first_not_of(" \t");

if (start == string::npos) {

cout << "Ошибка: Введите имя файла!" << endl;

continue;

}

size_t end = filename.find_last_not_of(" \t");

filename = filename.substr(start, end - start + 1);

// Проверяем, что имя файла не пустое

if (filename.empty()) {

cout << "Ошибка: Имя файла не может быть пустым!" << endl;

continue;

}

// Проверяем, что имя файла не содержит недопустимые символы

bool valid = true;

for (char c : filename) {

// Разрешаем буквы, цифры, дефис, подчеркивание, точку (но точку потом заменим)

if (!isalnum(static_cast<unsigned char>(c)) && c != '-' && c != '_' && c != '.') {

valid = false;

break;

}

}

if (!valid) {

cout << "Ошибка: Имя файла может содержать только буквы, цифры, дефис и подчеркивание!" << endl;

continue;

}

break;

}

// Автоматически добавляем расширение .txt

// Если пользователь ввел .txt, то не добавляем повторно

if (filename.length() >= 4 && filename.substr(filename.length() - 4) == ".txt") {

return filename;

}

return filename + ".txt";

}

// Функция для сохранения массива в файл

void save(const Person* people, int size, const string& filename) {

ofstream outFile(filename);

if (!outFile.is_open()) {

throw runtime_error("Невозможно открыть файл для записи: " + filename);

}

for (int i = 0; i < size; ++i) {

outFile << people[i].lastName << "|"

<< people[i].firstName << "|"

<< people[i].age << "|"

<< people[i].gender << endl;

}

outFile.close();

}

int main() {

SetConsoleCP(1251);

SetConsoleOutputCP(1251);

setlocale(LC_ALL, "Russian");

cout << "Выполнила Кашина Д. ИПсп-123 \n";

try {

// Очищаем буфер перед началом работы

clearInputBuffer();

// Ввод количества людей с валидацией

int size = getValidInt("Введите количество людей: ", 1, 1000000);

// Создаем динамический массив

Person* people = new Person[size];

// Заполнение массива

for (int i = 0; i < size; ++i) {

cout << "\n--- Ввод данных для человека " << (i + 1) << " ---" << endl;

people[i].lastName = getValidSurname("Введите фамилию: ");

people[i].firstName = getValidName("Введите имя: ");

people[i].age = getValidInt("Введите возраст (0-150): ", 0, 150);

people[i].gender = getValidGender();

}

// Получаем имя файла с автоматическим добавлением .txt

string filename = getValidFilename();

save(people, size, filename);

cout << "Данные успешно сохранены в файл " << filename << endl;

delete[] people;

}

catch (const out_of_range& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

catch (const runtime_error& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

catch (const exception& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

return 0;

}

Результат работы:

Запись в файле:

Блок-схема

Блок-схема обработки исключений

2 задание:

Код программы:

#include <iostream>

#include <fstream>

#include <string>

#include <algorithm>

#include <clocale>

#include <sstream>

#include <windows.h>

#include "person.h"

using namespace std;

// Функция загрузки массива из файла

Person* load(const string& filename, int& size) {

ifstream inFile(filename);

if (!inFile.is_open()) {

throw runtime_error("Невозможно открыть файл для чтения: " + filename);

}

// Сначала подсчитываем количество строк в файле

size = 0;

string line;

while (getline(inFile, line)) {

if (!line.empty()) {

size++;

}

}

if (size == 0) {

throw runtime_error("Файл пуст");

}

// Возвращаемся в начало файла

inFile.clear();

inFile.seekg(0);

// Выделяем память

Person* people = new Person[size];

// Читаем данные

int index = 0;

while (getline(inFile, line) && index < size) {

if (line.empty()) continue;

stringstream ss(line);

string temp;

// Читаем фамилию

getline(ss, people[index].lastName, '|');

// Читаем имя

getline(ss, people[index].firstName, '|');

// Читаем возраст

getline(ss, temp, '|');

people[index].age = stoi(temp);

// Читаем пол

getline(ss, temp, '|');

people[index].gender = temp[0];

// Проверка допустимых значений

if (people[index].age < 0 || people[index].age > 100) {

delete[] people;

throw out_of_range("Некорректный возраст в файле");

}

if (people[index].gender != 'М' && people[index].gender != 'Ж') {

delete[] people;

throw out_of_range("Некорректный пол в файле");

}

index++;

}

inFile.close();

return people;

}

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

void sort(Person* people, int size) {

for (int i = 0; i < size - 1; ++i) {

for (int j = 0; j < size - i - 1; ++j) {

// Сравниваем по фамилии

if (people[j].lastName > people[j + 1].lastName) {

swap(people[j], people[j + 1]);

}

// Если фамилии одинаковые, сравниваем по имени

else if (people[j].lastName == people[j + 1].lastName &&

people[j].firstName > people[j + 1].firstName) {

swap(people[j], people[j + 1]);

}

}

}

}

// Функция для вывода массива

void printPeople(const Person* people, int size) {

cout << "\n--- Список людей ---" << endl;

for (int i = 0; i < size; ++i) {

cout << (i + 1) << ". "

<< people[i].lastName << " "

<< people[i].firstName << ", "

<< "Возраст: " << people[i].age << ", "

<< "Пол: " << people[i].gender << endl;

}

}

int main() {

SetConsoleCP(1251);

SetConsoleOutputCP(1251);

cout << "Выполнила Кашина Д. ИПсп-123 \n";

try {

string filename;

cout << "Введите имя файла для чтения: ";

cin >> filename;

int size;

Person* people = load(filename, size);

cout << "\nИсходный список:" << endl;

printPeople(people, size);

// Сортируем массив

sort(people, size);

cout << "\nОтсортированный список (по фамилии и имени):" << endl;

printPeople(people, size);

delete[] people;

}

catch (const out_of_range& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

catch (const runtime_error& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

catch (const exception& e) {

cerr << "Ошибка: " << e.what() << endl;

return 1;

}

return 0;

}

Результат работы:

Блок-схема

Вывод: в ходе лабораторной работы были освоены возможности языка C++ по обработке исключительных ситуаций.

Соседние файлы в предмете Системное программирование