Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
програмирование..doc
Скачиваний:
0
Добавлен:
01.03.2025
Размер:
612.86 Кб
Скачать

Лекция 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.

Примеры определений функций.

  1. float min ( float x, float y )

{ if ( x < y ) return x; // два оператора return

else return y;

}

  1. int sqr ( int x )

{ return x*x ; // один оператор return

}

  1. 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”;

}

При вызове функции :

    1. формальным параметром присваиваются значения аргументов;

    2. выполняются операторы тела функции;

    3. управление передается конструкции, записанной в теле основной функции за конструкцией вызова функции.

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

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

  1. количество и тип фактических параметров (аргументов) должны строго соответствовать количеству и типу формальных параметров (параметров);

  2. аргументы должны перечисляться в том же порядке, в каком перечислены соответствующие им параметры.

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

#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. Даны три фрагмента программ

  1. 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

Замечания.

  1. В теле функции ссылочный параметр используется непосредственно, без ‘*’. i=10; эквивалентно по смыслу *i = 10;

  2. При вызове функции аргумент записывается без знака ‘&’. 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;

. . .

}

Особенности ввода и вывода данных

  1. использование операций сдвига для ввода и вывода данных не изменяет их приоритет.

Например:

сout << 5+6*7-a;

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

Пример:

cout << (3+4>5);

Здесь нужны скобки, т.к. приоритет операции сравнения меньше, чем ранг оператора <<.

  1. Для ввода последовательности значений можно использовать цепочки операций:

Например:

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

}

.______________________

    1. <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;

на экране появится:

    1. / 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); - устанавливает ширину поля вывода.

Примеры.

  1. void main()

{ int a, b;

cin >> a >> b;

cout.width (4);

cout << a << “ “;

cout.width (6);

cout << b;

}

._______________________

  1. 345 <enter>

Результат

  1. void main()

{ float a, b;

cin >> a >> b;

cout.precision (2);

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

}

._______________________

    1. 12.34567 <enter>

Результат:

15.35 12.35

  1. 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

  1. void main()

{ int h=10;

cout << “\n h= “ << h << “\n”;

cout.flags(0x0020); // восьмеричный код

cout << h ;

}

Результат:

h=10

12

  1. void main()

{ int h;

cin >> h;

cout << “\n h= “ << h << “\n”;

cout.width(4);

cout.fill(‘#’);

cout << h ;

}

.___________________________

  1. <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;

}

Результат:

    1. 12

В опросы

1.Задана главная функция:

void main()

{ int h=100;

cout.width(8);

cout.fill(‘*’);

cout << h ;

}

На экран будет выведена строка

1.100*****

2.*****100