Главная страница

конспект. Конспект. Курс лекций по дисциплине процедурное программирование


Скачать 1.95 Mb.
НазваниеКурс лекций по дисциплине процедурное программирование
Анкорконспект
Дата27.12.2021
Размер1.95 Mb.
Формат файлаpdf
Имя файлаКонспект.pdf
ТипКурс лекций
#319290
страница3 из 6
1   2   3   4   5   6

Тема 8. Динамические массивы в C
Когда мы разбирали понятие массива, то при объявлении мы задавали массиву определенный постоянный размер. Возможно, кто-то пробовал делать так:
int n = 10;

int arr[n];
Но, как уже было сказано — при объявлении статического массива, его размером должна являться числовая константа, а не переменная. В большинстве случаев, целесообразно выделять определенное количество памяти для массива, значение которого изначально неизвестно.
Например, необходимо создать динамический массив из N элементов, где значение N задается пользователем. Мы уже учились выделять память для переменных, используя указатели. Выделение памяти для динамического массива имеет аналогичный принцип.
Создание динамического массива
#include
using namespace std;
int main()
{
int num; // размер массива cout << "Enter integer value: "; cin >> num; // получение от пользователя размера массива
int *p_darr = new int[num]; // Выделение памяти для массива
for (int i = 0; i < num; i++) {
// Заполнение массива и вывод значений его элементов p_darr[i] = i; cout << "Value of " << i << " element = " << p_darr[i] << endl;
}
delete [] p_darr; // очистка памяти
return 0;
}
Синтаксис выделения памяти для массива имеет вид
указатель = new тип[размер]
.
В качестве размера массива может выступать любое целое положительное значение.
Задание 1. Объявите указатель на массив типа
double
и
предложите пользователю выбрать его размер. Далее напишите
четыре
функции
: первая должна выделить память для массива,
вторая – заполнить ячейки данными, третья – показать данные
на экран, четвертая – освободить занимаемую
память. Программа должна предлагать пользователю
продолжать работу (создавать новые динамические массивы)
или выйти из программы.
Задание 2. Объявите указатель на массив типа int и выделите
память для 12-ти элементов. Необходимо написать функцию,
которая поменяет значения четных и нечетных ячеек массива.
Например, есть массив из 4-х элементов:

Тема 9. Параметры командной строки в C++
При запуске программы из командной строки, ей можно передавать дополнительные параметры в текстовом виде. Например, следующая команда ping -t 5 google.com
Будет отправлять пакеты на адрес google.com с интервалом в 5 секунд. Здесь мы передали программе ping три параметра: «-t», «5» и «google.com», которые программа интерпретирует как задержку между запросами и адрес хоста для обмена пакетами.
В программе эти параметры из командной строки можно получить через аргументы функции main при использовании функции main в следующей форме:
int main(int argc, char* argv[]) { /* ... */ }
Первый аргумент содержит количество параметров командной строки. Второй аргумент
— это массив строк, содержащий параметры командной строки. Т.е. первый аргумент указывает количество элементов массива во втором аргументе.
Первый элемент массива строк (
argv[0]
) всегда содержит строку, использованную для запуска программы (либо пустую строку). Следующие элементы (от 1 до argc - 1
) содержат параметры командной строки, если они есть. Элемент массива строк argv[argc]
всегда должен содержать 0.
Пример 1
#include
using namespace std;
int main(int argc, char *argv[])
{
for (int i = 0; i < argc; i++) {
// Выводим список аргументов в цикле cout << "Argument " << i << " : " << argv[i] << endl;
}
return 0;
}
Откройте командную строку и запустите оттуда скомпилированную программу.

Для получения числовых данных из входных параметров, можно использовать функции atoi и atof.
Тема 10. Классы в C++
Весь реальный мир состоит из объектов. Города состоят из районов, в каждом районе есть свои названия улиц, на каждой улице находятся жилые дома, которые также состоят из объектов.
Практически любой материальный предмет можно представить в виде совокупности объектов, из которых он состоит. Допустим, что нам нужно написать программу для учета успеваемости студентов. Можно представить группу студентов, как класс языка C++.
Назовем его
Students
Основные понятия
Классы в программировании состоят из свойств и методов. Свойства — это любые данные, которыми можно характеризовать объект класса. В нашем случае, объектом класса является студент, а его свойствами — имя, фамилия, оценки и средний балл.

