Структура языка программирования С++

Язык программирования С++ на данный момент является одним из универсальных языков. Многие другие языки, такие как Java, PHP и т.д. используют сходные принципы программирования, кроме того, в отличие от Pascal, данный язык имеет полновесно рабочую и устойчивую систему работы в объектно-ориентированной парадигме и средствами работы с базами данных.

Основу языка программирования С++ составляет структурное представление кода. Приведем пример программы на языке С++, написанный для консоли (для удобства пронумеруем строки программы):

1

/* первая программа */

2

#include <iostream>

#include <cmath>

#include <windows.h>

3

#define Pi 3.141592653

4

using namespace std;

5

double area (double radius);

6

int main()

7

{

8

setlocale(LC_ALL,»Rus»);

SetConsoleCP(1251);

SetConsoleOutputCP(1251);

9

int r, h, v;

10

cout << “\n Введите радиус и высоту цилиндра, разделенные пробелами: “;

11

cin >> r >> h;

12

v = h * area(r);

13

cout << “\n Объем цилиндра радиуса ” << r << “ и высоты ” << h << “ равен ” << v;

14

return 0;

15

}

16

double area (double radius)

17

{

18

return Pi*radius*radius;

19

}

В строке 1 записан комментарий. На языке С++ комментарии к программам можно оформлять двумя способами:

  • с помощью комбинации //, в этом случае комментарий распознается до конца строки;
  • с помощью парных комбинаций /* и */, в данном случае комментарий располагается между данными парами, таким образом можно оформить многострочный комментарий.

Строки 2 определяют подключаемые библиотеки. Библиотеки подключаются с помощью директивы #include. Они служат для подключения функций программе, например библиотека iostream.h служит для обеспечения ввода и вывода текста и значений переменных (например, как в строках 10, 11). Основные библиотеки с их описанием будут описаны ниже. При работе со стандартными библиотеками можно опускать расширение заголовочных файлов, то есть вместо <cmath.h> можно писать просто <cmath>.

В программах часто используют директиву #define, она служит для подстановки в тексте программы символических констант, макросов, которые выглядят как функции, но реализуются подстановкой их текста в текст программы, символов, управляющих условной компиляцией (используются вместе с директивами #ifdef и #ifndef). Так, в строке 4 объявлена константа Pi, которая используется затем в функции. Приведем примеры использования данной директивы:

#define M 1000

#define Alex “Алексей Павлович”

В строке 4 объявляется пространство имен std (using namespace std). Пространство имен является областью определения функций, методов, операторов и применяется для того, чтобы избежать конфликтов имен из разных библиотек. Если пространство имен не определено, требуется описывать его для каждой конкретной используемой функции:

std::cout<< “Введите радиус и высоту цилиндра”

В строке 5 объявляется вспомогательная функция area, вынесение заголовка ее вперед позволяет легче уяснить состав вспомогательных функций и правила их использования. В скобках указан тип переменной, являющейся входным для выполнения данной функции. В приведенном примере такой переменной будет являться radius. Слово double (вещественное число с удвоенной точностью) в начале записи говорит о типе переменной, возвращаемой в результате выполнения функции.

Любая программа на языке С++ должна начинаться с функции с именем main (строка 6). Данное имя является фиксированным, обозначение int (integer – целое), говорит, что данная функция возвращает целочисленное значение. Местом вызова главной функции является среда выполнения или среда операционной системы. В строке 13 стоит возвращаемое значение 0 (return). Данное значение говорит о том, что во время выполнения функции main не было обнаружено ошибок. Возвращаемое значение главной функции не принципиально, главное, чтобы тип данных при инициализации функции соответствовал типу данных, прописанному для операции return. В круглых скобках функции main может находиться список формальных параметров. В данном примере их нет.

