Главная страница
Навигация по странице:

  • Рекомендации по работе с векторами

  • 4.4 Минимизация области видимости переменных

  • 4.5 Разделение программы на независимые cpp-файлы и их подключение с помощью заголовочных h-файлов

  • 5 Рекомендации по разработке алгоритмов работы программы

  • Важно

  • Название и обозначение на схеме Функция

  • Наименование Обозначение на схеме Функция

  • Методические указания к выполнению курсовой работы по дисциплине «Основы конструирования программ». 1_Меженная_ОКП_Курсовое_проектирование_Пособие. Курсовое проектирование


    Скачать 2.04 Mb.
    НазваниеКурсовое проектирование
    АнкорМетодические указания к выполнению курсовой работы по дисциплине «Основы конструирования программ
    Дата10.05.2023
    Размер2.04 Mb.
    Формат файлаpdf
    Имя файла1_Меженная_ОКП_Курсовое_проектирование_Пособие.pdf
    ТипРеферат
    #1118858
    страница3 из 6
    1   2   3   4   5   6
    Рекомендации по работе с динамически создаваемыми массивами:
    1. Для динамического создания массива необходимо запрашивать память в процессе выполнения программы. В контексте курсовой работы объем запрашива- емой памяти соответствует количеству структур в файле. Рекомендуется запро- граммировать отдельную функцию (например, getSizeOfFileWithStudents()) для вычисления количества структур в файле перед созданием динамического масси- ва. Примеры кода, реализующие данную задачу, приведены в подразделе 6.2.

    25 int number_of_students = getCountOfStucturesInFile(FILE_OF_DATA); int
    *arr = new int
    [
    number_of_students
    ];
    // динамически создаваемый массив
    2. Для динамически создаваемых массивов необходимо освобождать выде- ленную память в конце программы (в противном случае – утечки памяти): delete
    []arr;
    // освобождение памяти, выделенной под динамический массив
    3. Способ увеличения размера динамически созданного массива (для добав- ления нового элемента в массив): создаем новый массив, переносим туда содер- жимое старого массива, старый массив удаляем. Пример перевыделения памяти с целью увеличения размера динамически созданного массива приведен в подразде- ле 6.3.
    4. Для удаления элемента из динамически созданного массива необходимо сдвинуть все элементы на одну позицию, начиная с номера удаляемого элемента, а затем уменьшить логический размер массива (см. пример кода, реализующего данную задачу, в пояснениях к статически создаваемым массивам).
    В качестве альтернативы массивам выступают векторы из стандартной биб- лиотеки шаблонов. Векторы безопаснее и удобнее, чем массив, но в общем случае медленнее с точки зрения производительности.
    Рекомендации по работе с векторами:
    1. Для полноценной работы с векторами необходимо подключить следующие библиотеки:
    #include

    #include

    #include

    2. Для минимизации операций перевыделения памяти для вектора при считы- вании информации из файла рекомендуется после объявления вектора зарезерви- ровать для него память. При этом целесообразно отталкиваться от количества структур в читаемом файле. Наиболее удобно запрограммировать отдельную функцию (например, getCountOfStucturesInFile(
    string file_path
    )) для вычисления количества структур в файле, примеры кода, реализующие данную задачу, приве- дены в подразделе 6.2. Тогда: vector <
    Student
    > vector_of_students;
    /* резервируем память на getSizeOfFileWithStudents() элементов, но ничем не за- полняем: */
    vector_of_students.reserve(getCountOfStucturesInFile(FILE_OF_DATA));

    26 3. Передача вектора в функцию осуществляется либо по значению, либо по ссылке (например, если в функции происходят изменения вектора). Размер векто- ра при этом в функцию передавать не нужно (он доступен внутри функции по- средством библиотечного метода size()). Примеры: void showStudents(
    vector
    <
    Student
    > vec_of_students
    );
    // вывод массива на экран void delStudent(
    vector
    <
    Student
    > &
    vec_of_students
    );
    // удаление элемента массива
    4. Добавление элемента в конец вектора осуществляется посредством биб- лиотечного метода push_back: void readFileStudents(
    vector
    <
    Student
    > &
    vec_of_students
    )
    { ifstream fin(FILE_OF_STUDENTS, ios
    ::in); if
    (!fin.is_open()) cout
    <<
    "Файл не существует!"
    ; else
    {
    Student student_temp; while
    (!fin.eof())
    { fin
    >>
    student_temp.surname
    >>
    student_temp.name
    >>
    student_temp.age; vec_of_students
    .push_back(student_temp);
    }
    } fin.close();
    }
    5. Удаление элемента из вектора, расположенного по индексу index_for_delete, осуществляется посредством библиотечного метода erase (при этом необходимо с помощью итератора begin() выполнить позиционирование в начало вектора, а далее осуществить сдвиг на требуемое число позиций): vec_of_students
    .erase(
    vec_of_students
    .begin()
    +
    index_for_delete);
    6. Для доступа к элементу вектора используется метод at: void writeFileStudents(
    vector
    <
    Student
    > vec_of_students
    )

    27
    { ofstream fout(FILE_OF_STUDENTS, ios
    ::out); for
    (
    int i = 0; i < vec_of_students
    .size(); i++)
    { fout
    <<
    vec_of_students
    .at(i).surname
    <<
    " "
    <<
    vec_of_students
    .at(i).name
    <<
    " "
    <<
    vec_of_students
    .at(i).age; if
    (i < vec_of_students
    .size() - 1) fout
    <<
    endl;
    } fout.close();
    }
    7. Сортировку вектора можно выполнить с помощью метода sort из библиоте- ки algorithm, при этом требуется создать дополнительную функцию-компаратор, определяющую, по какому полю и в каком порядке (по возрастанию/по убыва- нию) будет выполнена сортировка: void sortStudentsBySurname(
    vector
    <
    Student
    > &
    vec_of_students
    )
    // сортировка
    { sort(
    vec_of_students
    .begin(), vec_of_students
    .end(), mySortBySurname);
    } bool mySortBySurname(
    Student student_a
    ,
    Student student_b
    )
    // функция-компаратор
    { return student_a
    .surname
    <
    student_b
    .surname;
    // по алфавиту: от а до я
    }
    4.4 Минимизация области видимости переменных
    Областью видимости называют фрагмент программы, в котором переменная известна и может быть использована. В C++ переменная может иметь область ви- димости, соответствующую фрагменту кода, заключенному в фигурные скобки, в котором переменная объявлена и используется (локальная переменная) или всей программе (глобальная переменная; объявляется вне блоков описания функций).
    Важно: минимизировать область видимости переменной, сделав ее как можно более локальной.

    28
    Несмотря на то, что глобальные переменные облегчают доступ к ним, так как не нужно беспокоиться о списках параметров и правилах области видимости, удобство доступа к глобальным переменным не может компенсировать связанную с этим опасность. Так программу, в которой каждый метод может вызвать любую переменную в любой момент времени, сложнее понять, чем код, основанный на грамотно организованных методах. Сделав данные глобальными, вы не сможете ограничиться пониманием работы одного метода: вы должны будете понимать ра- боту всех других методов, которые вместе с ним используют те же глобальные данные. Подобные программы сложно читать, сложно отлаживать и сложно изме- нять. В то время как локальная область видимости способствует интеллектуальной управляемости: чем больше информации скрыто, тем меньше нужно удерживать в уме в каждый конкретный момент времени и тем ниже вероятность того, что раз- работчик допустит ошибку, забыв одну из многих деталей, о которых нужно было помнить.
    Важно: выбирать локальную область видимости для массивов/векторов.
    Глобальные переменные имеют два главных недостатка: функции, обра- щающиеся к глобальным данным, не знают о том, что другие функции также обращаются к этим данным; или же функции знают об этом, но не могут контролировать, что именно другие функции делают с глобальны- ми данными.
    4.5 Разделение программы на независимые cpp-файлы и их подключение
    с помощью заголовочных h-файлов
    Следует выносить код логически независимых модулей в отдельные cpp- файлы и подключать их с помощью заголовочных h-файлов (рисунок 4.4).
    Рисунок 4.4 – Способы объявления функций в С++

    29
    Разделение исходного кода программы на несколько файлов становится не- обходимым по ряду причин:
    1. Обеспечение удобства работы с небольшими по объему фрагментами кода, локализованными в отдельных файлах.
    2. Разделение программы на логически завершенные модули, которые реша- ют конкретные подзадачи.
    3. Разделение программы на физически независимые модули с целью повтор- ного использования этих модулей в других программах.
    4. Разделение интерфейса и реализации.
    Последний принцип (разделение интерфейса и реализации) требует особого пояснения. Отдельный модуль состоит из двух файлов: заголовочного h-файла
    (интерфейс) и cpp-файла реализации. Для удобства h-файл и cpp-файл называют одинаково; имя должно соответствовать смысловой нагрузке данного модуля.
    Заголовочный файл подключается в одноименный с ним cpp-файл с реализа- цией программной логики модуля, а также в файл, который будет осуществлять вызов функций данного модуля (например, в файл с запускающей функцией main()). В этом смысле заголовочный файл представляет собой связующее звено между файлом, который задействует логику модуля, и файлом, собственно реали- зующим эту логику. Подклчение заголовочного файла производится посредством директивы препроцессора include, например:
    #include "validation.h"
    Сам по себе заголовочный файл не является единицей компиляции: на этапе обработки исходного кода препроцессором директива #include "validation.h" заме- няется текстом из файла validation.h.
    Заголовочный файл может содержать:

    директивы препроцессора;

    глобальные константы;

    описание типов пользователя;

    прототипы функций.
    Заголовочный файл не должен содержать описание функций!
    Заголовочный файл должен иметь механизм защиты от повторного включе- ния. Защита от повторного включения реализуется директивой препроцессора:
    #pragma once
    Файл реализации содержит описание функций. Следует отметить, что при не- совпадении сигнатуры функции в прототипе (h-файл) и в определении (cpp-файл) компилятор выдаст ошибку. Также файл реализации может содержать объявления.
    Объявления, сделанные в файле реализации, будут лексически локальны для этого

    30 файла, т. е. будут действовать только для этой единицы компиляции. При этом в файле реализации не должно быть объявлений, дублирующих объявления в соот- ветствующем заголовочном файле.
    В файле реализации должна быть директива включения соответствующего заголовочного файла.
    Далее на рисунках 4.5–4.10 приведены примеры выделения в программе неза- висимого модуля, выполняющего проверку вводимых данных на корректность, и его подключения к файлу main.cpp. Данный модуль состоит из заголовочного файла validation.h и файла реализации validation.cpp.
    Рисунок 4.5 – Добавление в проект заголовочного файла
    Рисунок 4.6 – Создание заголовочного файла validation.h

    31
    Рисунок 4.7 – Структура проекта с запускающим файлом main.cpp, а также модулем validation, состоящим из заголовочного файла validation.h и файла реализации validation.cpp
    Рисунок 4.8 – Пример программной реализации файла main.cpp

    32
    Рисунок 4.9 – Пример программной реализации файла validation.h
    Рисунок 4.10 – Пример программной реализации файла validation.cpp

    33
    5 Рекомендации по разработке алгоритмов работы программы
    Алгоритм – набор инструкций, описывающих порядок действий исполнителя для достижения некоторого результата.В самом упрощенном виде разработку простейшей программы можно представить в виде схемы: анализ задачи → разра- ботка (обдумывание) алгоритма ее решения → программирование (реализация ал- горитма с использованием конкретного алгоритмического языка программирова- ния).Разработать алгоритм решения задачи означает разбить задачу на последова- тельно выполняемые шаги. При этом должны быть четко указаны как содержание каждого шага, так и порядок выполнения шагов.
    В блок-схеме алгоритма отдельные шаги изображаются в виде блоков раз- личной формы, соединенных между собой линиями, указывающими направление последовательности. Правила оформления алгоритмов регламентируются ГОСТ
    19.701-90 Схемы алгоритмов, программ, данных и систем. Условные обозначения и правила выполнения.
    В таблице 5.1 приведены основные символы блок-схем алгоритмов и коммен- тарии по их применению.
    Важно: при начертании элементов необходимо придерживаться строгих размеров, определяемых двумя значениями a и b. Значение a выбирается из ряда 15, 20, 25, ... мм, b рассчитывается из соотношения 2a = 3b.
    Минимальное количество текста, необходимого для понимания функции символа, следует помещать внутри данного символа. Если объем текста внутри символа превышает его размеры, следует использовать символ комментария.
    В таблице 5.2 приведены обозначения соединений между символами блок- схем алгоритмов. Соединения между символами показываются линиями и носят название потоков. Направление потока слева направо и сверху вниз считается стандартным, стрелки в таких потоках не указываются. В случаях если поток име- ет направление, отличное от стандартного (справа налево или снизу вверх), при- менение стрелок обязательно. Стрелки выполняются с развалов в 60°.
    Важно: чтобы линии в схемах подходили к центру символа сверху, а
    исходили снизу. Исключениями из этого правила являются символы со- единитель, терминатор (с альтернативным сценарием программы), реше- ние и подготовка, допускающие иные направления входных и/или вы- ходных потоков.
    Важно: пересечения линий следует избегать, так как это существенно затрудняет восприятие алгоритма.

    34
    Таблица 5.1 – Символы блок-схем алгоритмов
    Название и обозначение на схеме
    Функция
    Терминатор
    Выход во внешнюю среду и вход из внеш- ней среды (начало или конец программы).
    На практике имеют смысл следующие описания терминаторов: начало/конец, за- пуск/остановка, ошибка (подразумевает завершение алгоритма с ошибкой), исклю- чение (подразумевает генерацию про- граммного исключения), наимнование действия
    (например, имя функ- ции/метода), возврат (подразумевает воз- врат из функции/метода в основную про- грамму каких-либо данных)
    Данные
    Ввод или вывод данных
    Процесс
    Обработка данных любого вида (выполне- ние определенной операции или группы операций, приводящее к изменению зна- чения, формы или размещения информа- ции). Например, инициализация перемен- ной, арифметические действия над данны- ми и др.
    Предопределенный процесс
    Отображение процесса, состоящего из ша- гов программы, которые определены в другом месте. Используется для вызова функции/метода.
    Внутри блока записывается имя вызывае- мой функции или метода

    35
    Продолжение таблицы 5.1
    Название и обозначение на схеме
    Функция
    Решение
    Отображение условия на алгоритме. Вход в элемент обозначается линией, входящей в верхнюю вершину элемента, выходы – ли- ниями, выходящими из оставшихся вершин и сопровождающимися соответствующими значениями условий.
    Если выходов больше трех (например, в switch-case), то их следует показывать од- ной линией, выходящей из нижней верши- ны элемента, которая затем разветвляется в соответствующее число линий
    Границы цикла
    Отображение границ цикла.
    Обе части символа имеют один и тот же идентификатор.
    Условия для инициализации, приращения, завершения помещаются внутри символа в начале или в конце в зависимости от распо- ложения операции, проверяющей условие.
    Символ используется для циклов do-while, while, for
    Подготовка
    Подготовительные операции для счетных циклов (циклов for)
    Соединитель
    Указание связи между прерванными лини- ями схемы (например, разделение блок- схемы, не помещающейся на листе). Соот- ветствующие символы-соединители долж- ны содержать одно и то же уникальное обо- значение (цифра или буква)

    36
    Продолжение таблицы 5.1
    Название и обозначение на схеме
    Функция
    Комментарий
    Добавление пояснительных записей. Пунк- тирные линии в комментарии связаны с со- ответствующим символом или группой символов (при этом группа выделяется за- мкнутой пунктирной линией). Текст ком- ментария помещается около ограничиваю- щей его по всей высоте скобки.
    Комментарий также используется, когда объем текста, помещаемого внутри некоего символа, превышает его размер.
    Комментарии используют с терминаторами для описания входных аргументов функ- ции/метода
    Таблица 5.2 – Соединения между символами блок-схемы алгоритма
    Наименование
    Обозначение
    на схеме
    Функция
    Линии потока
    Указание направления линии потока:

    без стрелки, если линия направлена слева направо или сверху вниз;

    со стрелкой в остальных случаях
    Излом линии под углом 90°
    Изменение направления потока
    Пересечение линий потока
    Пересечение двух несвязанных потоков
    следует избегать!
    Слияние двух линий потока
    Слияние двух линий потока, каждая из которых направлена к одному и тому же символу на схеме
    На рисунках 5.1–5.3 приведены примеры, поясняющие использование раз- личных графических символов на блок-схемах алгоритмов.

    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


    написать администратору сайта