Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебное пособие2013_09_28.doc
Скачиваний:
29
Добавлен:
20.05.2015
Размер:
2.72 Mб
Скачать

Операции , выражения и операторы.

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

Самая популярная операция – присваивание:

V = выражение

Если после “выражения” поставить точку с запятой (;), то такая конструкция превращается в оператор присваивания, который вычисляет “выражение” и полученное значение записывает в память компьютера, обозначенную именем V.

Операция присваивания может применяться в выражениях наряду с прочими операциями.

Пример.

int a, b, c = 5;

a = (b = c + 1) + 7;

cout << a << “ “ << b;

Результат работы этого фрагмента:

  1. 6

В зависимости от используемых знаков операций различают арифметические операции, операции отношения и логические операции.

А р и ф м е т и ч е с к и е о п е р а ц и и.

Основные бинарные арифметические операции: + (сложение), – (вычитание), * (умножение), / (деление ) и % (вычисление остатка от деления целых чисел). Все знаки операций в выражении должны быть записаны явно. При делении любых целых чисел дробная часть отбрасывается.

Операцию % продемонстрируем на следующем примере. Требуется ввести натуральное трехзначное число и напечатать его цифры в обратном порядке.

#include <iostream.h>

#include <conio.h>

int main()

// в стандартеC++ рекомендуется использовать заголовок вида:

// int main() либо даже int main(void)

{

clrscr(); // Очистка экрана

int a, z1, z2, z3;

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

cin>>a; // ввод числа

z3=a%10; cout<<z3; // последняя цифра

z2=a/10%10; cout<<z2; // средняя цифра

z1=a/100; cout<<z1; // первая цифра

getch(); return 0;

}

Порядок выполнения операций в арифметических выражениях определяется скобками и приоритетом операций:

а) выражения внутри скобок вычисляются до того, как взятая в скобки величина будет использована в дальнейших вычислениях;

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

в) операции, имеющие одинаковый приоритет, выполняются в порядке их следования в выражении: справа налево выполняются унарные операции, тернарная операция(см. далее), а также простая и составные операции присваивания (см. далее); остальные – слева направо.

Следует соблюдать осторожность при вычитании близких по величине чисел с плавающей точкой, помня о том, что вещественные числа представляются в компиляторе приближённо: данные типа float гарантируют 7-8 точных цифр в числе; тип double обеспечивает 15-16 точных цифр, а long double – до 20 цифр.

Пример.

float a = 2.5e+15;

float b = a + 1.0;

cout << b – a;

Очевидно, следовало бы ожидать, что результат будет равен 1. Однако на практике это не всегда так. Убедитесь сами.

Операция приведения типа. Операнды бинарных операций могут иметь различные типы. C/C++ автоматически выполняет преобразование между различными типами данных, приводя операнды к одному типу, когда это возможно. Следует обратить особое внимание на правила преобразования операндов различных типов, входящих в выражение. Основное правило здесь такое: если выражение содержит объекты разных типов, то более короткие типы перед вычислениями преобразуются к более длинным, чтобы по возможности исключить потерю значимости и точности. В сомнительных случаях обращайтесь к более толстым книгам по программированию.

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

имя_типа (выражение)

(имя_типа) выражение.

В результате «выражение» преобразуется к заданному типу (разумеется, если это возможно).

Пример. Вычислить площадь прямоугольного треугольника по его катетам a и b.

int a, b; float s;

a=3; b=4;

s=(float)1/2 * a*b;

cout<<"площадь = "<<s<<endl;

Убедитесь сами, что без описателя приведения к типу float программа выдаст в качестве результата 0.

Стандартные библиотечные функции. В выражениях могут использоваться имена вызываемых функций. Для вычисления часто встречающихся математических функций (sinx, cosx, , lnx, arctgx и др.), а также для преобразования данных, относящихся к разным типам, существуют заранее определенные стандартные функции. Вот некоторые из них:

abs(x), fabs(x) — вычисление | x | для целого и вещественного x ;

exp(x) — возведение e (основание натуральных логарифмов) в степень x ;

