Добавлен: 04.12.2023
Просмотров: 107
Скачиваний: 5
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
37
Начало
Конец
Действие 1
Действие 2
A
A
Действие 3
Действие 4
Деление на ноль
Начало
Ввод n, m
m = 0 ?
Возврат n/m
Ошибка
Да
Нет а б
Рисунок 5.1 – Пример использования терминатора и соединителя (а), ввода данных, условия и комментария (б) на блок-схеме алгоритма
Условие
Действие 1
Действие 2
Нет
Да
Условие
Действие 1
Нет
Да а б
Условие
Действие 3
Действие 2
Действие N
Действие 1
Значение 1
Значение 2
Значение 3
Значение N
в
Рисунок 5.2 – Отображение условной конструкции if-else (а), if (б), оператора выбора switch-case (в) на блок-схеме алгоритма
38
Начало а = 1
Цикл i от 1 до n а = a*i
Увеличить i на 1
Цикл i
Вывод а
Конец
Цикл j
Тело цикла
Конец цикла j
Конец цикла i
Цикл i а б
Рисунок 5.3 – Примеры отображения одного цикла (а) и вложенных циклов (б) на блок-схеме алгоритма
39
Далее на рисунках 5.4–5.9 приведены примеры алгоритмов ряда функций для курсовой работы.
Важно: данные примеры носят обучающий характер, не предназначены для копирования в курсовую работу, не являются единственно верным вариантом реализации логики курсовой работы. В частности, данные ал- горитмы могут выглядеть совершенно иначе вследствие авторского под- хода к функциональной декомпозиции задач курсовой работы, а также могут быть расширены за счет дополнительных функциональных воз- можностей, обработки исключительных ситуаций.
Начало systemSettings startSession core endSession
Конец
1 2 3 4 5 6
Предварительные настройки:
подключение русскоязычной локали;
вывод информации о программе:
название, ФИО разработчика
Начало сеанса работы программы:
объявление и резервирование памяти под массивы/векторы; чтение информации из файлов в массивы/векторы
Ядро работы программы:
авторизация; регистрация (если предусмотрена); реализация функционала пользователя или администратора
Завершение сеанса работы программы:
запись информации из массивов/векторов в файлы; очистка памяти (для динамически созданных массивов)
Рисунок 5.4 – Пример алгоритма главной функции main
40 core mainMenu choiceMenuItem
Конец
Ядро работы программы:
входные параметры: массив/вектор аккаунтов,
массив/вектор данных, размеры массивов
Вывод главного меню:
1-авторизация
2-регистрация (если предусмотрена)
0-завершение работы программы
Ввод пункта меню
возвращает item - целое положительное число из диапазона возможных пунктов меню
Бесконечный цикл 1
item logIn
Бесконечный цикл 1
registration
= 0
= 1
= 2
Рисунок 5.5 – Пример алгоритма функции core: основная логика программы
41 logIn authorization
Конец
Вход в систему:
входные параметры: массив/вектор аккаунтов, массив/вектор данных, размеры массивов
Авторизация:
входные параметры: массив/вектор аккаунтов,
размер массива аккаунтов; возвращает role (роль)
Бесконечный цикл 1
role
Бесконечный цикл 1
adminModule
= 0
иное
= 1
userModule
Такой пользователь не найден repeatRequest
Повторить авторизацию?
Запрос
на повтор действия;
возвращает ответ
Нет
Да
Рисунок 5.6 – Пример алгоритма функции logIn: вход в систему
42 authorization
Возврат current_role
Авторизация:
входные параметры: массив/вектор аккаунтов,
размер массива аккаунтов;
возвращает role (роль)
Обнаружено совпадение?
Нет
Да
Сравниваем current_login и current_password с соответствующими полями i-го элемента массива/вектора int current_login;
int current_password;
int current_role =
-
1;
int i = 0
Цикл 1
Пока i < размера массива/вектора и current_role = =
-
1
current_role присваиваем значение роли i-го элемента массива/вектора i = i + 1
Цикл 1
Ввод current_login current_password
Рисунок 5.7 – Пример алгоритма функции authorization: авторизация
43 userModule
Конец
Модуль пользователя:
входные параметры: массив/вектор данных,
размер массива данных item
Бесконечный цикл 1
Бесконечный цикл 1
showUserMenu
Вывод
меню пользователя choiceMenuItem
Ввод пункта меню
возвращает item - целое положительное число из диапазона возможных пунктов меню searchData sortData individualTask showData
= 0
= 1
= 2
= 3
= 4
Рисунок 5.8 – Пример алгоритма функции userModule: функционал пользователя
44 showData
Конец
Вывод данных на экран:
входные параметры: массив/вектор данных,
размер массива данных showTableTitle i = 0; i < размера массива/вектора;
i = i + 1
Вывод i-го элемента массива/вектора
Вывод
названий столбцов таблицы данных
Рисунок 5.9 – Пример алгоритма функции showData: вывод данных на экран
45
6 Рекомендации по программированию курсовой работы
6.1 Типичные ошибки начинающих при написании кода. Способы
отслеживания и устранения ошибок.
Создание exe-файла проекта
Типичные ошибки начинающих при написани кода:
1. Пропуск «;» в конце инструкции или размещение «;» там, где это не нужно.
2. Путаница в количестве открывающихся «{» и закрывающихся «}» скобок
(пишите обе скобки одновременно!).
3. Использование в условных конструкциях знака присвоения «=» вместо «=
=».
4. Ни о чем не говорящие имена переменных и функций.
5. Объявление служебных переменных и попытка их использования без инициализации (без присвоения начального значения).
6. «Магические» числа и строки в коде.
7. Отсутствие освобождения памяти (с помощью оператора delete) после ее ручного выделения (с помощью оператора new).
8. Использование слишком длинных функций, которые в реальности следо- вало бы разбить на несколько функций.
9. Сложная (неочевидная, неоптимальная) логика решения задачи.
10. Аргументация «Но программа же работает!» в ответ на замечания по ло- гике работы программы, «недружественному» интерфейсу и оформлению кода.
Для отслеживания и устранения ошибок рекомендуется использовать сле- дующие подходы в том порядке, в котором они перечислены далее:
1. Построение (сборка) проекта в среде разработки.
2. Отладка в пошаговом режиме.
3. Рефакторинг.
Частая сборка проекта, выполняемая в процессе работы над кодом, позволяет быстро выявлять ошибки компиляции и компоновки, например неверный синтак- сис, несоответствия типов и другое (рисунок 6.1) и своевременно их устранять.
Успешная сборка – это подтверждение правильности синтаксиса кода прило- жения и корректного разрешения всех статических ссылок на библиотеки. Однако успешная сборка не исключает наличие логических ошибок, о которых будут сви- детельстовать неверные результаты работы программы. Логические ошибки мо- гуть быть эффективно локализованы посредством отладки программы, позволяю- щей узнать текущие значения переменных; выяснить, по какому пути выполня- лась программа. Существуют две взаимодополняющие технологии отладки:
1. Пошаговое выполнение программы с остановками на строчках исходного кода (рисунок 6.2).
2. Логирование – вывод текущего состояния программы с помощью располо- женных в критических точках программы операторов вывода.
46
Рисунок 6.1 – Пример обнаружения ошибки сборки проекта
1 – устанавливаем точку остановки, 2 – после запуска программы переходим от точки остановки к следующей инструкции посредством панели инструментов для пошаговой отладки;
3 – отслеживаем значения переменных в процессе отладки
Рисунок 6.2 – Пример отладки программы в пошаговом режиме
47
Помимо синтаксических и логических ошибок собственно качество кода про- граммы зачастую нуждается в улучшении – рефакторинге. Рефакторинг – процесс изменения внутренней структуры программы, не затрагивающий ее внешнего по- ведения и имеющий целью облегчить понимание ее работы. Ни о чем не говоря- щие имена переменных и функций, «магические» числа и строки в коде, исполь- зование слишком длинных функций, сложная (неочевидная, неоптимальная) логи- ка – вот примеры проблем, которые необходимо решить на стадии рефакторинга.
После полного тестирования приложения и рефакторинга целесообразно скомпилировать итоговую release-версию проекта (помимо отладочной debug- версии) – рисунки 6.3, 6.4.
Рисунок 6.3 – Выбор версии проекта для сборки: debug или release
Рисунок 6.4 – Изменение динамического связывания библиотек времени выполнения на статическое связывание
48
Следует отметить, что приложения, созданные с помощью Microsoft Visual
Studio, зависят от Visual С++ Redistibutable и динамически связаны с библиотека- ми MSVCR**.dll (Microsoft C Runtime Library). Для последующих запусков exe- файла на других компьютерах, которые потенциально могут не содержать требуе- мых библиотек (не установлена Microsoft Visual Studio или версия установленной
Microsoft Visual Studio ниже требуемой) перед сборкой итоговой версии необхо- димо изменить динамическое связывание библиотек времени выполнения на ста- тическое связывание. Для этого требуется перейти к свойствам проекта (щелкнув правой кнопкой мыши на имени проекта в Обозревателе решений), а в разделе
C/С++ → Создание кода найти параметр Библиотека времени выполнения. Его необходимо изменить с Многопоточная DLL (/MD) на Многопоточная (/MT) – см. рисунок 6.4.
6.2 Структуры. Запись и чтение из файла
В языке C++ потоки, которые позволяют читать и записывать информацию в файл, являются объектами классов ifstream, ofstream. Они находятся в библиотеке с заголовочным файлом
ifstream: класс, функции которого используются для чтения файлов;
ofstream: класс, функции которого используются для записи файлов.
Название класса эквивалентно типу переменной, поэтому после названия класса объявляется объект, тип которого будет соответствовать классу. Для ини- циализации объектов в конструктор класса необходимо передать параметры: пер- вый параметр – путь к файлу, второй параметр – режим работы с файлом. Кон- станты режима файлов:
ios::in – открыть файл для чтения;
ios::out – открыть файл для записи;
ios::ate – перейти к концу файла после открытия;
ios::app – добавлять к концу файла;
ios::binary – бинарный файл.
Далее приведены два примера записи и чтения в файл.
Первый пример: работа с файлом выполняется в текстовом режиме. В качестве строковых полей структуры используем класс string, структуры объеди- няем в статически создаваемые локальные массивы, запись и чтение выполняем посредством указания всех полей структуры.
49
Приведенный ниже пример ориентирован на статически создаваемые масси- вы, а именно включает целый ряд проверок выхода за пределы зарезервированной под статический массив памяти.
С точки зрения скорости данный вариант работы с файлом уступает второму варианту, однако сам файл содержит информацию в текстовом виде (также при ручной записи в файл информации требуемого формата она впоследствии может быть корректно считана программно).
#include
#include
#include
using namespace std; struct
Student
{ string name; string surname; int age;
};
// Запись в файл (если что-то было в файле, то исходные данные будут удалены):
void writeFileStudents(
Student
*
arr_of_students
, int number_of_students
);
// Добавление в конец файла одной строки:
void writeEndFileStudents(
Student new_student
);
// Чтение из файла в массив:
void readFileStudents(
Student
*
arr_of_students
, int
&
number_of_students
);
// Заполнение массива студентов void generateStudentArray(
Student
*
arr_of_students
, int
&
number_of_students
);
// Добавление студента в массив void addStudentInArray(
Student
*
arr_of_students
, int
&
number_of_students
);
// Удаление студента из массива void delStudentFromArray(
Student
*
arr_of_students
, int
&
number_of_students
);
// Вывод содержимого массива на экран void showStudentArray(
Student
*
arr_of_students
, int number_of_students
); const string
FILE_OF_DATA =
"MyFile.txt"
;
//Путь к файлу const int
RESERVE_SIZE = 100;
//Максимальное количество элементов массива
50 void main()
{ setlocale(
LC_ALL
,
"rus"
);
Student arr_of_students[RESERVE_SIZE]; int number_of_students = 0; generateStudentArray(arr_of_students, number_of_students); writeFileStudents(arr_of_students, number_of_students); addStudentInArray(arr_of_students, number_of_students); showStudentArray(arr_of_students, number_of_students); delStudentFromArray(arr_of_students, number_of_students); showStudentArray(arr_of_students, number_of_students);
Student arr_new_of_students[RESERVE_SIZE];
/* Создаем новый массив исключительно для того, чтобы продемонстрировать корректность чтения данных из файла */
int new_number_of_students = 0; readFileStudents(arr_new_of_students, new_number_of_students); showStudentArray(arr_new_of_students, new_number_of_students); system(
"pause"
);
} void generateStudentArray(
Student
*
arr_of_students
, int
&
number_of_students
)
{ number_of_students
= 2; arr_of_students
[0].name
=
"Alex"
; arr_of_students
[0].surname
=
"Black"
; arr_of_students
[0].age = 20; arr_of_students
[1].name
=
"Ivan"
; arr_of_students
[1].surname
=
"Ivanov"
; arr_of_students
[1].age = 25;
} void addStudentInArray(
Student
*
arr_of_students
, int
&
number_of_students
)
{
51
//добавление студента, если не происходит выход за пределы массива if
(
number_of_students
+ 1 <= RESERVE_SIZE)
{ number_of_students
++; cout
<<
"Введите имя студента: "
; cin
>>
arr_of_students
[
number_of_students
- 1].name; cout
<<
"Введите фамилию студента: "
; cin
>>
arr_of_students
[
number_of_students
- 1].surname; cout
<<
"Введите возраст студента: "
; cin
>>
arr_of_students
[
number_of_students
- 1].age; writeEndFileStudents(
arr_of_students
[
number_of_students
- 1]);
} else cout
<<
"Недостаточно памяти для добавления нового элемента!"
<<
endl;
} void delStudentFromArray(
Student
*
arr_of_students
, int
&
number_of_students
)
{ int number_of_deleted_item; cout
<<
"Введите номер удаляемой записи: "
; cin
>>
number_of_deleted_item;
// пользователь мыслит с 1, но индексы нумеруются с 0
: number_of_deleted_item--; if
(number_of_deleted_item >= 0 && number_of_deleted_item < number_of_students
)
{ for
(
int i = number_of_deleted_item; i < number_of_students
- 1; i++) arr_of_students
[i]
=
arr_of_students
[i + 1]; number_of_students
--; writeFileStudents(
arr_of_students
, number_of_students
);
} else cout
<<
"Введен некорректный номер удалемой записи!"
<<
endl;
} void showStudentArray(
Student
*
arr_of_students
, int number_of_students
)
{ for
(
int i = 0; i<
number_of_students
; i++) cout
<<
arr_of_students
[i].name
<<
" "