Язык программирования C++. Скалярные стандартные типы данных. Основные операторы языка. Учебный практикум к курсу «Практикум на ЭВМ»
.pdfНеобходимо помнить, что для вычисления размера типа переменной имя типа должно быть заключено в круглые скобки. Имя переменной заключать в скобки не обязательно, но ошибки в этом не будет.
double c,f;
printf(“%d ”, sizeof(f)); printf(“%d ”, sizeof c); printf(“%d ”, sizeof(int));
Операции сдвига (<< и >>) применяются к целочисленным операндам. они сдвигают двоичное представление первого операнда влево или вправо на количество двоичных разрядов, заданное вторым операндом. При сдвиге влево (<<) освободившиеся разряды обнуляются. При сдвиге вправо (>>) освободившиеся биты заполняются нулями, если первый операнд беззнакового типа, и знаковым разрядом в противном случае. Операции сдвига не учитывают переполнение и потерю значимости.
Операции отношения (<, <=, >, >=, ==, !=) сравнивают первый операнд со вторым. Операнды могут быть арифметического типа или указателями. Результатом операции является значение true или false (любое значение, не равное нулю, интерпретируется как true). Операции сравнения на равенство и неравенство имеют меньший приоритет, чем остальные операции сравнения.
Поразрядные операции (&, |, ^) применяются только к целочисленным операндам и работают с их двоичными представлениями. Поразрядные операции выполняются над отдельными разрядами (битами) операндов.
При поразрядной конъюнкции (&) бит результата равен 1 только тогда, когда соответствующие биты обоих операндов равны 1.
При поразрядной дизъюнкции (|) бит результата равен 1 только тогда, когда соответствующий бит хотя бы одного из операндов равен 1.
При поразрядном исключающем ИЛИ (^) бит результата равен 1 только тогда, когда соответствующий бит только одного из операндов равен 1.
Например,
11000001 |
двоичное представление числа 193 |
|
01111111 |
двоичное представление числа 127 |
|
& ------------ |
поразрядная операция конъюнкция |
|
01000001 |
результат |
|
10000000 |
двоичное представление числа 128 |
|
00000011 |
двоичное представление числа 3 |
|
| ------------ |
поразрядная операция дизъюнкция |
|
10000011 |
результат |
|
01111111 |
двоичное представление числа 127 |
|
01111000 |
двоичное представление числа 120 |
|
^ ------------ |
поразрядная операция исключающее ИЛИ |
|
00000111 |
результат |
|
#include <iostream.h > |
|
Результат работы программы: |
int main (){ |
|
|
printf(“ 7 & 5 = %d\n ”, (7 & 5)); |
7 & 5 = 5 |
|
printf(“ 7 ^ 5 = %d\n ”, (7 ^ 5)); |
7 ^ 5 = 2 |
|
printf(“ 7 | 5 = %d\n ”, (7 | 5)); |
7 | 5 = 7 |
|
return 0; |
|
|
} |
|
|
11
Логические операции (!, &&, || ) отрицание, конъюнкция и дизъюнкция применяются к операндам арифметического типа или указателям. Результатом логической операции является true или false.
Логическое отрицание (!) дает в результате значение 0, если операнд есть истина (не нуль), и значение 1, если операнд равен нулю.
Результат операции (&&) имеет значение true, если оба операнда равны true.
Результат операции (||) имеет значение true, если хотя бы один из операндов равен true. Операции присваивания (=, +=, -=, *= т. д.) могут использоваться в программе как законченные операторы. Эти операции подробно рассматриваются в разделе «Оператор присваивания, с.».
6. Выражения
Выражение строится из операндов, знаков операций и круглых скобок. Оно задает правило для получения одного значения определенного типа, т. е. показывает, какие действия, в каком порядке и над какими величинами должны быть выполнены. В качестве операндов могут быть использованы константы, переменные, указатели функций. Если выражение не имеет круглых скобок, то порядок вычислений определяется приоритетом операций. С помощью скобок можно задать любой желаемый порядок вычислений.
Если в выражении встречаются операнды разного типа, то при вычислении выражения выполняется преобразование типов по определенным правилам, которые обеспечивают приведение коротких типов к более длинным типам для сохранения значимости и точности.
7. Форматный ввод/вывод на консоль
Несколько предварительных замечаний о вводе/выводе. В языке С++ нет встроенных средств для ввода/вывода - он осуществляется с помощью функций, типов и объектов, содержащихся в стандартных библиотеках. Существует два способа:
-используются функции, унаследованные из языка С;
-используются объекты С++.
Основными функциями ввода/вывода в стиле С являются функции scanf ( ) printf ( ).
Эти функции выполняют форматированный ввод и вывод, то есть они могут читать и писать данные в разных форматах. Обе функции могут работать с любым встроенным типом данных.
Функция scanf() считывает данные с клавиатуры. Она может читать данные всех встроенных типов и автоматически преобразовывать числа в соответствующий внутренний формат.
Прототип функции scanf () имеет следующий вид:
int scanf (<строка_форматирования>, <список_ элементов_ввода>);
Эта функция возвращает количество тех элементов данных, которым было успешно присвоено значение.
Строка форматирования содержит спецификаторы, которые определяют преобразование считываемых значений при записи их в переменные, определяемые списком_элментов_ ввода. Каждый спецификатор формата ввода начинается со знака % и сообщает функции scanf () тип считываемых данных. Спецификаторам преобразования в порядке слева направо ставятся в соответствие элементы списка ввода.
12
Наиболее часто используются следующие спецификаторы преобразования:
Код Значение
%d Читает десятичное целое число %e Читает число с плавающей точкой %f Читает число с плавающей точкой %u Читает целое значение без знака %c Читает одиночный символ
%s Читает строку
Пример программы, использующей функции ввода/вывода в стиле С.
#include <stdio.h> void main ( ){
int n,m; float f’ char sim;
scanf (“%d%d%f%c”, &n, &m, &a, &sim); printf (“%d %d %f %c\n”, n, m, a, sim);
}
Первая строка этой программы - директива препроцессора, по которой в текст программы вставляется заголовочный файл <stdio.h>, содержащий описание используемых в программе функций ввода/вывода (в данном случае угловые скобки являются элементом языка). Все директивы препроцессора начинаются со знака #. Для всех переменных, которые должны получить значения с помощью scanf (), должны быть переданы адреса (это достигается применением операции получения адреса &).
Четвертая, пятая и шестая строки содержат описание переменных.
Функция scanf() заносит введенные с клавиатуры данные в соответствующие переменные, а функция printf ( ) выводит на экран строку, заменив спецификации преобразования соответствующими значениями.
Пример программы, использующей библиотеки классов С++:
#include <iostream.h> int main ( )
{
int n,m; float a; char sim;
cin >> n >>m >> a >> sim; cout << n << m << a << sim;
printf (“%d %d %f %c ”, n, m, a, sim); retutn 0;
}
Заголовочный файл <iostream.h> содержит описание набора классов для управления вводом/выводом. В нем определены стандартные объекты-потоки cin для ввода с клавиатуры и cout для вывода на экран, а также операции помещения в поток << и чтения из потока >>.
13
Функция printf() выводит данные всех встроенных типов, автоматически преобразовывает числа из внутреннего формата в строку символов и имеет следующий вид:
int printf (<строка_форматирования>, <список_ элементов_вывода>);
Функция возвращает число выведенных символов или отрицательное значение в случае ошибки.
Строка форматирования состоит из элементов двух видов. Первый из них – это символы, которые предстоит вывести на экран; второй – это спецификаторы преобразования, которые определяют способ вывода, стоящих за ними элементов вывода. Функция printf () использует те же спецификаторы, что и функция scanf (). Элементов в списке вывода должно быть ровно столько, сколько и спецификаторов. Спецификаторы преобразования и элементы вывода должны попарно соответствовать друг другу в направлении слева направо.
Во многих спецификаторах преобразования при выводе можно указывать модификаторы, которые позволяют редактировать результат вывода. Например, можно указать ширину поля, количество десятичных разрядов и выравнивание по левому краю. Модификатор формата помещают между знаком процента и кодом формата.
Целое число, расположенное между знаком % и кодом формата, играет роль модификатора ширины поля. Если указан модификатор ширины поля, то чтобы ширина поля вывода была не меньше указанной длины, при необходимости вывод будет дополнен пробелами. Если же выводятся строки или числа, которые длиннее указанной ширины, то они все равно будут отображаться полностью.
Модификатор ширины поля чаще всего используется при создании таблиц, в которых столбцы должны быть выравнены по вертикали. Например, следующая программа выводит таблицу квадратов и кубов чисел от 1 до1:
// вывод таблицы квадратов и кубов целых чисел от 1 до 12 #include <iostream>
int main()
{
int i;
for( i=1; i<=12; i++)
printf (“%8d %8d %8d \n”, i, i*i, i*i*i ); return 0;
}
А вот пример полученного с ее помощью вывода:
1 |
1 |
1 |
2 |
4 |
8 |
3 |
9 |
27 |
4 |
16 |
64 |
5 |
25 |
125 |
6 |
36 |
216 |
7 |
49 |
343 |
8 |
64 |
512 |
9 |
81 |
729 |
10100 1000
11121 1331
12144 1728
14
Модификатор точности следует за модификатором ширины поля (если таковой имеется). Он состоит из точки и расположенного за ней целого числа. Значение этого модификатора зависит от типа данных, к которым он применяется.
Когда модификатор точности применяется к данным с плавающей точкой, для преобразования которых используется спецификаторы преобразования %f или %e, то он определяет количество цифр в дробной части числа.
Если модификатор точности применяется к целым типам, то он определяет минимальное количество цифр, которые будут выведены для каждого из чисел.
#include <iostream> int main()
{
printf (“%.4f\n”, 123.1234567 ); printf (“%3.8d\n”, 1000);
return 0;
}
Результат работы программы:
123.1235
00001000
По умолчанию весь вывод выравнивается по правому краю поля. Если ширина поля больше ширины выводимых данных, то эти данные располагаются по правому краю поля. Для выравнивания по левому краю поля необходимо поместить знак минус прямо за %.
Например, %-10.2f означает, что число с плавающей точкой и с двумя знаками в дробной части будет выравнено по левому краю 10-символьного поля.
В следующей программе показано как применяется выравнивание по левому краю.
#include <iostream> int main()
{
printf (“…………………………………. \n” ); printf (“по правому краю: %8d \n”, 100); printf (“ по левому краю: %-8d \n”, 100); printf (“…………………………………. \n” ); return 0;
}
Результат работы программы:
…………………………………..
по правому краю: 100 по левому краю: 100
………………………………….
Подробно о кодах форматов и модификаторах смотри [1], [3].
В дальнейшем изложении в рамках структурного программирования будет использоваться ввод/вывод в стиле С.
15
8.Базовые конструкции структурного программирования
Втеории программирования доказано, что программу для решения задачи любой сложности можно составить только из трех структур, называемых следованием, ветвлением и циклом.
Следование, ветвление и цикл называют базовыми конструкциями структурного программирования. Следованием называется конструкция, представляющая собой последовательное выполнение двух или более операторов (простых или составных). Ветвление задает выполнение либо одного, либо другого оператора в зависимости от выполнения какого-либо условия. Цикл задает многократное выполнение оператора в зависимости от некоторого условия. Особенностью базовых конструкций является то, что они имеют один вход и один выход, поэтому конструкции могут вкладываться друг в друга произвольным образом.
Следование |
|
|
Ветвление |
|
|
Цикл |
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Целью использования базовых конструкций является получение программы простой структуры. Такую программу легко читать, отлаживать и при необходимости отлаживать. В большинстве языков высокого уровня существует несколько реализаций базовых конструкций. Главное, о чем нужно помнить даже при написании самых простых программ, - что они должны состоять из четкой последовательности блоков строго определенной конфигурации.
Рассмотрим операторы языка, реализующие базовые конструкции структурного программирования.
Оператор - это часть программы, которая может быть выполнена отдельно, и определяет операцию и значения или местонахождение ее операндов.
Оператор присваивания
В языке С++ любое выражение, заканчивающееся точкой с запятой рассматривается как оператор, выполнение которого заключается в вычислении выражения.
Оператор присваивания предназначен для установления значений переменным в программе и имеет следующий формат:
<имя_ переменной> = <выражение>;
Работа оператора начинается с вычисления выражения. Полученное значение присваивается переменной, имя которой указано слева от знака « = ».
В операторе присваивания действует простое правило: значение выражения в правой части преобразуется к типу объекта в левой части.
16
При описании переменной можно присвоить начальное значение, это называется инициализацией. Инициализатор можно записать в двух формах – со знаком равенства или в круглых скобках.
Примеры операторов присваивания:
int a, sum=0; sum=sum + a; R = p1 * x / y; i = i + 1; found = B /C;
x1 = (-b + sqrt(b * b – 4 * a * c)) / (2 * a);
В языке С++ допускается множественное присваивание. В одном операторе присваивания можно задать одно и то же значение многим переменным, например:
x = y = z = 0;
Также в языке С++ допускается составное присваивание. Это разновидность оператора присваивания, в которой запись сокращается и становится более удобной в написании. Например, операторы
x = x+10; |
y = y-100; |
можно записать как
x +=10; |
y -=100; |
Следует отметить, что в практике программирования множественное присваивание и составное присваивание используются очень часто.
Операторы ветвления
Условный оператор.
Условный оператор используется для программирования разветвляющихся вычислительных процессов, когда в зависимости от результатов проверки некоторого условия, вычисления идут по одному или другому направлению.
Оператор имеет следующий формат:
if ( <выражение> ) <оператор_1>;
[else <oператор_2>;]
Квадратные скобки означают, что конструкция, стоящая в них, может присутствовать, но может и отсутствовать. В первом случае условный оператор имеет полную форму, во втором – краткую. Выражение в условном операторе имеет логический тип.
Работа оператора начинается с вычисления выражения, если оно имеет значение true (т.е. принимает любое значение, отличное от нуля), то выполняется <оператор_1>, если false , то выполняется <оператор_2>. Следует обратить внимание на то, что согласно синтаксису
17
как в одной, так и в другой ветви допускается только один оператор. Если в какой либо ветви требуется выполнить несколько операторов, то необходимо использовать составной оператор.
Например, для нахождения наибольшего из значений х1 и х2 достаточно выполнить следующий условный оператор
if (x1 > x2) max = x1;
else
max = x2;
При использовании краткой формы оператора, если выражение имеет значение true, то выполняется <оператор_1>, в противном случае никаких действий не производится и осуществляется переход к следующему оператору программы. Например,
if (x > y) alfa = true;
Если величина х больше y , то оператор присваивания переопределит значение логической переменной alfa, в противном случае значение alfa не изменится.
Пример. Написать программу вычисления действительных корней квадратного уравнения
аx2 + bx + c = 0 (a .> 0) , в случае мнимых корней выдать сообщение.
#include <iostream.h>
#include <math.h> //подключается стандартная библиотека математических функций int main ()
{
float a, b, c, x1, x2, d, d1, a1; printf(“введите а, в, с \n”); scanf(“%f%f%f”, &a, &b, &c); d=b*b – 4*a*c;
if (d<0)
printf(“корни мнимые\n”); else
{
d1 = sqrt(d); a1= 2 * a;
x1 = (-b + d1) / a1;
x2 = (-b – d1) / a1;
printf(“x1=%f x2=%f\n”, x1, x2);
}
return 0;
}
В этой программе в условном операторе после else стоит составной оператор. Примечание. Если имеется переменная found логического типа (bool),
то вместо условного оператора if (A == B)
found=true; else
found=false;
проще воспользоваться логическим оператором присваивания found = A == B; 18
Оператор «?», альтернативный условному оператору if
Оператор ? является тернарным, потому что он имеет три операнда. Его общая форма следующая:
<выражение _1> ? <выражение_2> : <выражение_3>;
Обратите внимание на использование и расположение двоеточия.
Результат операции ? определяется следующим образом. Сначала вычисляется <выражение_1>. Если оно имеет значение true (истина), вычисляется <выражение_2> и его значение становится результатом операции ?. Если <выражение_1> имеет значение false (ложь) вычисляется выражение_3 и его значение становится результатом операции ?. Например,
х= 10;
у= х > 9 ? 100 : 200;
Вэтом примере переменной у присваивается значение 100. Если бы х было меньше 9, то переменная у получила бы значение 200.
То же самое можно записать, используя оператор if: x = 10;
if (x > 9) y = 100; |
else y = 200; |
Оператор выбора - |
switch |
Оператор выбора switch (часто его называют переключателем) предназначен для разветвления процесса вычислений на несколько направлений.
Оператор имеет следующий формат:
switch (<выражение>)
{
case <константное_ выражение_1> : [<список_операторов_1> break; ] case <константное_ выражение_2> : [<список_операторов_2> break; ]
.
.
.
case <константное_ выражение_n> : [<список_операторов_n> break; ] [ default: <последовательность операторов>;]
}
Значение выражения оператора switch должно быть таким, чтобы его можно было выразить целым числом. Это означает, что в управляющем выражении можно использовать переменные целого или символьного типа.
Выполнение оператора начинается с вычисления выражения. Полученное значение по очереди сравнивается с константным выражением в операторах case. Если значение управляющего выражения совпадает с каким-то из константных выражений, то управление передается на соответствующую метку case и выполняется список операторов до оператора break. Если оператор break отсутствует, выполнение последовательности операторов продолжается до тех пор, пока не встретится break (в другой метке) или не кончится тело оператора switch. Оператор default выполняется в том случае, когда
19
значение управляющего выражения не совпало ни с одним константным выражением. Если оператор default отсутствует, то управление передается следующему за switch оператору.
Пример. Написать программу, имитирующую работу простейшего калькулятора на четыре действия (+, -, *, /).
#include <iostream.h>
int main()
{
int a,b, r; char op; bool fl=true;
printf(“ введите первый операнд \n”); scanf(“%d”, &a);
printf(“ введите знак операции \n”); scanf(“%с”, &op);
printf(“ введите второй операнд \n”); scanf(“%d”, &b);
switch (op)
{
case ‘+’: |
r = a + b; |
break; |
case ‘-’: |
r = a - b; |
break; |
case ‘*’: |
r = a * b; |
break; |
case ‘/’: |
r = a / b; |
break; |
default : |
fl=false; |
|
}
if (fl)
printf(“результат=%d\n”, r); else
printf(“неизвестная операция\n”); return 0;
}
Операторы цикла
Операторы цикла используются для программирования циклических вычислительных процессов. Любой цикл состоит из заголовка цикла и тела цикла, то есть тех операторов, которые выполняются несколько раз.
Вязыке С++ различают три вида операторов цикла:
-оператор цикла с предусловием ( while );
-оператор цикла с постусловием (do … while);
- оператор цикла с параметром ( for ).
Один проход цикла называется итерацией. Переменные, изменяющиеся в теле цикла и используемые при проверке условия продолжения, называются параметрами цикла.
20