log(x) — вычисление натурального логарифма x ;

sqrt(x) — вычисление квадратного корня из x ;

ceil(x) — отыскание ближайшего целого, которое >=x ;

floor(x) — отыскание ближайшего целого, которое <=x ;

pow(x, y) — вычисление x в степени y ;

sin(x),cos(x),atan(x) — соответствующие тригонометрические функции.

Для подключения к программе библиотеки стандартных математических функций необходимо с помощью препроцессорного утверждения #include в самом начале программы включить за­головочный файл <math.h> (или <cmath>), а для некоторых из рассматриваемых функций — файл <stdlib.h>:

#include <math.h>

#include <stdlib.h>

Примеры арифметических выражений:

Математическая запись Арифметическое выражение С/С++

a*x*x + b*x + c

sqrt((a*x + b)/(c*x-d))

log(sqrt(x*exp(-y)))

(-b + sqrt(b*b – 4*a*c))/(2*a)

О п е р а ц и и и н к ре м е н т а и д е к р е м е н т а. В языке С/С++ широко используются две нетрадиционные унарные операции для увеличения (инкремент) или уменьшения (декремент) значения переменной на 1, обозначаемые соответственно ++ и – –. Эти операции могут быть использованы или перед операндом, или после него (т. н. префиксная и постфиксная формыоперации соответственно). Они оказывают разное действие в выражениях: в записи ++n увеличение происходит до использования значения n, а в n++ увеличение идет уже после того, как используется значение n. Если считать, что значение переменной n равно 5, то выполнение оператора m = ++ n; присвоит переменной m значение 6, а после выполнения оператора m = n++; значение m станет равным 5. И в том, и в другом случае n получит значение 6. Первый пример в точности соответствует последовательности операторов n=n+1; m=n; а во втором случае - следующим двум операторам: m=n; n=n+1. Операция декремента (--) действует аналогично. Обе операции имеют самый низкий приоритет среди арифметических операций и выполняются после бинарных операций + и .

Эти операции в выражениях следует применять с некоторой осторожностью. Не будьте слишком самоуверенными!

Пример.

int n=5, y;

y=n/2 + 5*(1 + n++) + n/2;

cout << y;

Что, на Ваш взгляд, будет выдано на экран? Возможно, компилятор сперва вычислит выражение в скобках, увеличив n, а затем использует это новое значение для вычисления n/2 ? На этот счет нет никаких гарантий, всё зависит от реализации компилятора.

