
- •Часть 1
- •Лекция 1
- •Лекция 3
- •Алфавит
- •Идентификаторы
- •Константы
- •Знаки операций и разделители
- •4. Знаки операций.
- •Унарные операции.
- •Бинарные операции
- •5. Разделители.
- •Выражения.
- •4.1 Условный оператор
- •4.2. Переключатели
- •5.Оператор цикла с предусловием.
- •6.Оператор цикла с постусловием.
- •7.Оператор итерационного цикла
- •8.1.Оператор goto
- •8.2.Оператор return
- •8.3.Оператор break
- •8.4.Оператор continue
- •Функция strcpy()
- •2. Функция strcat().
- •3. Функция strcmp()
- •12. Функция strlen().
- •Лекция 11
- •Лекция 12
- •Лекция 14
Лекция 14
Введение в функции.
Функция – это часть программы, которая выполняет какое-либо законченное действие. Самые простые программы содержат только одну функцию main(), которая определяет точку входа в откомпилированную программу.
В общем случае программа на языке С++ - это совокупность функций.
Различают объявление и определение функции. Объявление (прототип) позволяет компилятору узнать имя функции, тип значения, возвращаемого функцией, и тип параметров, которые она может иметь. Компилятору нужно знать эту информацию до первого вызова функции. Единственная функция, которая не требует прототипа, это функция main(), поскольку она встроена в язык С++.
Прототип имеет следующий синтаксис:
<тип функции><имя функции>(<список формальных параметров>);
Здесь <тип функции> - это любой тип, за исключением массива. Если функция не возвращает никакого значения, необходимо указать void.
В качестве имени функции можно использовать любой идентификатор, который ещё на задействован в программе. В списке формальных параметров перечисляются через запятую спецификации вида:
<тип><имя параметра>
или
<тип><имя параметра> = <умалчиваемое значение>
Если функция не имеет параметров, то список либо отсутствует, но скобки остаются, либо указывается слово void.
В конце прототипа ставится “;”
Примеры прототипов функций.
void print ( int value );
float min ( float x, float y );
int sqr( int x );
float max ( float, float y ); // опустили имя
void write (void);
Определение функции, кроме объявления, содержит тело функции. Синтаксис определения функции:
<тип функции><имя функции>(<список формальных параметров>){ <тело функции>}
Здесь <тело функции> - это либо составной оператор, либо блок. Если функция не выполняет никаких действий, то телом функции является { }.
Имя функции со списком формальных параметров называется сигнатурой.
Следует заметить, что в отличие от прототипа, в определении функции в списке формальных параметров нужно указывать их имена.
Определение функции можно разместить после главной функции в том же файле, а можно сохранить в отдельном файле, а затем подключить этот файл с помощью препроцессорной директивы:
#include “<имя файла>”
Возврат из функции к инициатору её вызова осуществляется при обнаружении закрывающей фигурной скобки или с помощью оператора return, который имеет две формы:
return <выражение> ;
или
return ;
Здесь <выражение> - это возвращаемой функцией значение. Тип возвращаемого значения определяется типом функции. Если функция имеет тип void , то <выражение> в операторе return опускается. Можно опустить и сам оператор.
В теле функции может быть несколько операторов return. Оператор return можно использовать в главной функции main(). Если тип возвращаемого ею результата отличен от void, то при благоприятном завершении программы возвращается значение 0, в противном случае – не 0.
Примеры определений функций.
float min ( float x, float y )
{ if ( x < y ) return x; // два оператора return
else return y;
}
int sqr ( int x )
{ return x*x ; // один оператор return
}
void print ( int value )
{ cout << “\n” << value; // нет оператора return
}
Вызов функции выполняется с помощью конструкции
<имя функции>(<список фактических параметров>);
Здесь <имя функции> - это имя функции из ее заголовка;
<список фактических параметров> - это совокупность аргументов, перечисленных через запятую. Под аргументом пока будем понимать выражение.
Рассмотрим механизм активизации функции на примере.
Создадим программу, включающую объявление и определение функции box(), вычисляющей объем параллелепипеда, и главную функцию main(), в теле которой организуем многократный вызов функции box().
#include <iostream.h>
void box( int length, int width, int height);
void main()
{ box (7,20, 4);
box (50,3,2);
box (8,6,9);
}
void box( ( int length, int width, int height)
{
cout << “Объем параллелепипеда = “ << length*width*height << “\n”;
}
При вызове функции :
формальным параметром присваиваются значения аргументов;
выполняются операторы тела функции;
управление передается конструкции, записанной в теле основной функции за конструкцией вызова функции.
Применение функций позволяет экономить память компьютера: каждая функция описывается в программе один раз, в то время как обращаться к ней можно многократно.
При вызове функции нужно помнить следующее правила:
количество и тип фактических параметров (аргументов) должны строго соответствовать количеству и типу формальных параметров (параметров);
аргументы должны перечисляться в том же порядке, в каком перечислены соответствующие им параметры.
Следует заметить, что определение функции может также служить в качестве своего прототипа, если оно размещено до первого её использования в программе. Например, можно написать следующий вариант программы:
#include <iostream.h>
int box( int length, int width, int height)
{
return length*width*height;
}
void main()
{
int answer;
answer = box( 10,11,3);
cout << “объем параллелепипеда = ” << answer;
}
Здесь функция box() определена до её использования в функции main(). Таким образом, её определение служит и ее прототипом, поэтому нет необходимости в отдельном включении прототипа в программу.
Обычно всё же проще объявить прототипы для всех функций, используемых в программе, вместо определения до их вызова. Особенно это касается больших программ, в которых трудно отследить последовательность вызова одних функций другими. Более того, возможны ситуации, когда две функции вызывают друг друга. В этом случае прототипы необходимы.
Области видимости функций
Правила действия областей видимости любого языка программирования позволяют управлять доступом к объекту из различных частей программы. В С++ определены две основные области видимости: локальная и глобальная.
Локальная область видимости создается блоком. Переменная, объявленная внутри блока, называется локальной. Локальные переменные не доступны вне блока. Локальные переменные существуют только во время выполнения программного блока, в котором они объявлены. Это значит, что локальная переменная создается при входе в блок и разрушается при выходе из него.
Тело функции является программным блоком, который начинается с “{“ и завершается “}”. Каждая функция определяет собственную область видимости.
Пример.
#include <iostream.h>
void f(); // прототип функции
void main( )
{ int value = 10; // локальная по отношению к main()
cout << “ Значение value в функции main():” << value << “|n”;
f();
cout << “ Значение value в функции main():” << value << “|n”;
}
void f() // определение функции
{ int value = 88; // локальная в функции f()
cout << “ Значение value в функции f():” << value << “|n”;
}
Результат:
Значение value в функции main() : 10
Значение value в функции f() : 88
Значение value в функции main() : 10
Каждая переменная value известна только своему блоку.
Локальные переменные можно объявлять в любой части блока, главное, чтобы это произошло до её использования.
Например :
void main()
{ cout << “Введите первое число” ;
int a;
cin >> a;
cout << “Введите второе число”;
int b;
cin >> b;
cin << “a*b=” << a*b << ‘\n’;
}
Если имя переменной, объявленной во внутреннем блоке, совпадет с именем переменной, объявленной во внешнем блоке, то внутренняя переменная переопределяет внешнюю в пределах видимости внутреннего блока.
Пример.
int main()
{ int i, j;
i = 10;
j = 100;
if ( j>0) {
int i; i = j/2;
cout << “Внутренняя переменная i :” << i << ‘\n’;
}
cout << “Внешняя переменная i :” << i << ‘\n’;
}
Результат:
Внутренняя переменная i:50
Внешняя переменная i:10
Формальные параметры функции существуют в пределах области видимости функции, они локальны по отношению к функции.
Поскольку локальные переменные известны только в пределах функции, то возникает вопрос: а как создать переменную, которую могли бы использовать сразу несколько функций ? Необходимо создать переменную в глобальной области видимости. Глобальная область видимости - это декларативная область, которая заполняет пространство вне всех функций.
Глобальные переменные известны на протяжении всей программы, и они поддерживают свои значения во время выполнения всего кода программы. Следовательно их область видимости – вся программа.
Глобальные переменные объявляют вне всех функций, например, до функции main(). Формально они должны быть определены до их первого использования.
Пример.
#include <iostream.h>
void f1();
void f2();
int count; // глобальная переменная
void main ()
{
int i; // локальная переменная
for ( i = 0; i < 3; i++)
{ count = i*2;
f1();
}
} // конец функции main(()
void f1()
{ cout << “count: “ << count; // доступ к глобальной переменной
cout << ‘\n’;
f2();
}
void f2()
{
int count; // локальная переменная
for (count=0; count<3; count++)
cout <<’.’;
}
Результат:
count : 0
.. . count: 2
.. . count: 4
...
В этом примере функция main() и функция f1() используют глобальную переменную count. Но в функции f2() объявляется локальная переменная count, которая внутри функции перекрывает глобальную и не оказывает на неё никакого влияния.
Глобальные переменные инициализируются по-умолчанию нулевыми значениями и полезны в тех случаях, когда в нескольких функциях используются одни и те же данные. Однако без особой необходимости следует избегать их использование, поскольку:
- они занимают память в течение всего времени выполнения программы и не только тогда, когда действительно необходимы;
- использование большого количества глобальных переменных может привести к ошибкам в программе;
- использование глобальной переменной вместо локальной делает функцию менее универсальной.
Вопросы
1. Конструкция
int f(char c,int k,float b);
является:
1. заголовком функции;
2. определением функции;
3. прототипом;
4. сигнатурой.
2. Задан текст программы
#include<iostream.h>
void f(int x=0, int y=100);
void main()
{f(10);}
void f(int x, int y)
{cout<<”x=”<<x<<”,y=”<<y<<”\n”;}
Укажите правильный результат:
1. x=0, y=100
2. x=10, y=0
3. x=10, y=100
4. x=0, y=10
5. x=10, y=10
3. Даны три фрагмента программ
int F(int a)
{…}
int c,d;
void main()
{…
c=F(d);
…
}
2) int F(int x)
{…}
int a;
void main()
{…}
3) int F (int x)
{int a;
…
}
В каком фрагменте переменная a является локальной?
1. 1;
2. 2;
3. 3.
Лекция 15
Передача указателей и массивов
в качестве аргументов функций.
Чтобы передать функции указатель, необходимо задать в списке формальных параметров параметр типа указатель. Фактическим параметром для него будет адрес объекта.
Пример.
#include <iostream.h>
void f(int *j); // параметр- указатель j на целое число
void main()
{ int i;
f(&i); // аргумент-указатель на целое число i
cout << i;
}
void f(int *j);
{ *j = 100;
}
В результате переменная i получит значение 100.
Если аргументом функции является массив, то при вызове такой функции ей передается только адрес первого элемента массива.
Существует два способа объявления формального параметра, который принимает в качестве значения указатель на массив.
1). Формальный параметр можно объявить как массив, тип и размер которого совпадет с типом и размером фактического массива.
Пример.
.
#include <iostream.h>
void display ( int mas[10]);
void main()
{ int t[10], i;
for ( i=0; i<10; i++)
t[i] = i;
display(t); // передаем функции массив
}
void display (int mas[10])
{ int i;
for ( i=0; i<10; i++)
cout << mas[i] << “ “;
}
Несмотря на то, что формальный параметр mas объявлен как целочисленный массив, компилятор автоматически преобразует его в указатель на целое число.
2). При передаче функции массива её формальный параметр можно объявить как указатель. Этот вариант чаще всего используется профессиональными программистами.
void display (int *mas) // указатель на целое число
{ int i;
for ( i=0; i<10; i++) cout << mas[i] << ‘ “;
}
Такой способ передачи параметра-массива основывается на том факте, что указатели можно индексировать.
Итак, если массив используется в качестве аргумента функции, то функции передается адрес этого массива. Это означает, что код функции может изменить реальное содержимое массива, используемого при вызове функции.
Пример.
#include <iostream.h>
void cube(int *n, int length); // n – адрес массива, length – длина его
/* функция возводит в куб элементы массива */
void main()
{ int i, nums[10];
for ( i=0; i<10; i++)
nums[i] = i+1;
count << “Исходное содержимое массива :”;
for (i=0; i<10; i++) cout << nums[i] << “ ‘;
cout << ‘\n’;
cube (nums,10); // передаем функции адрес массива nums
cout << “Изменненое содержимое :”;
for (i=0; i<10; i++) cout << nums[i] << “ “;
}
//Возводим в куб элементы массива
void cube( int *n, int length)
{ while (length) {
*n = (*n)*(*n)*(*n);
length--;
n++;
}
} // конец функции
Результат:
Исходное содержимое массива : 1 2 3 4 5 6 7 8 9 10
Измененное содержимое: 1 8 27 64 125 216 343 512 729 1000
Здесь элементы массива nums были изменены операторами тела функции cube(), поскольку ей передается адрес массива nums.
Передача функциям строк
Поскольку строка в С++ - это символьный массив, завершающийся нулевым байтом, то при передаче функции строки реально передается только указатель типа char* на начало этой строки.
Пример.
Определим функцию strInvert(), которая инвертирует регистр букв строки, т.е. заменяет строчные символы прописными, а прописные – строчными.
#include <iostream.h>
#include <string.h> // копирование strcpy()
#include <ctype.h> // функции над строками
void strInvert(char *str); // параметр – строка
void main()
{ char str[80]; // исходная строка
strcpy(str, “This Is A Test”);
strInvert(str); // преобразуем строку
cout << str; // вывод преобразованной строки
}
void strInvert(char *str)
{
while (*str) // пока не нулевой байт
{ if (isupper(*str)) // возвращает true, если буква верхнего регистра
*str = tolower(*str); // возвращает символ в нижнем регистре
else
if (islower(*str)) // возвращает true, если буква нижнего регистра
*str = toupper(*str); // возвращает символ в верхнем регистре
str++; // переход к следующему символу
} // конец while
} // конец функции
Результат:
tHIS iS a tEST
Возвращение функциями указателей
Функции могут возвращать указатели. Чтобы вернуть указатель, функция должна объявить его тип в качестве типа возвращаемого значения.
Например:
int *f(); // прототип функции f(), возвращающей указатель на целое число
Если функция возвращает указатель, то значение выражения в операторе return должно быть указателем.
Пример. Определим функцию get_substr(), возвращающую указатель на первую подстроку, которая совпадает с заданной. Если подстрока не найдена, то функция возвращает нулевой указатель.
#include <iostream.h>
char *get_substr( char *sub, char *str); // прототип
void main()
{ char *substr; // указатель на символ
substr = get_substr(“ab”, “cd_ablm”);
if (substr)
cout << “\nЗаданная подстрока найдена : “ << substr;
else
cout << “\nЗаданная подстрока не найдена : “;
}
char *get_substr(char *sub, char *str)
{ int i; // номер символа
char *p, *p2, *start;
for ( i=0; str[i]; i++)
{ p = &str[i];
start = p;
p2 = sub;
while (*p2 && *p2 == *p)
{ p++;
p2++;
}
/* если обнаружен конец p2-строки (т.е. подстроки), то искомая подстрока найдена */
if (!*p2)
return start; // указатель на начало подстроки
} // переход к следующему символу
return 0; // совпадение не обнаружено
}
Результат :
Заданная подстрока найдена: ablm
Рекурсивные функции
Функция называется рекурсивной, если в процессе выполнения составляющих ее операторов она обращается к себе.
Функция называется косвенно рекурсивной, если она содержит обращение к другой функции, включающей прямой или косвенный вызов первой.
Пример. Написать рекурсивную функцию вычисления к!
long fact ( int k)
{ if ( k>0 ) return 0;
If (k = =0 ) return 1;
return k*fact(k-1);
}
При выполнении правильно организованной рекурсивной функции осуществляется многократный переход от текущего уровня организации алгоритма к нижнему уровню до тех пор, пока не будет получено простое решение.
Например: требуется вычислить fact(3).
В этом примере простое решение появляется при n4=0.
Иногда удается рекурсивную процедуру сделать более компактной, чем итерационную.
Однако рекурсия требует больше времени и памяти при вычислениях.
Подставляемые функции
Обычно при вызове функции компилятор включает в код программы команду передачи управления на тело функции.
Если тело функции состоит из нескольких операторов и не требует большого объема памяти, то компилятор может включать код такой функции в каждое место вызова.
Такие функции называются подставляемыми.
Синтаксис определения подставляемой функции:
inline<тип><имя функции>(<список формальных параметров>)
<тело функции>
Пример:
inline float r ( float x, float y)
{ return sqrt (x*x + y*y);}
В некоторых реализациях компиляторов вводятся ограничения на подставляемые функции:
- функция не должна быть рекурсивной;
- функция не должна содержать операторы цикла, переключатели и т.д.
Вопросы
1.Для того, чтобы передать функции массив, необходимо в качестве аргумента указать
1.полное определение массива;
2.имя массива;
3.адрес первого элемента массива.
2.Для того, чтобы передать функции строку, необходимо в качестве аргумента указать
1.любой символ строки;
2.имя строки;
3.указатель на символ;
4.адрес первого символа строки.
Лекция 16
Передача аргументов функции
В языках программирования обычно реализуют два способа передачи аргументов функции: по значению и по ссылке.
При передаче аргументов по значению фактический параметр копируется во временную память и, следовательно, не может быть изменен в теле функции, Функция обрабатывает копию фактического параметра.
При передаче аргументов по ссылке функция обрабатывает сам аргумент, поскольку ей передается адрес аргумента, а не его значение. Это значит, что изменения, внесенные в формальный параметр в теле функции, изменяет сам аргумент.
Рассмотрим эти способы на примерах.
// Передача аргумента по значению.
#include <iostream.h>
int f ( int x );
void main()
{ int arg = 10.0;
cout << “Значение функции f(arg) = “ << f(arg) << “\n”;
cout << “Значение аргумента arg = “ << arg << “\n”;
}
int f( int x)
{ x = 2*x;
return x;
}
Результат:
Значение функции f(arg) = 20
Значение аргумента arg = 10
В этом примере аргумент arg сохранил своё значение при выходе из функции f().
Для организации передачи аргумента по ссылке используется ссылочный формальный параметр, который объявляется в заголовке функции с помощью знака ‘&’.
//Передача аргумента по ссылке
#include <iostream.h>
void f ( int &i) // &i – ссылочный прараметр
{ i = 10; }
// Значение 10 присваивается переменной, на которую ссылается i
void main()
{ int value = 1;
cout << “Исходное значение value :” << value << ‘\n’;
f (value); // передаем адрес переменной value
cout << “Новое значение value :” << value << ‘\n’;
}
Результат:
Исходное значение value: 1
Новое значение value : 10
Замечания.
В теле функции ссылочный параметр используется непосредственно, без ‘*’. i=10; эквивалентно по смыслу *i = 10;
При вызове функции аргумент записывается без знака ‘&’. f(value) ; эквивалентно по смыслу f(&value);
Функция может возвращать ссылку в качестве результата. Это означает, что она возвращает неявный указатель на значение, передаваемое ею в операторе return.
Пример.
# include <iostream.h>
int & f(); // возвращает ссылку на целое число
int value = 100; // глобальная переменная
void main()
{ cout << f() << ‘\n’;
/* вывести на экран значение, записанное по адресу, возвращаемому
функцией f() */
int x;
x = f();
/* переменной х присвоить значение по ссылке, которую возвращает
функция f() */
f() = 200;
/* по адресу, возвращаемому функцией f(), записать
значение 200 */
cout << f() << ‘\n’;
}
int &f()
{ return value; } // возвращает ссылку на value
Результат:
100
100
200
Замечание.
Нельзя возвращать ссылку на локальную переменную.
Например:
int &f()
{ int i = 10;
return i; } // ошибка
При завершении функции переменная i выйдет за пределы видимости и ссылка на неё будет не определена.
Перегрузка функций
В С++ несколько функций могут иметь одинаковые имена, но при условии, что их параметры будут различными. Такую ситуацию называют перегрузкой функций, а функции, которые в ней задействованы – перегруженными.
Перегруженные функции должны отличаться типами и (или) числом параметров.
Рассмотрим пример.
# include <iostream.h>
void f( int i ); // один целочисленный параметр
void f( int i, int j); // два целочисленных параметра.
void f( double k); // один параметр типа double
void main()
{ f(10); // вызов f(int )
f(10,20); // вызов f(int,int)
f(12.23); // вызов f(double)
}
void f( int i)
{ cout << “В функции f(int), i=” << i << ‘\n’;}
void f(int i, int j)
{ cout << “В функции f(int, int), i=” << i;
cout << “, j=” << j << ‘\n’;}
void f(double k)
{ cout << “В функции f(double), k=” << k << ‘\n’;}
Результат:
В функции f(int), i=10
В функции f(int,int), i=10, j=20
В функции f(double), k=12.23
В этом примере функция f( ) перегружается три раза. Компилятор обладает достаточной информацией, чтобы вызвать правильную версию функции.
В С++ предусмотрено автоматическое преобразование типов при перегрузке функций.
Например:
# include <iostream.h>
void f(int x);
void f(double x);
void main()
{ int i = 10;
double d = 10.1;
short s = 99;
float r = 11.5F;
f( i ); // вызов версии f(int)
f( d ); // вызов версии f( double )
// далее автоматическое преобразование типов
f( s ); // short => int и вызов f(int)
f( r ); // float => double и вызов f(double)
}
void f( int x ) {
cout << “В функции f(int): “ << x << “\n”;}
void f( double x) {
cout << “В функции f(double): “ << x << “\n”;}
Результат:
В функции f(int): 10
В функции f(double): 10.1
В функции f(int): 99
В функции f(double): 11.5
Однако важно понимать, что автоматические преобразования применяются только в случае, если нет непосредственного совпадения в типах параметра и аргумента.
Аргументы, передаваемые функции по умолчанию
В С++ можно формальному параметру присвоить значение в прототипе функции, которое автоматически будет использоваться, если при вызове функции не задается соответствующий аргумент.
Пример.
# include <iostream.h>
void myfunc( int x=0, int y=0);
void main()
{ myfunc(1,2);
myfunc(10);
mufunc();
}
void myfunc (int x, int y)
{ cout << “x=” << x << “,y=” << y << “\n”;}
Результат
x=1, y=2
x=10, y=100
x=0, y=100
Все параметры, которые принимают значения по умолчанию, должны быть расположены справа от остальных.
void f( int a = 1, int b) ; // неверно
Благодаря применению аргументов по умолчанию, программисту нужно указывать не все аргументы, а только те, которые имеют смысл для определенной ситуации.
Значения, передаваемые по умолчанию, должны быть заданы только один раз и причем при первом объявлении функции.
Передача аргументов по умолчанию применяется при перегрузке функций.
Пример.
Определим две версии стандартной функции strcat(): одна будет присоединять всё содержимое одной строки к концу другой, а вторая функция использует один аргумент – количество присоединяемых символов:
void mystrcat( char *s1, char *s2, int len);
void mystrcat( char *s1, char *s2);
Используя возможность передачи аргументов по умолчанию, можно создать только одну функцию:
# include <iostream.h>
# include <string.h>
void mystrcat( char *s1, char *s2, int len=0);
void main()
{ char str1[80]=”Это тест. ”;
char str2[80]=”’0123456789”;
mystrcat(str1,str2,5);
cout << str1 << ‘\n’;
strcpy(str1,”Это тест. ”);
mystrcat(str1,str2); // присоединяем всю строку, поскольку len=0
cout << str1 << ‘\n’;
}
void mystrcat( char *s1, char *s2, int len)
{ while (*s1) s1++; //находим конец строки
if ( len == 0) len = strlen(s2);
while (*s2 && len) {
*s1 = *s2; // копируем символы
s1++;
s2++;
len --;
}
*s1=’0\’; // добавляем нулевой байт
}
Результат
Это тест.01234
Это тест.0123456789
Вопросы
1.Для организации передачи аргумента по ссылке используется параметр
1.&;
2.*.
2.Перегруженные функции могут отличаться числом параметров
1.да;
2.нет.
3.Функция может возвращать ссылку на глобальную переменную
1.да;
2.нет.
Лекция 17
Ввод-вывод в языке С++
В языке С++ отсутствуют встроенные средства ввода-вывода. В связи с этим к программе необходимо подключать библиотеку ввода-вывода. с помощью директивы
# include <iostream.h>
При выполнении операции ввода осуществляется преобразование сигналов от клавиатуры в двоичные коды внутреннего представления данных. Операция вывода данных на экран дисплея выполняет преобразование двоичных кодов в символы.
Операция ввода на языке С++ имеет следующий формат:
сin >> <имя объекта базового типа>;
К базовому типу относятся: int, long, float, double, char и др.
Операция вывода имеет следующий формат:
cout << <выражение базового типа>;
Пример.
. . . .
{ int a; float b;
cin >> a;
cout << “\n a= “ << a;
cin >> b;
cout << “\n b= “ << b;
. . .
}
Особенности ввода и вывода данных
использование операций сдвига для ввода и вывода данных не изменяет их приоритет.
Например:
сout << 5+6*7-a;
Поскольку приоритет арифметических операций выше приоритета оператора <<, то скобки можно не использовать в операторе вывода.
Пример:
cout << (3+4>5);
Здесь нужны скобки, т.к. приоритет операции сравнения меньше, чем ранг оператора <<.
Для ввода последовательности значений можно использовать цепочки операций:
Например:
int i, j, k;
cin >> i >> j >> k;
3). При вводе и выводе массивов необходимо использовать циклы.
Например:
float a[5];
for ( int i=0; i<5; i++) cin >> a[i]; // ввод
for ( int i=0; i<5; i++) cout <<”\n”<< a[i]; // вывод
Рассмотрим особенности ввода и вывода целых чисел, вещественных чисел и строк.
4). При вводе и выводе целых чисел существует ограничение на длину внешнего и внутреннего представления.
Например:
a). long g;
cin >> g;
cout << “\n g= ” << g;
_______________________.
123456789 <enter>
Результат:
g=123456789
б). int i;
cin >> i;
cout << “\n i= ” << i;
.______________________
123456789 <enter>
Результат:
i = -13035 - неправильное значение
5). При вводе целых чисел их можно набирать на клавиатуре в десятичном, восьмеричном и шестнадцатеричном виде.
Например:
. . . .
{ int a;
cin >> a;
cout << “\n a= “ << a;
}
._____________________
1).077777<enter>
a= 32767
2). -0x7FFF <enter>
a = -32767
6). При вводе вещественных чисел допустимы все их формы записи.
Например:
. . . .
{ float pi;
cin >> pi;
cout << “\n pi= “ << pi
}
.______________________
<enter>
или
3.1415e0 <enter>
или
+3.1415e0 <enter>
или
0.3.415e+1 <enter>
Результат:
pi = 3.1415
7). Если вещественное значение слишком мало, то вывод происходит в экспоненциальном формате.
Например:
. . . .
{ float t;
cin >> t;
cout << “\n t= “ << t;
}
.____________________
0.0….01 <enter>
Результат:
t = 1e-23
8). Символьная строка – массив типа char, завершающийся нулевым байтом. При вводе строки с клавиатуры набираются символы до нажатия клавиши <enter>.
Например:
char line[81];
cin >> line;
cout << line;
.______________
abcdef
Результат:
abcdef
Замечание. При вводе строки с помощью оператора >> пробел заменяется нулевым байтом.
Оператор вывода << переносит строку на экран до нулевого байта.
При выводе данных допускается их форматирование.
Вопросы
1.Задан блок
{char s[10];
cin>>s;
cout<<s;
}
При вводе строки aaaa bbb на экране появится строка
1.aaaa bbb;
2.aaaa.
Лекция 18
Форматирование данных при выводе
При выводе чисел каждое из них занимает ровно столько позиций, сколько необходимо для его представления.
Напимер:
int i=1, j=2, k=5;
cout << “\n” << i << j << k;
Результат:
125
Для улучшения читаемости можно в операторе вывода включить пробелы:
cout << “\n” << i << “ “ << j << “ “ << k;
1 2 5
Вещественные числа по умолчанию выводятся на экран с фиксированной точкой.
Например:
cout << “\n 1.0 / 3.0 = ” << 1.0/3.0;
на экране появится:
/ 3.0 = 0.333333 (6 знаков по умолчанию)
Форматы представления выводимой информации могут быть изменены с помощью флагов форматирования. Флаги реализованы в виде отдельных битов целого числа типа long.
Например:
0х0001 - при таком значении флага операция ввода >> будет игнорировать пробелы.
0х0002 – вывод с выравниванием по левому краю.
0х0004 – вывод с выравниванием по правому краю ( по умолчанию).
0х0010 - десятичная система счисления.
0х0020 – восьмеричная система счисления.
0х0040 – шестнадцатеричная система счисления.
0х0100 – при выводе вещественных чисел обязательно печатать десятичную точку, даже
если дробная часть равна 0.
0х0400 – печатать знак + при выводе положительных чисел.
0х0800 – использовать для вывода вещественных чисел формат с плавающей точкой.
0х1000 – использовать формат с фиксированной точкой при выводе вещественных чисел.
Количество цифр в дробной части определяется заданной по умолчанию точностью
Флаги могут обрабатываться как по отдельности, так и группами (используют операцию ИЛИ ‘|’ )
Кроме флагов для управления форматом используются следующие функции:
char fill(); - возвращает текущий символ заполнения пустых позиций поля вывода;
char fill(char); - заменяет символ заполнения;
long flags(); - возвращает текущий набор битов флагов;
long flags(long); - устанавливает биты флагов;
long unsetf(long); - сбрасываются биты флагов;
int precision(); - возвращает текущее значение точности при выводе вещественных.чисел;
int precision(int); - устанавливает по значению n точность;
int width(); - возвращает min ширину поля вывода;
int width(int); - устанавливает ширину поля вывода.
Примеры.
void main()
{ int a, b;
cin >> a >> b;
cout.width (4);
cout << a << “ “;
cout.width (6);
cout << b;
}
._______________________
345 <enter>
Результат
void main()
{ float a, b;
cin >> a >> b;
cout.precision (2);
cout << a << “ “ << b;
}
._______________________
12.34567 <enter>
Результат:
15.35 12.35
void main()
{ float a=2.7689547;
cout << “\n a= “ << a << “\n”;
cout.flags(0x0800);
cout << a ;
}
Pезультат:
а=2.768955
2.768955е+00
Если внести изменения в строку установки флагов:
cout.flags(0x0800|0x0400);
Результат:
а = 2.768955
+ а = 2.768955е+00
void main()
{ int h=10;
cout << “\n h= “ << h << “\n”;
cout.flags(0x0020); // восьмеричный код
cout << h ;
}
Результат:
h=10
12
void main()
{ int h;
cin >> h;
cout << “\n h= “ << h << “\n”;
cout.width(4);
cout.fill(‘#’);
cout << h ;
}
.___________________________
<enter>
Результат:
12
##12
Следует отметить, что существует еще один способ изменения флагов с помощью манипуляторов. Манипулятор – это функция , вызов которой можно использовать в качестве правого операнда для операции ввода-вывода.
Различают манипуляторы без параметров и с параметрами.
Манипуляторы без параметров:
dec – установка флага десятичной с.с.
hex – шестнадцатеричной с.с
oct – восьмеричной с.с.
ws - извлечение из входного потока пробелов
endl – при выводе включается символ новой строки.
Например:
cout << 15 << hex << 15 << oct << 15 << dec << 15;
Результат
150xF01715
Манипуляторы с параметрами определены в файле iomanip.h
Примеры:
setprecision( int n) - задает точность представления вещественных чисел;
setw( int n) - задает min ширину поля вывода:
setfill( int n) - задает код символа-заполнителя;
resetiosflags( long l) - сбрасывает флаги.
Пример.
# include <iostream>h>
# include <iomanip.h>
void main()
{ cout << setprecision(3) << 12.345678;
cout << setw(4) << 12;
}
Результат:
12
В
опросы
1.Задана главная функция:
void main()
{ int h=100;
cout.width(8);
cout.fill(‘*’);
cout << h ;
}
На экран будет выведена строка
1.100*****
2.*****100