После описания данной функции открывается ее тело, которое определяется фигурными скобками (строки 7 и 15). Тело функции представляет собой последовательность операторов. Как правило, в начале тела функции определяются переменные с помощью соответствующих операторов (строка 9). Оператором является законченное предложение, его описание заканчивается точкой с запятой. Операторы объявления переменных начинаются с имени типа, после которого указывается список имен переменных данного типа. Также операторы можно инициализировать непосредственно в тексте до первого применения.

В строках 8 записана функция setlocale. Во многих средах программирования на языке C++ кириллица (русский алфавит) отображается неправильно, поэтому необходима дополнительная настройка под формат Windows-1251. Для этого используется данная функция, подключаемая с помощью библиотеки windows.h. Кроме того, функции SetConsoleCP и SetConsoleOutputCP используются для обеспечения соответственно правильного ввода и вывода кириллических символов. Данные две функции используются в основном в том случае, когда происходит непосредственная работа со строками, но использование setlocale желатульно для всех программ. Единственный разумный альтернативный вариант – составлять программы с выводом на английском языке.

В строке 9 указаны вводимые переменные для программы. Переменные в С++ могут быть введены в любом месте программы до их первого упоминания. Формат ввода позволяет дать переменной начальное значение. Крме того, перед наименованием переменной всегда пишется его тип данных (см. табл. 1.1).

В строке 10 записан стандартный оператор вывода cout библиотеки iostream.h. Операция << (вставка в поток) обеспечивает вывод на экран текстовых записей (выделенных кавычками) или значений переменных. Если требуется вывести их попеременно, необходимо разделять вывод данными знаками (как в строке 13). Оператор \n обеспечивает перевод курсора в новую строку экрана, сам оператор при этом не отображается. В результате выполнения строки 10 на экран будет выведено следующее сообщение:

Введите радиус и высоту цилиндра, разделенные пробелами:

В строке 11 записан стандартный оператор вывода сin библиотеки iostream. Операция >> (извлечение из потока) обеспечивает считывание данных с клавиатуры, их преобразование в соответствии с типом переменной, расположенной справа от операции и присвоение значения:

V = h * area(r);

В строке 12 выполняется присвоение результата переменной V (через оператор «=»), при этом, согласно приоритетам выполнения действий, сначала будет вызвана функция и выполнены команды внутри нее.

В строке 13 с помощью операции cout организован вывод сообщения о результате выполнения программы.

После определения главной функции следует определение вспомогательной функции area() (строки 16-18). Вывод значения, получаемого с помощью данной вспомогательной функции, определяется с помощью оператора return.

Таким образом можно условно разделить написание программы на языке С++ на следующие пункты:

  1. Подключение необходимых библиотек.
  2. Объявление пользовательских констант, вспомогательных функций, классов и типов данных, глобальных переменных.
  3. Заголовок главной функции.
  4. Определение главной функции (объявление локальных переменных и констант, их инициализация, ввод исходных данных, обработка и вывод результата выполнения главной функции).
  5. Определение вспомогательных функций.

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

  • прежде, чем использовать функции, переменные, типы данных, следует объявить их или подключить файлы необходимых библиотек (чтобы сделать их понятными компилятору);
  • чтобы вызов функции мог быть выполнен, функция должна быть определена, то есть должны быть описаны действия, которые она осуществляет;
  • в любой последовательности действий нужно стремиться к следующему: инициализация –> обработка –> возвращение значения.

Основная цель любой программы состоит в обработке данных. Данные различного типа хранятся и обрабатываются по-разному. В любом алгоритмическом языке каждая константа, переменная, результат вычисления выражения или функции должны иметь определенный тип. Тип данных определяет:

  • внутреннее представление данных в памяти компьютера;
  • множество значений, которые могут принимать величины этого типа;
  • операции и функции, которые можно применять к величинам этого типа.

Исходя из этих характеристик, программист выбирает тип каждой величины, используемой в программе для представления реальных объектов. Обязательное описание типа позволяет компилятору производить проверку допустимости различных конструкций программы. От выбора типа величины зависит последовательность машинных команд, построенная компилятором.