Результаты работы этого фрагмента, полученные для семейства компиляторов Borland C++ ( в т. ч. Borland C++ Builder 6), приведены далее ( см. задачу 7 в разделе «Программирование алгоритмов линейной структуры».

Операция определения размера sizeof предназначена для вычисления длины переменой ( выражения ) или типа (в байтах), например, sizeof (max), sizeof (double).

О п е р а ц и и о т н о ш е н и я.

Эти операции используются для сравнения операндов и обозначаются в языке С/C++ следующим образом:

== (равно);

!= (не равно);

< (меньше);

> (больше);

<= (меньше или равно);

>= (больше или равно).

Операндами операций отношения могут быть как арифметические выражения, так и строковые данные. Результатом операции отношения является значение логического типа TRUE(1) или FALSE(0). Приоритет операций отношения ниже приоритета арифметических операций, так что выражение вида k > n%i вычисляется как k > (n%i). Интересно, что операции = = (равно ) и != (не равно) имеют более низкий приоритет, чем остальные операции сравнения.

Пример.

#include <stdio.h>

#include <iostream.h>

#include <conio.h>

int main ()

{

int x=25, y=23; int z; // bool z;

cout<< "x = "<<x<<endl;

cout<< "y = "<<y<<endl;

z=x == y; cout<<"x == y ? "<< z <<endl;

z=x > y; cout<<"x > y ? "<< z <<endl;

z=x <= y; cout<<"x <= y ? "<< z <<endl;

return 0;

}

Результат работы программы:

x = 25

y = 23

x == y ? 0

x > y ? 1

x <= y ? 0

Л о г и ч е с к и е о п е р а ц и и.

Операндами логических операций могут быть выражения арифметического или логического типов. Преобразование типов в выражениях не производится . Каждый операнд оценивается с точки зрения его равенства нулю. Равный нулю операнд трактуется как FALSE (ЛОЖЬ), а ненулевой – как TRUE (ИСТИНА).

Символ ! в языке С/С++ обозначает логическое отрицание НЕ. Эта унарная операция записывается непосредственно перед операндом и изменяет его логическое значение на противоположное. Будем использовать еще две логические операции: || означает логическое ИЛИ, а &&логическое И. Первая возвращает в качестве результата TRUE(1), если хоть один из операндов — TRUE(1); в противном случае результат операции — FALSE (0). Результат операции логическое И имеет значение TRUE(1), только если оба операнда — TRUE(1); в остальных случаях — FALSE (0).

Приоритет операции && выше, чем у ||, но обе логические операции выполняются после операций отношения и арифметических операций. В сомнительных случаях лучше расставлять скобки.

Пример. Известно, что квадратное уравнение

ax2 + bx +c=0

имеет два различных корня, если b2 – 4ac >0. Кроме того, ветви графика фунции

y= ax2 + bx +c

направлены вверх, если a > 0.

Ввести коэффициеты a, b, c и проверить, удовлетворяет ли сответсвующий квадратный трехчлен перечисленным выше требованиям?

#include <stdio.h>

#include <iostream.h>

#include <conio.h>

int main ()

{

float a, b, c; int z; // bool z;

clrscr(); //Очистка экрана

cout<< "a = "; cin>>a;

cout<< "b = "; cin>>b;

cout<< "c = "; cin>>c;

z = b*b-4*a*c > 0 && a > 0;

cout<<"Да - 1, нет - 0 : "<< z <<endl;

return 0;

}

Протокол выполнения программы:

a = 1

b = -5

c = 6

Да - 1, нет - 0 : 1

Операции отношения и логические операции используются преимущественно в операторах управления – ветвлениях и циклах ( см. далее).

П о р а з р я д н ы е л о г и ч е с к и е о п е р а ц и и и с д в и г и предназначены для работы с отдельными битами целого числа или символа:

& поразрядное логическое И

^ поразрядное логическое исключающее ИЛИ

>> cдвиг вправо

| поразрядное логическое ИЛИ

<< сдвиг влево

~ инверсия

При поразрядных логических операциях (&, |, ^) сопоставляются соответствующие биты обоих операндов и над каждой парой битов выполняется логическая операция:

а) при операции & бит результата равен 1 тогда и только тогда, когда соответствующие биты обоих операндов равны 1; в противном случае результат операции — 0.

б) при операции | бит результата равен 1, если в соответствующих битах обоих операндов есть хоть одна 1; в противном случае результат операции — 0.

в) при операции ^ бит результата равен 1, если соответствующие биты обоих операндов имеют разные значения; в противном случае результат операции — 0.

Поразрядная логическая операция И (&) часто используется для выделения некоторой группы двоичных разрядов; например, n = n & 0177 «сбрасывает» в ноль все двоичные разряды числа n, кроме семи младших.

Операция ИЛИ (|) используется для установки отдельных двоичных разрядов в единицу. Например, операция m=m|0xF0F “включает” 11, 10, 9, 8, 3, 2, 1 и 0 биты числа m,сохраняя неизменными его остальные биты .

Следует иметь в виду, что поразрядные логические операции (&, |) и “обычные” логические операции (&&, | |) – не одно и то же. Порой, будучи применёнными к одним и тем же наборам данных, они дают прямо противоположные результаты. Пусть, например, int x=1, y=2; Тогда x&y есть 0(FALSE), тогда как x&&y есть 1(TRUE).