У каждого студента есть имя — name и фамилия last_name
. Также, у него есть промежуточные оценки за весь семестр. Эти оценки мы будем записывать в целочисленный массив из пяти элементов. После того, как все пять оценок будут проставлены, определим средний балл успеваемости студента за весь семестр — свойство average_ball
Методы — это функции, которые могут выполнять какие-либо действия над данными
(свойствами) класса. Добавим в наш класс функцию calculate_average_ball()
, которая будет определять средний балл успеваемости ученика.

Методы класса — это его функции.

Свойства класса — его переменные.
class Students {
public:
// Функция, считающая средний балл
void calculate_average_ball()
{
int sum = 0; // Сумма всех оценок
for (int i = 0; i < 5; ++i) { sum += scores[i];
}
// считаем среднее арифметическое average_ball = sum / 5.0;
}
// Имя студента std::string name;
// Фамилия std::string last_name;
// Пять промежуточных оценок студента
int scores[5];
private:
// Итоговая оценка за семестр
float average_ball;
};
Функция calculate_average_ball()
просто делит сумму всех промежуточных оценок на их количество.
Модификаторы доступа public и private
Все свойства и методы классов имеют права доступа. По умолчанию, все содержимое класса является доступным для чтения и записи только для него самого. Для того, чтобы разрешить доступ к данным класса извне, используют модификатор доступа public
. Все функции и переменные, которые находятся после модификатора public
, становятся доступными из всех частей программы.
Закрытые данные класса размещаются после модификатора доступа private
. Если отсутствует модификатор public
, то все функции и переменные, по умолчанию являются закрытыми (как в первом примере).
Обычно, приватными делают все свойства класса, а публичными — его методы. Все действия с закрытыми свойствами класса реализуются через его методы. Рассмотрим следующий код.

