
- •1. Порядок выполнения работы
- •2. Предмашинная подготовка задачи
- •2.1. Алфавит
- •2.2. Простейшие конструкции
- •2.2.1. Ключевые слова
- •2.2.2. Переменные
- •2.2.4. Вызов функций
- •2.3. Выражения
- •2.3.1. Арифметические операции
- •2.4. Операторы
- •2.5.1. Комментарии
- •2.5.2. Директивы препроцессора
- •2.5.3. Глобальные переменные
- •2.5.4. Тело программы.
2.4. Операторы
Выполняемая часть программы на любом алгоритмическом языке состоит из операторов, которые определяют элементарные шаги и логику реализованного алгоритма. Операторы языка С++ делятся на три группы:
операторы-выражения, получающиеся из произвольных выражений добавлением точки с запятой, как описано ранее;
пустые операторы и блоки;
операторы, начинающиеся с ключевого слова.
Блок – составной оператор, имеющий вид последовательности операторов, заключённой в фигурные скобки :
{ оператор1; оператор2; … }
Наличие в языке блока значительно расширяет возможности синтаксических конструкций: везде, где синтаксис позволяет использовать оператор, допустимо использование и блока операторов.
Специальным случаем оператора служит пустой оператор. Она представляется символом "точка с запятой", перед которым нет никакого выражения или не завершённого разделителем (;) оператора. Пустой оператор не предусматривает выполнения никаких действий. Он используется там, где синтаксис языка требует присутствия оператора, а по смыслу программы никакие действия не должны выполняться (например, в качестве тела цикла, когда все циклически выполняемые действия определены в заголовке цикла). Другое его применение связано с необходимостью в ряде случаев помечать пустое действие, например для реализации перехода к концу блока операторов.
2.4.1. Ввод и вывод в С/С++
В языке С/С++ отсутствуют стандартные операторы ввода-вывода. Организация ввода и вывода данных в языке С/С++ может быть реализована с помощью функций библиотеки стандартного ввода-вывода, объявление которых содержится в заголовочном файле stdiо.h, подключаемом к основной программе с помощью директивы include.
Наряду с библиотечными функциями язык С++ содержит дополнительный набор объектно-ориентированных средств ввода-вывода.
Рассмотрим сначала функции библиотеки стандартного ввода-вывода.
Функция ввода scanf()
Структура обращения к функции scanf():
scanf("строка форматирования", АП1[, АП2,…,АПn]);
где scanf – имя функции;
" строка форматирования" - список спецификаторов
вводимых данных (полей),
оформленный в виде
символьной строки;
АП1,…,АПn - список адресов переменных, которым
присваиваются значения вводимых
данных;
,…, - разделители аргументов функции;
[ ] – признак необязательности содержимого
; - признак оператора.
Функция scanf() сканирует (откуда и её название) поля из стандартного ввода (по умолчанию — клавиатуры) и форматирует каждое поле в соответствии со спецификатором формата, переданном в строке форматирования. Для каждого поля должен существовать спецификатор формата и адрес переменной, предназначенной для размещения результата преобразования поля в соответствии с заданным спецификатором формата. Функция может прекратить сканирование поля до достижения конца поля (символа-заполнителя) или прекратить сканирование полей вообще. В случае успеха scanf() возвращает число успешно просканированных, преобразованных и сохранённых входных полей. В это число не входят не сохранённые поля. Если ни одно поле не было сохранено, функция возвращает 0.
Строка форматирования представляет собой символьную строку, которая содержит объекты трёх типов:
символы-заполнители;
символы, отличные от символов-заполнителей;
спецификаторы формата.
Символы-заполнители – это пробел, символ табуляции
(\t) и перевод строки (\n). Эти символы считываются из форматной строки, но не сохраняются.
Символы, отличные от символов-заполнителей – это все остальные символы, за исключением знака процента (%). Эти символы так же считываются, но не сохраняются.
Спецификаторы формата направляют процесс сканирования, считывания и преобразования символов из входного поля в переменные, заданные своими адресами. Каждому спецификатору формата должен соответствовать адрес переменной. Если спецификаторов формата больше, чем переменных, результат непредсказуем. Наоборот, если имеется больше переменных, чем спецификаторов формата, они игнорируются.
Спецификаторы формата имеют следующий вид:
% [*] [ширина] [F |4 N] [h | l | L] символ_типа
Каждый спецификатор формата начинается с символа процента (%).
После знака процента идут следующие знаки в указанном в табл. 6 порядке.
Таблица 6
Компонент |
Обязательный или нет |
Назначение |
* |
Нет |
Символ подавления присвоения переменной значения следующего поля. Текущее поле сканируется, но не сохраняется в переменной. Предполагается, что аргумент, соответствующий спецификатору формата, содержащему звёздочку, имеет тип, указанный символом типа преобразования (type_char), который идёт за звёздочкой. |
ширина |
Нет |
Спецификатор ширины поля. Задаёт максимальное число считываемых символов. Функция может прочесть меньше символов, если в потоке ввода встретится символ-заполнитель. |
F | N |
Нет |
Модификатор величины указателя. Переопределяет величину по умолчанию аргумента задающего адрес: N – near pointer F – far pointer |
h | l | L |
Нет |
Модификатор типа аргумента. Переопределяет тип по умолчанию аргумента, задающего адрес: h = short int l =long int, если type_char задаёт преобразование в целое l=double, если type_char задаёт преобразование в тип с плавающей точкой L=long double (верно только для преобразования в тип с плавающей точкой) |
символ_типа |
Да |
Символ типа (преобразования) |
Возможные значения символа типа приведены в табл. 7.
Таблица 7
Тип данных |
Ожидаемый ввод |
Тип вводимой переменной |
d |
Десятичное целое |
Целая обычной точности (int). Если указан модификатор типа аргумента h, то вводимая переменная имеет тип короткое целое (short int). Если указан модификатор типа аргумента h, то вводимая переменная имеет тип длинное целое (long) |
D |
Десятичное целое |
Длинное целое (long) |
E,e |
Число с плавающей точкой |
Вещественное обычной точности. Если указан модификатор типа l, то вводимая переменная имеет тип double. Если указан модификатор типа L, то вводимая переменная имеет тип long double. |
f |
Число с фиксированной точкой |
Вещественное обычной точности. Если указан модификатор типа l, то вводимая переменная имеет тип double. |
о |
Восьмеричное целое |
Восьмеричное целое обычной точности (int) |
О |
Восьмеричное целое |
Длинное восьмеричное целое (long) |
i |
Десятичное, восьмеричное или шестнадцатиричное целое |
Целое обычной точности (int) |
I |
Десятичное, восьмеричное или шестнадцатиричное целое |
Длинное целое (long) |
u |
Беззнаковое десятичное целое |
Беззнаковое десятичное целое обычной точности (int) |
U |
Беззнаковое десятичное целое |
Беззнаковое длинное десятичное целое (unsigned long) |
х |
Шестнадцатиричное целое |
Шестнадцатиричное целое обычной точности (int) |
Х |
Шестнадцатиричное целое |
Шестнадцатиричное длинное целое (long) |
s |
Символьная строка |
Символьная строка (char arg[]) |
c |
Символ |
Одиночный символ |
Кроме того, в качестве спецификаторов формата можно задать совокупность символов, заключённых в квадратные скобки. Соответствующий ему аргумент должен указывать на массив символов. Эти квадратные скобки определяют совокупность символов поиска. Если первым символом в квадратных скобках является каре (^), то условие соответствия инвертируется: во входном потоке ищутся символы, не соответствующие указанным в квадратных скобках.
Например,
%[abcd] - поиск во входном поле любого из символов a, b, c, d.
%[^abcd] - поиск во входном поле любого из символов, за исключением a, b, c, d.
Вы также можете указать диапазон поиска, задав символы через тире в качестве совокупности символов поиска.
Например,
%[0-9] – поиск во входном потоке любых десятичных цифр.
%[0-9A-Za-z] – поиск во входном потоке любых десятичных цифр и букв.
Сканирование прекращается, если очередной символ не попадает в совокупность символов поиска.
Функция может прекратить сканирование какого-то поля ещё до достижения его естественного конца (символа-заполнителя) или даже прекратить сканирование совсем. В частности, это происходит, когда в поле ввода появляется символ, не соответствующий по типу заданному преобразованию в спецификаторе формата. В этом случае результат может оказаться непредсказуем.
Адреса вводимых переменных. Любой объект программы (в том числе и переменные) занимает в памяти определённую область. Местоположение объекта в памяти определяется его адресом. Доступ к содержимому переменной осуществляется с использованием её идентификатора (имени). Для того, чтобы узнать адрес конкретной переменной, необходимо использовать унарную операцию взятия адреса. При этом перед именем переменной ставится знак амперсанда (&). Таким образом, адрес переменной имеет вид:
&имя,
где & – символ операции взятия адреса.
имя – идентификатор переменной, для которой
формируется адрес.
Например, для переменных a, x2, summa адресами будут &a, &x2, &summa.
Примечание. Для символьных строк адресом является имя символьной строки.
Примером вызова scanf() может служить следующий фрагмент кода:
int i, res;
float fp;
char c, s[81];
res=scanf("%d%f%c%s",&i, &f, &c, s);
printf("\n\n Количество полей ввода равно %d \n",res);
printf("Результат:\n %d %f %c %s\n", i, f, c, s);
При вводе исходных данных с клавиатуры:
1234 1234.5678 F string
программа выведет на экран монитора:
Количество полей ввода равно 4
Результат:
1234 1234.5678 F string
Функция вывода на экран монитора printf().
Структура обращения к функции printf():
printf(" управляющая строка", [АВ1,…,АВn]);
где printf – имя функции;
" управляющая строка" – список спецификаторов
выводимых данных (полей),
оформленный в виде
символьной строки;
АВ1,…,АВn – список арифметических выражений,
значения которых выводятся на дисплей
(в простейшем случае список может
содержать только имена выводимых
переменных);
,…, - разделители аргументов функции;
[ ] – признак необязательности содержимого
; - признак оператора.
Функция printf() позволяет осуществлять форматированный вывод в стандартный поток вывода stdout (по умолчанию – дисплей). Функция принимает последовательность аргументов, применяя к каждому аргументу спецификатор формата, который содержится в управляющей строке. Если аргументов меньше, чем спецификаторов формата, результат непредсказуем. С другой стороны, если аргументов больше, чем спецификаторов формата, лишние аргументы просто игнорируются. В случае успеха функция возвращает число выведенных байтов, в случае ошибки – значение EOF.
Управляющая строка в функции printf() определяет то, как эта функция будет преобразовывать, форматировать и выводить свои аргументы. Она представляет собой символьную строку, которая содержит два типа объектов:
простые символы, которые копируются в выходной поток;
спецификаторы формата, которые применяются к аргументам (арифметическим выражениям), выбираемым из списка аргументов.
Спецификаторы формата имеют следующий вид:
%[флаги] [поле][.точность][F | N | h | l | L] символ типа
Каждый спецификатор формата начинается с символа процента (%), после которого идут спецификаторы в порядке, указанном в табл. 8.
Таблица 8
Компонент |
Обязательный или нет |
Назначение |
флаги |
Нет |
Флаговые символы. Управляют выравниванием, знаком числа, десятичной точкой, конечными нулями, префиксами для восьмеричных и шестнадцатиричных чисел |
поле |
Нет |
Спецификатор ширины поля. Указывает минимальное число выводимых символов (дополняемое в случае необходимости пробелами или нулями) |
точность |
Нет |
Спецификатор точности. Указывает максимальное число выводимых символов; для целых чисел – минимальное число выводимых цифр |
F | N | h | l | L |
Нет |
Модификатор размера. Переопределяет размер аргумента по умолчанию |
символ типа |
Да |
Символ типа преобразования |
Флаговые символы (флажки) могут появляться в любом порядке и комбинации. Таблицы флажков и их смысл приведены в табл. 9.
Таблица 9
Флажок |
Назначение |
- |
Выровнять вывод по левому краю поля. |
0 |
Заполнить свободные позиции нулями вместо пробелов. |
+ |
Всегда выводить знак числа. |
пробел |
Вывести пробел на месте знака, если число положительное. |
# |
Вывести 0 перед восьмеричным или Ох перед шестнадцатеричным значением. |
Замечание: Флажок «плюс» (+) имеет преимущество перед флажком «пробел» (' '), если они заданы оба.
Спецификатор ширины поля устанавливает минимальную ширину поля для выводимого значения. Ширина задаётся одним из двух способов:
непосредственно с помощью десятичного числа;
косвенно, с помощью символа звёздочки (*).
Если вы используете в качестве спецификатора ширины звёздочку, следующий аргумент в списке аргументов (который должен быть целым числом) задаёт не выводимое значение, а минимальную ширину поля для вывода. Если ширина поля вывода не указана или мала, это не вызывает усечения значения до ширины поля. Вместо этого поле расширяется до нужного размера, чтобы вместить результат преобразования значения. Спецификаторы ширины и их влияние на вывод перечислены в табл. 10
Таблица 10
Спецификатор ширины |
Влияние на вывод |
N |
По крайней мере N символов выводятся. Если выводимое значение имеет менее чем N символов, вывод дополняется пробелами (справа, если указан флажок минус (-), слева – в противном случае). |
0n |
Выводится, по меньшей мере, n символов. Если выводимое значение имеет меньше чем n символов, оно дополняется слева нулями. |
* |
Список аргументов предоставляет спецификатор ширины, который должен предшествовать реально выводимому аргументу. |
Спецификатор точности функции printf() устанавливает максимальное число выводимых символов или минимальное число выводимых цифр для целых чисел. Этот спецификатор всегда начинается с точки, чтобы отделить его от предыдущего спецификатора ширины. Как и спецификатор ширины, он задаётся одним из двух способов:
непосредственно, с помощью десятичного числа;
косвенно, с помощью символа звёздочки (*).
Если вы используете звёздочку в качестве спецификатора точности, то следующий аргумент в списке аргументов (который должен быть целым числом) задаёт точность. Если вы задаёте звёздочки в качестве спецификаторов ширины и точности, то вслед за ними в списке аргументов должен идти спецификатор ширины, затем спецификатор точности, а за ними – само выводимое значение.
Спецификатор типа преобразования задаёт преобразование типа выводимого аргумента. Возможные значения символа типа преобразования и их назначение приведены в табл. 11. Информация в этой таблице основывается на предположении, что спецификатор формата не содержит ни флажков, ни спецификатора ширины, ни спецификатора точности, ни модификатора размера входного значения.
Таблица 11
Символ типа преобразования |
Ожидаемый ввод |
Формат вывода |
d |
Целое число |
Десятичное целое со знаком. |
i |
Целое число |
Десятичное целое со знаком. |
o |
Целое число |
Восьмеричное целое без знака. |
u |
Целое число |
Десятичное целое без знака. |
x |
Целое число |
Шестнадцатеричное целое без знака (причём, для 16-ричных цифр используются символы a,b.c,d,e,f). |
X |
Целое число |
Шестнадцатеричное целое без знака (причём, для 16-ричных цифр используются символы A,B.C,D,E,F). |
f |
Число с плавающей точкой |
Число с плавающей точкой в виде [-]dddd.dddd |
e |
Число с плавающей точкой |
Число с плавающей точкой в виде [-]d.dddd или [-]d.dddde[+/-]ddd |
g |
Число с плавающей точкой |
Число с плавающей точкой в форме е или f с учётом заданного значения и точности. Конечные нули и десятичная точка выводятся, если это необходимо. |
E |
Число с плавающей точкой |
То же, что и для е, но для экспоненты используется символ Е. |
G |
Число с плавающей точкой |
То же, что и g, но для экспоненты используется символ Е, если используется формат е. |
c |
Символ |
Один символ. |
s |
Указатель на строку |
Выводит символы до тех пор, пока не встретится 0-символ или не будет достигнута заданная точность. |
% |
Никакой |
Выводит символ процента (%). |
Модификаторы размера определяют, как функция printf() интерпретирует следующий входной аргумент. Возможные значения модификатора размера и их действие представлены в табл. 12.
Таблица 12
Модификатор размера |
Символ типа преобразования |
Приписываемый входному аргументу тип |
H |
D i o u x X |
short int |
L |
d i o u x X |
long int |
L |
e E f g G |
double |
L |
e E f g G |
long double |
h |
c C |
Однобайтовый символ |
l |
c C |
Широкий символ |
h |
s S |
Строка однобайтовых символов |
l |
s S |
Строка широких символов |
/* Демонстрация форматирования вывода на дисплей
функцией printf(). * /
double p = 27182.81828;
int j = 255;
char s[] = "Нажмите любую клавишу...";
// Вывести 4 цифры; вывести обязательный знак:
printf("Проверка формата для целых чисел: %13.4d %4-8d\n",
j, j);
// Вывести по левому краю со знаком; заполнить нулями:
printf("Продолжение проверки формата для целых чисел: "
"%-+13d % 08d\n", j, j);
printf("Проверка восьмеричных и шестнадцатиричных: "
"%#13o %#8.6x\n", j, j);
printf("\nПроверка e и f преобразований: %13.7e %8.2f\n",
p, p) ;
printf("\n%s", s); // Вывести строку подсказки
getch() ;
Операции помещения и извлечения из потока
Как уже отмечалось, язык С++, наряду со стандартными функциями, включает в себя библиотеку объектно-ориентированных средств управления вводом-выводом. Библиотека обеспечивает программиста механизмами для извлечения данных из потоков и для помещения данных в потоки. Каждый из потоков (за исключением строковых) ассоциируется при помощи операционной системы с определённым внешним устройством. При обмене с потоком используется вспомогательный участок памяти, называемый буфером потока. При вводе данных они вначале помещаются в буфер и только затем передаются выполняемой программе. При выводе – данные заполняют буфер перед передачей внешнему устройству. Работу, связанную с заполнением и очисткой буфера операционная система выполняет без явного участия программиста, поэтому поток в прикладной программе можно рассматривать как последовательность байтов, независящую от конкретных устройств, с которыми ведётся обмен данными.
В зависимости от реализуемого направления передачи данных потоки делятся на три группы:
входные, из которых читается информация;
выходные, в которые вводятся данные;
двунаправленные, допускающие как чтение, так и запись.
В соответствии с особенностями обслуживаемого устройства потоки принято делить на следующие группы:
стандартные, для передачи данных от клавиатуры и к дисплею;
файловые, при размещении данных на внешнем носителе (например, диске);
строковые, позволяющие размещать данные потока в памяти (символьный массив или строка) и пользоваться при этом всеми средствами, предоставляемыми библиотекой потоков (например, форматный ввод-вывод данных).
Ограничимся рассмотрением стандартных потоков. Библиотека реализует обслуживание стандартных потоков путём определения в заголовочном файле iostream (он должен быть подключён директивой к основной программе) четырёх специальных объектов:
сin – объект, связанный со стандартным буферизованным входным потоком (по умолчанию – клавиатура);
cout – объект, связанный со стандартным буферизованным выходным потоком (по умолчанию – дисплей);
cerr – объект, связанный со стандартным небуферизованным выходным потоком (по умолчанию – дисплей), в который направляются сообщения об ошибках;
clog – объект, связанный со стандартным буферизованным выходным потоком (по умолчанию – дисплей), в который с буферизацией направляются сообщения об ошибках.
Установленную по умолчанию связь стандартных потоков с клавиатурой и дисплеем программист может по своему усмотрению разорвать, перенаправив ввод-вывод данных, например, в файловый поток.
Операция помещения в поток
Вывод в поток выполняется с помощью операции вставки (в поток), которая является перегруженной5 операцией сдвига влево <<. Левым её операндом является объект потока вывода (cout, cerr или clog). Правым её операндом может являться любая переменная, арифметическое выражение или символьная строка. Например, инструкция
cout << "Введите исходные данные \n";
приводит к выводу в предопределённый поток cout (на дисплей) строки
Введите исходные данные
Операция << возвращает ссылку на объект, для которого она вызвана. Это позволяет строить цепочки вызовов операций вставки в поток, которые выполняются слева направо:
int i=5;
double d=2.08;
cout << "i = " << i << ", d = " << d;
Эта инструкция приведёт к выводу на экран следующей строки:
i = 5, d = 2.08
Данные форматируются в соответствии с правилами, принятыми по умолчанию для функции printf(), если они не изменены путём установки различных флагов форматирования.
Операция извлечения из потока
Для ввода информации из потока используется операция извлечения, которой является перегруженная операция сдвига вправо >>. Левым операндом является объект входного потока cin. Это позволяет строить цепочки инструкций извлечения из потока, выполняемых слева направо. Правым операндом может быть любая переменная или символьная строка. Например,
int i;
double d;
cin >> i >> d;
Последняя инструкция приводит к тому, что считывает сначала переменную целого типа i, а затем – вещественную d.
Форматирование потока
Для управления форматированием библиотека ввода-вывода предусматривает три вида средств: форматирующие функции, флаги и манипуляторы.
Здесь ограничимся рассмотрением только форматирующих функций. Их всего три: width(), precision() и fill().
По умолчанию при выводе любого значения оно занимает столько позиций, сколько символов выводится. Функция width() позволяет задать минимальную ширину поля для вывода значения. При вводе она задаёт максимальное число читаемых символов. Если выводимое значение имеет меньше символов, чем заданная ширина поля, то оно дополняется символами-заполнителями до заданной ширины (по умолчанию - пробелами). Однако если выводимое значение имеет больше символов, чем ширина отведённого ему поля, то поле будет расширено до нужного размера. Функция задаёт ширину поля, указанную её аргументом и возвращает предыдущее значение ширины поля. Если аргумент функции не указан, она возвращает текущее значение ширины поля. По умолчанию оно равно нулю, т. е. вывод не дополняется и не обрезается.
Например
int i= width();
Переменная i примет текущее значение ширины поля.
int i= width(10);
Переменная i примет предыдущее значение ширины поля, новое значение ширины будет равно 10.
В некоторых компиляторах после выполнения каждой операции вывода значение ширины поля возвращается к значению, заданному по умолчанию.
Функция precision() позволяет узнать или задать точность (число выводимых цифр после запятой), с которой выводятся числа с плавающей точкой. По умолчанию числа с плавающей точкой выводятся с точностью, равной шести цифрам.
Функция задаёт число выводимых цифр после запятой, указанное её аргументом и возвращает предыдущее значение точности. Если аргумент функции не указан, она возвращает текущее значение точности.
Например
int i= precision();
Переменная i примет текущее значение точности.
int i= precision(3);
Переменная i примет предыдущее точности, новое значение будет равно 3.
Функция fill(). позволяет прочесть или установить символ-заполнитель. По умолчанию в качестве символа-заполнителя используется пробел.
Например
char ch= fill ();
Переменная ch примет текущее значение символа-заполнителя.
char ch = fill ('0');
Переменная ch примет предыдущее значение символа-заполнителя, и установит в качестве нового символа 0.
2.5. Структура С/С++ программы
Любая С/С++ программа физически представляет собой исходный модуль, состоящий из заголовка программы и её тела (рис. 1).
Рис. 1 Структура программы на языке С/С++
Заголовок – начальная часть программы, предназначенная для выполнения некоторых вспомогательных операций.
Заголовок содержит последовательность следующих элементов (рис. 2).
Рис. 2. Структура заголовка программы на языке С/С++