Операции << и >> выполняют сдвиг первого (левого) операнда соответственно влево или вправо на заданное число двоичных разрядов, заданное вторым (правым) операндом. Например, m << 3 сдвигает значение m влево на три разряда, заполняя освобождающиеся младшие разряды нулями. Это, кстати, соответствует умножению числа на 8 (в общем случае на 2 в степени n, где n – число сдвигаемых разрядов). Аналогично выполняется и сдвиг вправо на n разрядов, что равносильно делению числа на 2 в n-й степени. Но при этом сдвиге высвобождающиеся разряды заполняются значением знакового бита для знаковых целых чисел и нулём – для беззнаковых (unsigned).

Пример.

#include <conio.h>

#include <iostream.h>

int main()

{

short int n, m=-1; cout <<m<<endl; // -1

n=m>>3; cout <<n<<endl; // -1

unsigned short int n1, m1=65535;

n1=m1>>3; cout <<n1<<endl; // 8191

getch(); return0;

}

Результат работы программы приведен в виде комментария к каждому из операторов вывода.

Унарная операция ~ выполняет инверсию двоичных разрядов числа (символа), т. е. преобразует каждый единичный бит в нулевой и наоборот.

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

#include <stdio.h>

#include <iostream.h>

#include <conio.h>

intmain ()

{

int x=25,y=23,z;

z=x&y; cout<<"x&y="<<z<<endl;

z=x|y; cout<<"x|y="<<z<<endl;

z=x^y; cout<<"x^y="<<z<<endl;

x=2;

z=x<<2; cout<<"x<<2="<<z<<endl;

x=16;

z=x>>2; cout<<"x>>2="<<z<<endl;

return0;

}

Протокол выполнения программы:

x&y=17

x|y=31

x^y=14

x<<2=8

x>>2=4

Операция «запятая». Несколько выражений, разделённых запятыми, вычисляются последовательно слева направо. В качестве результата сохраняются тип и значение самого правого выражения.

Пример.

float S, a, x, pi=3.14;

S = (a = pi, x = 0.5, sin(a*x));

cout << "a= ”<<a << ‘\t’ <<”S= ”<< S;

Результат : a= 3.14 S= 1

О п е р а ц и и п р и с в а и в а н и я (=) и составного присваивания (+=, –=, *=, и т. д.) могут использоваться в качестве составной части выражения. Выражение вида i = i + b, где левая часть повторяется в правой части операции присваивания, могут быть записаны в сжатой форме: i += b. При этом используется операция присваивания вида +=, которая означает буквально " i увеличить на b".

Для большинства бинарных операций допускается запись вида op=, где op — одна из рассмотренных ранее операций : +, –, *, /, %, |, ^, &, <<, >>. Если Е1 – переменная и Е2 — выражение, то Е1 op= Е2 эквивалентно Е1 = Е1 op (Е2). Обратите внимание на скобки вокруг Е2: присваивание x*=y+1 фактически означает x=x*(y+1), а не x=x*y+1.

У с л о в н а я (тернарная) о п е р а ц и я (? :). Фактически она представляет сокращенную форму оператора if else (будет рассмотрен позже), и в общем виде записывается так:

логическое_выражение1 ? выражение2 : выражение3

Если "логическое_выражение1" истинно (не равно нулю), то результатом операции будет значение "выражения2", в противном случае – значение "выражения3". Условная операция, называемая иногда тернарной (она имеет три операнда) , определяет обычное выражение, которое может, в частности, быть использовано в операторе присваивания. Таким образом, вместо оператора ветвления (см. далее)

if(x>y)

max=x;

else

max=y;

достаточно написать:

max = (x > y) ? x : y;

Скобки вокруг " логического_выражения1" ставить не обязательно, так как приоритет тернарной операции очень низкий, ниже он только у присваивания.

Операторы.

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

Любое выражение, которое завершается точкой с запятой, представляет собой оператор, выполнение которого приводит к некоторой обработке данных. Это так называемый «оператор-выражение». Примеры:

k++;

a*x*x + b*x + c; // скорее всего, бесполезный оператор

Один оператор может занимать одну или более строк. Два или более операторов могут быть расположены на одной строке.