Константы, как известно, представляют собой изображение фиксированных числовых, строковых или символьных значений. Они делятся на пять групп:

  • целые;
  • вещественные;
  • перечислимые.

Целые константы вводятся стандартным образом, например, а = 5;

При определении констант компилятор самостоятельно определяет тип данных, например при вводе вещественной константы с = .12 он не только определит ее как вещественное число, но и узнает в записи числа 0.12.

Для ввода перечислимых констант существует служебное слово enum, которое С++ распознает, как группу констант, например

enum {one = 1, two = 2, three = 4, four = 87, five};

даст четыре константы, которые в дальнейшем можно применять в программе. Соответственно, константе one будет соответствовать 1, two = 2, three = 4, four = 87, five = 0. Если же ввести несколько констант без определения их значений, то каждая следующая будет увеличена на единицу, например в результате записи

enum {zero, one, two = 2, three = 3, four, five, six = 6};

константы примут следующие значения:

// zero = 0, one = 1, two = 2, three = 3, four = 4, five = 5, six = 6.

Данный инкремент можно использовать, например, при определении номеров дней недели,

enum {Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday}

соответственно от 0 (Sunday) до 6 (Saturday).

Также, со значениями констант можно производить арифметические операции при их назначении, например

enum {one = 1, seven = one * 7, fourteen = seven * 2};