class Students {
public:
// Установка среднего балла
void set_average_ball(float ball)
{ average_ball = ball;
}
// Получение среднего балла
float get_average_ball()
{
return average_ball;
} std::string name; std::string last_name;
int scores[5];
private:
float average_ball;
};
Мы не можем напрямую обращаться к закрытым данными класса. Работать с этими данными можно только посредством методов этого класса. В примере выше, мы используем функцию get_average_ball()
для получения средней оценки студента, и set_average_ball()
для выставления этой оценки.
Функция set_average_ball()
принимает средний балл в качестве параметра и присваивает его значение закрытой переменной average_ball
. Функция get_average_ball()
просто возвращает значение этой переменной.
Программа учета успеваемости студентов
Создадим программу, которая будет заниматься учетом успеваемости студентов в группе.
Создайте заголовочный файл students.h, в котором будет находиться класс
Students
/* students.h */
#include
class Students {
public:
// Установка имени студента
void set_name(std::string student_name)
{ name = student_name;
}
// Получение имени студента std::string get_name()
{
return name;
}
// Установка фамилии студента
void set_last_name(std::string student_last_name)
{ last_name = student_last_name;
}
// Получение фамилии студента std::string get_last_name()

{
return last_name;
}
// Установка промежуточных оценок
void set_scores(int student_scores[])
{
for (int i = 0; i < 5; ++i) { scores[i] = student_scores[i];
}
}
// Установка среднего балла
void set_average_ball(float ball)
{ average_ball = ball;
}
// Получение среднего балла
float get_average_ball()
{
return average_ball;
}
private:
// Промежуточные оценки
int scores[5];
// Средний балл
float average_ball;
// Имя std::string name;
// Фамилия std::string last_name;
};
Мы добавили в наш класс новые методы, а также сделали приватными все его свойства.
Функция set_name()
сохраняет имя студента в переменной name
, а get_name()
возвращает значение этой переменной. Принцип работы функций set_last_name()
и get_last_name()
аналогичен.
Функция set_scores()
принимает массив с промежуточными оценками и сохраняет их в приватную переменную int scores[5]
Теперь создайте файл main.cpp со следующим содержимым.
/* main.cpp */
#include
#include "students.h"
int main()
{
// Создание объекта класса Student
Students student; std::string name; std::string last_name;
// Ввод имени с клавиатуры std::cout << "Name: "; getline(std::cin, name);

// Ввод фамилии std::cout << "Last name: "; getline(std::cin, last_name);
// Сохранение имени и фамилии в объект класса Students student.set_name(name); student.set_last_name(last_name);
// Оценки
int scores[5];
// Сумма всех оценок
int sum = 0;
// Ввод промежуточных оценок
for (int i = 0; i < 5; ++i) { std::cout << "Score " << i+1 << ": "; std::cin >> scores[i];
// суммирование sum += scores[i];
}
// Сохраняем промежуточные оценки в объект класса Student student.set_scores(scores);
// Считаем средний балл
float average_ball = sum / 5.0;
// Сохраняем средний балл в объект класса Students student.set_average_ball(average_ball);
// Выводим данные по студенту std::cout << "Average ball for " << student.get_name() << " "
<< student.get_last_name() << " is "
<< student.get_average_ball() << std::endl;
return 0;
}
В самом начале программы создается объект класса
Students
. Дело в том, что сам класс является только описанием его объекта. Класс
Students является описанием любого из студентов, у которого есть имя, фамилия и возможность получения оценок.
Объект класса
Students характеризует конкретного студента. Если мы захотим выставить оценки всем ученикам в группе, то будем создавать новый объект для каждого из них.
Использование классов очень хорошо подходит для описания объектов реального мира.
После создания объекта student
, мы вводим с клавиатуры фамилию, имя и промежуточные оценки для конкретного ученика. Пускай это будет Вася Пупкин, у которого есть пять оценок за семестр — две тройки, две четверки и одна пятерка.
Введенные данные мы передаем set-функциям, которые присваивают их закрытым переменным класса. После того, как были введены промежуточные оценки, мы высчитываем средний балл на основе этих оценок, а затем сохраняем это значение в закрытом свойстве average_ball
, с помощью функции set_average_ball()
Скомпилируйте и запустите программу.