Оператор присваивания имеет вид: V= выражение;

Например, absZ = (Z < 0) ? – Z : Z ;

Этот оператор мы рассмотрели ранее достаточно подробно.

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

Оператор перехода goto имеет вид : goto метка;

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

Пример.

m1: x:=x+1;

. . .

gotom1;

Оператор вызова функции имеет вид:

Имя_функции (аргумент1, ... , аргументN);

Пример. setviewport (x1, y1, x2, y2, clip);

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

return [ выражение ];

Составной оператор (блок) состоит из одного или большего числа операторов любого типа, заключенных в фигурные скобки ( { }). В начале составного оператора могут содержаться описания данных. Они служат для определения переменных, локализованных в данном блоке, либо для распространения на данный блок области действия глобальных объктов. Подобно другим операторам языка, любой оператор внутри составного оператора может быть помечен. Передача управления по метке внутрь составного оператора хотя и возможна, но требует соблюдения определённой осторожности. Ведь если блок содержит определение переменных с их инициализацией, то при входе в блок по метке эта инициализация не состоится и значения переменных будут непредсказуемы.

Элементарный ввод – вывод

Ввод-вывод в стиле языка С++. Для правильного использования операторов ввода/вывода в С++ следует включить в программу заголовочный файл <iostream.h> либо файл <iostream>. Этот файл содержит описание набора так называемых классов для управления вводом-выводом. Класс iostrem использует потоки (streams) для организации базового ввода и вывода, например, печати текста на экране или приёма данных пользователя с клавиатуры. В нём определены стандартные объекты – поток cin для приёма с консоли данных, вводимых пользователем и поток cout – для пересылки данных в стандартный выходной поток, отождествляемый с экраном монитора, а также операторы чтения (извлечения ) из потока ( >>) и вывода (включения ) в поток (<<).

Оператор извлечения ( >> ), используемый для считывания данных из стандартного входного потока cin, имеет вид:

cin >> переменная;

При вводе последовательность символов входного потока преобразуется во внутреннее представление переменной, стоящей справа от знака >> , в сответствии с её типом. Числовые данные можно вводить в десятичной или шестнадцатеричной системе счисления (с префиксом 0x), со знаком или без него. Вещественные числа можно вводить как в форме основной константы (с фиксированной точкой ), так и в экспоненциальной форме (с порядком).

Пример.

int a; char ch; float b, c, d;

cin >> a; cin>>ch;

cin >> b >> c >> d;

Последний пример иллюстрирует возможность применения нескольких подряд расположенных операторов извлечения >>.

Внимание! При вводе строк символов извлечение продолжается до первого пробела.

С помощью оператора включения ( << ) можно вывести данные любого базового типа языка С++. В общем случае для вывода данных на экран применяется следующая форма этого оператора:

cout << выражение;

Здесь выражение может быть произвольного допустимого в С++ типа. Оператор << записывает данные в выводной поток cout, которые при необходимости преобразуются к символьному виду.

Пример.

cout << " Всё пройдёт – и печаль, и радость ";

Посредством цепочки операторов включения текстовую строку можно записывать в поток по частям:

cout << " Всё пройдёт - " << " и печаль, " << " и радость";

С помощью оператора включения несложно записать в поток значения переменных и выражений. Для перехода на новую строку экрана можно использовать вывод символа ‘\n’, либо так называемый манипулятор endl.

Рассмотрим пример.

#include<conio.h>

#include <iostream.h>

#define STR " Длина окружности = "

void main()

{

int r; double pi=3.14159;

clrscr();

cout << " Только верить надо, что \n";

cout << STR << "2*pi*R"<<endl;

cout << " Введи радиус ";

cin >> r;

cout << STR << 2*pi*r;

getch();

}

В результате выполнения этого кода на экране после ввода радиуса (r=2) появится:

Только верить надо, что

Длина окружности = 2*pi*R

Введи радиус 2

Длина окружности = 12.56636

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

Ввести катеты прямоугольного треугольника a, b. Вычислить его площадь и периметр.