Алфавит C++ включает:

  • прописные и строчные латинские буквы и знак подчеркивания;
  • арабские цифры от 0 до 9;
  • специальные знаки: {, %, # и т.д.;
  • пробельные символы: пробел, символы табуляции, символы перехода на новую строку.

При написании программы на языке С++ необходимо помнить, что код составляется посредством кодировки UNICODE, что в практическом плане означает главное: переменные типа «А» и «а» будут иметь различный адрес в памяти, то есть, грубо говоря, являться разными переменными.

Все типы языка С++ можно разделить на простые (скалярные), составные (агрегатные) и функциональные. Простые типы могут быть стандартными и определенными программистом. В языке C++ определено шесть стандартных простых типов данных для представления целых, вещественных, символьных и логических величин. На основе этих типов, а также массивов и указателей можно вводить описание собственных простых или структурированных типов. К структурированным типам относятся перечисления, функции, структуры, объединения и классы.

Простые типы делятся на целочисленные типы и типы с плавающей точкой. Для описания стандартных типов определены следующие ключевые слова:

  • int (целый);
  • char (символьный);
  • wchar_t (расширенный символьный);
  • bool (логический);
  • float (вещественный);
  • double (вещественный с двойной точностью).

Существует четыре спецификатора типа, уточняющих внутреннее представление и диапазон значений стандартных типов:

  • short (короткий);
  • long (длинный);
  • signed (со знаком);
  • unsigned (без знака).

Для вещественных типов в таблице 1.1 приведены абсолютные величины минимальных и максимальных значений.

Таблица 1.1 – Простые типы данных

Тип

Диапазон значений

Размер (байт)

bool

true и false

1

signed char

–128 … 127

1

unsigned char

0 … 255

1

signed short int

–32 768 … 32 767

2

unsigned short int

0 … 65 535

2

signed long int

–2 147 483 648 … 2 147 483 647

4

unsigned long int

0 … 4 294 967 295

4

float

3.4e–38 … 3.4e+38

4

double

1.7e–308 … 1.7e+308

8

long double

3.4e–4932 … 3.4e+4932

10

Для того, чтобы узнать размер памяти, выделяемой на переменную можно воспользоваться следующим примером:

// Размеры разных типов данных

#include<iostream>

#include <windows.h>

using namespace std;

int main()

{

setlocale(LC_ALL,»Rus»);

char a=’A’; cout<<«\n Размер sizeof(int) = «<<sizeof(int);

cout<<«\n Размер sizeof(float) = «<<sizeof(float);

cout<<«\nРазмер sizeof(double)=»<<sizeof(double);

cout<<«\n Размер sizeof a = «<<sizeof a;

return 0;

}

С++ для расчетов использует систему подключаемых библиотек. Для того, чтобы, например, ввести или вывести значения переменных, необходимо подключать дополнительную библиотеку. В чистом языке С++, если не использовать подключаемые библиотеки, находится лишь небольшое количество операций. Большинство данных операций приведено в таблице 1.2, они определены в соответствии с их приоритетами.

Таблица 1.2 – Основные операции языка C++.

Операция

Краткое описание

++

увеличение на 1 (инкремент)

– –

уменьшение на 1 (декремент)

sizeof

размер памяти

*

умножение

/

деление

%

остаток от деления

+

сложение

вычитание

<<

сдвиг влево

>>

сдвиг вправо

=

присваивание

*=

умножение с присваиванием

/=

деление с присваиванием

%=

остаток отделения с присваиванием

+=

сложение с присваиванием

–=

вычитание с присваиванием

,

последовательное вычисление

В языке С++ существует два типа инкремента и декремента, префиксный и постфиксный. Синтаксис использования операций инкремента и декремента следующий:

—a; // префиксный декремент

a—; // постфиксный декремент

++a; // префиксный инкремент

a++; // постфиксный инкремент

Когда операция инкремента или декремента ставится перед именем переменной, то такая операция называется соответственно префиксным инкрементом (сокращённо – преинкрементом) или префиксным декрементом (сокращённо – предекрементом). А если операция инкремента или декремента ставится после имени переменной, то такая операция называется соответственно операцией постфиксного инкремента (сокращённо – постинкремент) или постфиксного декремента (сокращённо – постдекремент). При использовании операции преинкремента значение переменной, сначала, увеличивается на 1, а затем используется в выражении. При использовании операции постинкремента значение переменной сначала используется в выражении, а потом увеличивается на 1. При использовании операции предекремента, значение переменной, сначала, уменьшается на 1, а затем используется в выражении. При использовании операции постдекремента, значение переменной, сначала, используется в выражении, а потом уменьшается на 1. Данные операции удобно использовать при работе со счетчиками, массивами или при выводе значений переменных. Например:

int a = 3, b = 5, c = 8, d;

d = a++ — b + c; // выдаст 6

d = ++a – b + c; // выдаст 7

В обоих случаях примера переменная а увеличит свое значение на единицу, только в первом случае это произойдет после выполнения вычисления, а во втором – до вычисления.

Привязка в типу данных для операций в языке С++ весьма условная. Например, если требуется разделить вещественное число, программа при использовании знака деления произведет обычное деление. Если же с помощью того же знака деления разделить целое число, программа выдаст целочисленный результат.

float a = 3.5;

float c = a / 2; // в результате получим c равное 1.75

int b = 5

int d = b / 2; // в результате получим d равное 2

Также в языке С++ широко используются указатели на переменные. Указателем называется некоторое символическое представление адреса ячейки памяти, отведенной для переменной. Например,

&imya

это указатель на переменную imya. Здесь & (знак «амперсанд») – операция получения адреса. Фактический адрес – это число, а символическое представление адреса &name является константой типа «указатель». В языке Си++ также имеются переменные типа указатель. Точно так же, как значением переменной типа char является символ, а значением переменной типа int – целое число, значением переменной типа указатель служит адрес некоторой величины. Если мы дадим указателю имя «per», то сможем написать следующий оператор:

per = &name; /* присваивает адрес name переменной per */

В данном случае говорят, что per – это указатель на переменную name. Различие между двумя формами записи: per и &name в том, что per – это переменная, в то время как &imya – это константа. Для доступа к значению этой переменной можно использовать операцию «косвенной адресации», обозначаемой знаком «*»:

val = *per; // определение значения, на которое указывает per

Последние два оператора, взятые вместе, эквивалентны следующему:

val = imya;

nurs = 22;

tool = &nurs;

col = *tool;

При определении указателей необходимо сообщать, на переменную какого типа ссылается данный указатель. Причина заключается в том, что переменные разных типов занимают различное число ячеек памяти, в то время как для некоторых операций, связанных с указателями, требуется знать объем отведенной памяти:

int *vy; char *pc;

double y;

double *vx, *vy = &y;

Для указателей определены операции сравнения, сложения указателя с целым числом, вычитание двух указателей, а также операция индексирования (операция []). При объявлении указателя может использоваться описатель const, например

const int vc = 20;

const int *pc = &vc; /* Можно инициализировать адресом константы.*/

double *const omega = 0.001; // Указатель – константа

В C++ заведомо существуют библиотеки, реализующие основные функции. Рассмотрим некоторые из них.

Библиотека <stdio> предоставляет возможность ввода / вывода посредством операторов соответственно scanf и printf. Они выполняют форматированный ввод и вывод произвольного количества величин в соответствии со строкой формата format. Строка формата содержит символы, которые при выводе копируются в поток (на экран) или запрашиваются из потока (с клавиатуры) при вводе, и спецификации преобразования, начинающиеся со знака %, которые при вводе и выводе заменяются конкретными величинами. Типы спецификаторов представлены в таблице 1.3.

Таблица 1.3 – Спецификаторы формата данных для printf

Спецификатор

Результат

символ

%d или %i

целое десятичное число

%e

десятичное число в виде x.xx e+xx

%f

десятичное число с плавающей запятой xx.xxxx

%o

восьмеричное число

%s

строка символов

%u

беззнаковое десятичное число

%x

шестнадцатеричное число

%X

шестнадцатеричное число

%%

символ %

%p

указатель

%n

указатель

Например, если имеется переменная x=10.3563 типа float и необходимо вывести её значение с точностью до 3-х цифр после запятой, то надо написать:

printf(«Переменная x = %.3f»,x);

В результате получится:

Переменная x = 10.356

Можно также указать минимальную ширину поля отводимого для печати. Если строка или число больше указанной ширины поля, то строка или число печатается полностью. Например, если написано:

printf(«%5d»,20);

то результат будет следующим:

20

то есть визуально будет произведен отступ на три символа вправо под пустые разряды. Если необходимо, чтобы неиспользованные места поля заполнялись нулями, то нужно поставить перед шириной поля символ 0:

printf(«%05d»,20);

Результат:

00020

Кроме спецификаторов формата данных в управляющей строке могут находиться управляющие символы (см. табл. 1.4). управляющие символы необходимы для управления расположением курсора вывода в файле, консоли или любом другом выводящем объекте.

Таблица 1.4 – Управляющие символы

Символ

Значение

\f

Новая страница, перевод страницы

\n

Новая строка, перевод строки

\r

Возврат каретки

\t

Горизонтальная табуляция

\v

Вертикальная табуляция

Двойная кавычка

\’

Апостроф

\\

Обратная косая черта

\0

Нулевой символ, нулевой байт

\a

Сигнал

\N

Восьмеричная константа

\xN

Шестнадцатеричная константа

\?

Знак вопроса

Рассмотрим следующий пример:

#include <stdio.h>

#include <windows.h>

using namespace std;

int main()

{

setlocale(LC_ALL,»Rus»);

int i;

printf(«Введите целое число\n»);

scanf(«%d», &i);

printf(«Вы ввели число %d, спасибо!», i);

return 0;

}

Первая строка программы, приведённой в примере – директива препроцессора, по которой в текст программы вставляется заголовочный файл <stdio.h>, содержащий описание использованных в программе функций ввода/вывод. Третья строка – описание переменной целого типа с именем i. Функция printf в четвертой строке выводит приглашение «Введите целое число» и переходит на новую строку в соответствии с управляющей последовательностью \n. Функция scanf заносит введенное с клавиатуры целое число в переменную i, а следующий оператор выводит на экран указанную в нем строку, заменив спецификацию преобразования на значение этого числа.

Библиотека <iostream> предоставляет возможность ввода / вывода посредством операторов соответственно cin и cout. Они также выполняют форматированный ввод и вывод произвольного количества величин. В их написании также возможно использование управляющих символов (см. табл. 3). Разница заключается в синтаксисе использования данных операторов. Пример их использования представлен ниже:

#include <iostream>

#include <windows.h>

using namespace std;

int main(){

setlocale(LC_ALL,»Rus»);

int i;

cout << «Введите целое число» << endl;

cin >> i;

cout << «Вы ввели число «<< i << «, спасибо!»;

return 0;

}

Кроме того, в библиотеке iostream существует оператор endl, назначение которого аналогично управляющему символу \n. Так как библиотека потокового ввода /вывода используется достаточно часто, многие используют именно endl.

Библиотека <cmath> реализует большинство математических функций. В ее составе достаточно большое количество математических функций, они приведены в таблице 1.5.

Таблица 1.5 – Операторы библиотеки <cmath>.

Функция

Значение

double cos(double x)

косинус аргумента

double abs(double x)

абсолютное значение аргумента

double exp(double x)

экспоненциальную функцию аргумента

double log(double x)

натуральный логарифм аргумента

double sin(double x)

синус аргумента

double sqrt(double x)

квадратный корень аргумента

double tan(double x)

тангенс аргумента

double acos(double x)

арккосинус аргумента

double asin(double x)

арксинус аргумента

double atan(double x)

арктангенс аргумента

double ceil(double x)

округление до большего целого

double floor(double x)

округление до меньшего целого

double pow(double x, double y)

Число х в степени у

Рассмотрим канонический пример линейной программы. Например, необходимо определить стоимость человека в золотом эквиваленте. Стоимость веса человека необходимо посчитать в соответствии со стоимостью грамма золота.

#include <iostream>

#include <windows.h>

using namespace std;

int main()

{

setlocale(LC_ALL,»Rus»);

float weight; //вес пользователя

float value; //»золотой эквивалент» пользователя

cout<<«\n\tВведите ваш вес в килограммах: «;

cin>> weight;

cout<<«\tВаш вес в граммах равен: «;

cout<<1000*weight;

cout<<«\n\tСтоимость одного грамма золота 245,6 рублей\n»;

value=245.6*weight*1000;

cout<<«\tВаша стоимость в золотом эквиваленте равна: «;

cout<<value<<» рублей»;

return 0;

}

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

Кроме того, при построении программ часто используются уже готовые алгоритмы. Несмотря на то, что данные конструкции являются часто употребимыми, они не входят в набор библиотек. В данном пособии будет разбираться несколько таких случаев. Например, случай, когда число необходимо разделить на цифры разрядов. При варианте трехзначного числа можно обойтись обычной комбинацией из целочисленного деления и делания с остатком:

#include <iostream>

#include <windows.h>

using namespace std;

int main()

{

setlocale(LC_ALL,»Rus»);

int n;

cout << «Введите трехзначное число: «;

cin >> n;

int a,b,c;

c = n % 10;

a = n / 100;

b = (n — a*100 — c)/10;

cout << «В Вашем числе » << a << » сотен, » << b << » десятков, » << c << » единиц»;

return 0;

}

Кроме того, может возникнуть необходимость поменять значения переменных местами. Обычно для этого используется алгоритм с третьей переменной:

int a = 2, b = 3, c;

c = a;

a = b;

b = c;

Таким образом, после выполнения данных строк a станет равно 3, b =2. Но также возможен вариант обмена без использования третьей переменной за счет изначальной суммы двух значений и последовательного отделения от нее имеющихся значений:

int a = 2, b = 3;

a = a + b;

b = a – b;

a = a – b;

В данном случае происходит некоторая экономия памяти за счет избавления от необходимости использования третьей переменной.