Отделение данных от логики
Вынесем реализацию всех методов класса в отдельный файл students.cpp.
/* students.cpp */
#include
#include "students.h"
// Установка имени студента
void Students::set_name(std::string student_name)
{
Students::name = student_name;
}
// Получение имени студента std::string Students::get_name()
{
return Students::name;
}
// Установка фамилии студента
void Students::set_last_name(std::string student_last_name)
{
Students::last_name = student_last_name;
}
// Получение фамилии студента std::string Students::get_last_name()
{
return Students::last_name;
}
// Установка промежуточных оценок
void Students::set_scores(int scores[])
{
for (int i = 0; i < 5; ++i) {
Students::scores[i] = scores[i];
}
}
// Установка среднего балла
void Students::set_average_ball(float ball)
{
Students::average_ball = ball;

}
// Получение среднего балла
float Students::get_average_ball()
{
return Students::average_ball;
}
А в заголовочном файле students.h оставим только прототипы этих методов.
/* students.h */
#pragma once /* Защита от двойного подключения заголовочного файла */
#include
class Students {
public:
// Установка имени студента
void set_name(std::string);
// Получение имени студента std::string get_name();
// Установка фамилии студента
void set_last_name(std::string);
// Получение фамилии студента std::string get_last_name();
// Установка промежуточных оценок
void set_scores(int []);
// Установка среднего балла
void set_average_ball(float);
// Получение среднего балла
float get_average_ball();
private:
// Промежуточные оценки
int scores[5];
// Средний балл
float average_ball;
// Имя std::string name;
// Фамилия std::string last_name;
};
Такой подход называется абстракцией данных — одного из фундаментальных принципов объектно-ориентированного программирования. К примеру, если кто-то другой захочет использовать наш класс в своем коде, ему не обязательно знать, как именно высчитывается средний балл. Он просто будет использовать функцию calculate_average_ball()
из второго примера, не вникая в алгоритм ее работы.
Над крупными проектами обычно работает несколько программистов. Каждый из них занимается написанием определенной части продукта. В таких масштабах кода, одному человеку практически нереально запомнить, как работает каждая из внутренних функций проекта. В нашей программе, мы используем оператор потокового вывода cout
, не задумываясь о том, как он реализован на низком уровне. Кроме того, отделение данных от логики является хорошим тоном программирования.
В начале обучения мы говорили о пространствах имен (namespaces). Каждый класс в C++ использует свое пространство имен. Это сделано для того, чтобы избежать конфликтов
при именовании переменных и функций. В файле students.cpp мы используем оператор принадлежности
::
перед именем каждой функции. Это делается для того, чтобы указать компилятору, что эти функции принадлежат классу
Students
Создание объекта через указатель
При создании объекта, лучше не копировать память для него, а выделять ее в в куче с помощью указателя. И освобождать ее после того, как мы закончили работу с объектом.
Реализуем это в нашей программе, немного изменив содержимое файла main.cpp.
/* main.cpp */
#include
#include "students.h"
int main()
{
// Выделение памяти для объекта Students
Students *student = new Students; std::string name; std::string last_name;
// Ввод имени с клавиатуры std::cout << "Name: "; getline(std::cin, name);
// Ввод фамилии std::cout << "Last name: "; getline(std::cin, last_name);
// Сохранение имени и фамилии в объект класса Students student->set_name(name); student->set_last_name(last_name);
// Оценки
int scores[5];
// Сумма всех оценок
int sum = 0;
// Ввод промежуточных оценок
for (int i = 0; i < 5; ++i) { std::cout << "Score " << i+1 << ": "; std::cin >> scores[i];
// суммирование sum += scores[i];
}
// Сохраняем промежуточные оценки в объект класса Student student->set_scores(scores);
// Считаем средний балл
float average_ball = sum / 5.0;
// Сохраняем средний балл в объект класса Students student->set_average_ball(average_ball);
// Выводим данные по студенту std::cout << "Average ball for " << student->get_name() << " "
<< student->get_last_name() << " is "

<< student->get_average_ball() << std::endl;
// Удаление объекта student из памяти
delete student;
return 0;
}
При создании статического объекта, для доступа к его методам и свойствам, используют операция прямого обращения — «
.
» (символ точки). Если же память для объекта выделяется посредством указателя, то для доступа к его методам и свойствам используется оператор косвенного обращения — «
->
».
Конструктор и деструктор класса
Конструктор класса — это специальная функция, которая автоматически вызывается сразу после создания объекта этого класса. Он не имеет типа возвращаемого значения и должен называться также, как класс, в котором он находится. По умолчанию, заполним двойками массив с промежуточными оценками студента.
class Students {
// Имя студента std::string name;
// Фамилия std::string last_name;
// Пять промежуточных оценок студента
int scores[5];
// Итоговая оценка за семестр
float average_ball;
};
class Students {
public:
// Конструктор класса Students
Students(int default_score)
{
for (int i = 0; i < 5; ++i) { scores[i] = default_score;
}
}
private:
int scores[5];
};
int main()
{
// Передаем двойку в конструктор
Students *student = new Students(2);
return 0;
}
Мы можем исправить двойки, если ученик будет хорошо себя вести, и вовремя сдавать домашние задания. А на «нет» и суда нет :-)

Деструктор класса вызывается при уничтожении объекта. Имя деструктора аналогично имени конструктора, только в начале ставится знак тильды


. Деструктор не имеет входных параметров.
#include
class Students {
public:
// Деструктор
Students()
{ std::cout << "Memory has been cleaned. Good bye." << std::endl;
}
};
int main()
{
Students *student = new Students;
// Уничтожение объекта
delete student;
return 0;
}
1   2   3   4   5   6


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