Очевидно, что площадь S можно найти сразу же:

S = ab/2

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

c =  , p = a + b + c.

#include <conio.h>

#include <iostream.h>

#include <math.h>

voidmain()

{

floata,b,c,s,p;

cout<<"Введи через пробел a, b\n ";

cin >> a >> b; //либо cin>>a; cin>>b;

s = 0.5*a*b;

c = sqrt(a*a + b*b);

p = a + b + c;

cout<<"Площадь = "<<s<<endl;

cout<<"Периметр = "<<p<<endl;

}

Еще раз напомним, что в процессе ввода числовых данных последовательность символов, изображающих число, авто­матически преобразуется во внутреннее представление согласно типу переменной (здесь - вещественный тип). Для ввода нескольких величин в объекте cin используется цепочка опе­раций >>.

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

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

decвывод в 10 с/с, hex – вывод в 16 с/с, oct – вывод в 8 с/с.

Используя т. н. методы объекта cout, можно управлять выводом информации на экран:

cout.width(ширина поля вывода);

cout.precision(число цифр дробной части);

Рассмотрим пример.

#include <iostream.h>

#include <conio.h>

void main()

{

int n=13;

clrscr(); //Очистка экрана

cout << n<<" "<<oct<<" "<<n<<hex<<" "<<n<<endl;

long x=12345678;

double y=12345.123456789;

cout.width(12); cout <<dec<< x <<endl;

cout.width(20); cout.precision(4);

cout << y <<endl;

getch();

}

При запуске программы на экране появится:

13 15 d

12345678

12345.1235

Форматированный ввод и вывод языка С осуществляется функциями стандартной библиотеки языка; подключение к программе описаний средств ввода-вывода осуществляет директива #include <stdio.h>.

Вывод данных. Для вывода данных на экран используется функция printf(). Она преобразует данные из машинного представления в символьное и выводит полученные изображения результатов на экран. При этом программист имеет возможность гибко форматиировать выводимые данные.

Общий вид оператора вызова функции printf():

printf(форматная_строка, список_выражений);

Форматная_ строка ограничена двойными кавычками и может включать:

  • обычный текст, который выводится на экран “как есть”;

  • управляющие символы (‘\n’ – переход на новую строку, ‘\t’ – табуляция и др.), которые позволяют влиять на размещение выводимой информации на экране.

  • спецификации преобразования, которые предназначены для управления формой внешнего представления значений из списка_ выражений.

Несколько упрощённый формат спецификации преобразования имеет вид:

%[флаги][ширина][.точность][модификатор] спецификатор

Среди элементов спецификации преобразования обязательными являются символы % и спецификатор. Каждому спецификатору соответствует тип выводимой с их помощью информации. Наиболее часто используются следующие спецификаторы.

Спецификатор Тип выводимой информации

%d,%iДесятичное целое число

%cОдин символ

%sСтрока символов

%f,%FЧисло с плавающей точкой, десятичная запись

%e,%EЧисло с плавающей точкой, экспоненциальная запись

%uДесятичное целое число без знака.

%oВосьмеричное число без знака.

%x,%XШестнадцатеричное число без знака.

Список_выражений в операторе вызова функции printf() может отсутствовать или включать объекты, значения которых должны быть выведены на экран. Это могут быть как собственно выражения, так и их частные случаи – константы и переменные. Количество элементов в списке вывода не фиксировано, но каждому элементу вывода должна соответствовать одна спецификация преобразования в форматной строке.

Пример.

inta= 5,b= 7;

printf(“Результаты: \n”);

printf(“сумма %dи %dравна %d\n”,a,b,a+b);

Кратко о необязательных полях спецификации преобразования:

Флаги служат для выравнивания выводимых данных (минус – по левой границе

поля вывода) и управления печатью знаков (пробел, +, – ) перед числом.

Пример. printf(“%-20s\n”, fio);

Ширина определяет минимальную ширину поля вывода. Параметр игнорируется,

если выводимое значение не помещается в отведённое поле.

Пример. printf(“%5d”, 127);

Точность задаёт количество цифр в дробной части числа с плавающей точкой;

для символьных строк – максимальное число печатаемых символов.

Пример.

float z=123.4567;

printf(“%8.2f”, z);

printf(“%20.3s\n”, “математика”);

Из модификаторов будем использовать только l для представления “длинных” типов (long, doubleL для long double.

Пример.

long alng=1234567890; double fdbl=987654321.12345678;

printf(“%ld\t %lf\n”,alng, fdbl);

Ввод данных. Для ввода данных с клавиатуры будем использовать функцию:

scanf(форматная_строка, список_адресов_переменных);

Так же, как для функции printf(), для функции scanf() указываются форматная строка и следующий за ней список аргументов. Основное различие двух этих функций заключается в особенностях данного списка. Функция printf() использует в нём имена переменных, константы и выражения ( в частности, строки символов), в то время как функция scanf() — только адреса переменных. Для определения адреса переменной перед её именем ставится знак & (это не касается имён массивов и строк символов).

Спецификация преобразования чаще всего имеет вид:

%[ширина] [модификатор] спецификатор

Ширина определяет количество символов из входного потока, соответствующих вводимому значению (используется редко).

Модификатор. Нами будет использован только модификатор l (см. описание функции printf()).

Спецификаторы. Для ввода числовых данных чаще всего используют: %d, %u, %f, %e; для ввода символов - %с; для ввода строк - %s.

Функция scanf() хорошо приспособлена для ввода десятичных целых и вещественных чисел. Она воспринимает пробельные символы (пробел, табуляция, перевод строки) как разделители между вводимыми числами. Если параметр спецификации преобразования “ширина” отсутствует, то при вводе числовых данных функция scanf() сканирует символы входного потока, игнорируя пробельные символы, выделяет непробельные символы и преобразует их (если среди них нет недопустимых символов для числа) в машинное представление согласно спецификации преобразования.

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

Замечание. Ширину поля вывода и точность в спецификации формата можно задавать и с помощью переменных, значения которых определяются, быть может, в процессе выполнения программы. Для этого в спецификации формата вместо полей ширина и точность ставят символ *, которым в списке вывода соответствуют имена упомянутых переменных. Например, для вставки в поле вывода переменного количества пробелов перед выводом символа @ можно поступить следующим образом:

int W;

printf ("Укажи количество пробелов ");

scanf ("%d", &W);

printf ("%*c", W, '@');

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

#include <conio.h>

#include<stdio.h>

void main()

{ clrscr(); //Очистка экрана

int width, precis;

double pi=3.1415926536;

printf("Введи ширину поля вывода ");

scanf("%d",&width);

printf("Введи точность ");

scanf("%d",&precis);

printf("pi= %*.*lf\n", width, precis, pi);

getch();

}

Всё тот же символ * , используемый в качестве поля ширина в спецификации преобразования функции scanf(), позволяет игнорировать присваивания вводимых полей данных соответствующим переменным. Пример.

#include <conio.h>

#include<stdio.h>

void main()

{ clrscr(); //Очистка экрана

int n;

printf("Введи 3 целых числа ");

scanf("%*d %*d %d",&n);

printf("Последнее число есть %d\n ",n);

getch();

}

Протокол работы программы:

Введи 3 целых числа 333 666 999

Последнее число есть 999

Некоторые экзотические возможности ввода данных с помощью функции scanf()(использование поля “ширина”, переменный формат и др. мы не рассматриваем).

Реализуем рассмотренный ранее пример вычисления площади и периметра треугольника с использованием ввода-вывода с стиле языка С.

#include <conio.h>

#include <stdio.h>

#include <math.h>

void main()

{

float a,b,c,s,p;

printf("Введи через пробел a, b\n ");

scanf("%f %f",&a , &b);

s = 0.5*a*b;

c = sqrt(a*a + b*b);

p = a + b + c;

printf("Площадь = %10.2f\n",s);

printf("Периметр = %10.2f\n",p);

}

О проблеме вывода текста на русском языке.

В среде Windows при подготовке текстов программ для кодировки символов используется стандарт ANSI. Отладку и выполнение программ как в среде Visual Studio 2008 (2010), так и в среде Borland C++ Builder мы собираемся осуществлять в режиме консольных приложений. Но дело в том, что в режиме консольного приложения используется кодировка символов в стандарте ASCII. Что касается кодировки латиницы, то она одинакова и в ASCII, и в ANSI, а вот кодировка кириллицы различна. Именно этим и объясняется, что в ранее приведенных примерах вместо нормальных фраз русского языка на экран выводятся какие-то странные символы.

Для вывода на экран сообщений на русском языке в среде Visual Studio 2008(2010) воспользуемся следующим приемом. Сначала выполним так называемую локализацию выходного потока с установкой кодовой страницы России:

wcout.imbue ( locale ( “rus_rus.866” ) );

После этого всюду в тексте программы для вывода строки символов на русском языке будем использовать объект wcout вместо cout с символом L перед строкой-литералом:

wcout << L”Добро пожаловать в Visual Studio 2010”<<endl;

Гораздо удобней для вывода на экран сообщений на русском языке в среде Visual Studio 2008 выполнить локализацию выходного потока с установкой кодовой страницы России следующим образом:

setlocale (NULL, “.1251”);

После этого вывод текста на русском языке всеми доступными средствами осуществляется уже без проблем (в частности, оператором cout), например:

cout << ”Добро пожаловать в Visual Studio 2008”<<endl;

puts (”Добро пожаловать в Visual Studio 2008”);

К сожалению, теперь возникают проблемы со вводом текста на русском языке.

Еще один вариант вывода (и ввода!) текста на русском языке: выполнить локализацию выходного потока с установкой кодовой страницы России следующим образом:

system("chcp 1251");

После запуска программы на выполнение следует щелкнуть в левом верхнем углу, выбрать

СВОЙСТВА ->ШРИФТЫ с ТОЧЕЧНЫХ заменить на LUCIDA CONSOLE.

Для нормального вывода на экран фраз на русском языке в среде Borland C++ Builder 6 будем использовать готовую функцию rus() (см. ниже), которая используется для перекодировки ANSI-строки в ASCII-код для вывода сообщений на русском языке. И хотя, быть может, эта функция не очень понятна (т.к. мы еще не изучали указатели), будем смело использовать её в наших программах, предварительно подключив её код с помощью препроцессорной команды, например:

#include "d:\\My_C_Builder_6\\rus.h"

Здесь мы явно указали путь к каталогу, где постоянно хранится функция rus() .

Рассмотрим снова пример, уже обсуждавшийся ранее (см. раздел 1. “ Структура программ на языке C/C++”).

// Программа отлажена в Borland C++ Builder 6

//---- используется функция rus перекодировки ANSI-строки ---

// в ASCII-код для вывода сообщений на русском языке

#pragma hdrstop

#include <stdio.h>

#include <iostream.h>

#include <conio.h>

const double PI=3.14159;

#define DEZL "C++ - это круто!"

#pragma argsused

#include "d:\\My_C_Builder_6\\rus.h"

int main()

{ char name[15]; int r;

double c, s;

clrscr();

cout<<rus(DEZL)<<endl;

cout<<rus("Как тебя зовут? "); cin>>name;

cout<<rus("Привет, ")<<name<<endl;

cout<<name<<rus(", введи радиус ==>");

cin>>r;

c= 2*PI*r; s=PI*r*r;

cout<<rus(" Площадь круга = ")<<s<<'\n';

cout<<rus(" Длина окружности = ")<<c<<'\n';

getch();

return 0;

}

/*

char* rus(char* st) //функция rus

{

unsigned char* p = st; // при объявлении символов как char русские

// буквы кодируются отрицательными числами

while ( *p )

{

if (*p >= 192) // здесь русская буква

if (*p <= 239) // А,Б, ... Я,а,б, ... п

*p -= 64;

else // р ...я

*p -= 16;

p++;

}

return st;

}

*/