Лекции.ИНФО


Прежде чем двигаться дальше, не помешало бы поэкспериментировать с собственными вариациями на тему цикла for. Это вам поможет убедиться в его гибкости и могуществе.



Инструкция switch

Инструкция switch— это инструкция многонаправленного ветвления, которая позволяет выбрать одну из множества альтернатив.

Прежде чем переходить к изучению других циклических С++-конструкций, познакомимся с еще одной инструкцией выбора — switch. Инструкция switch обеспечивает многонаправленное ветвление. Она позволяет делать выбор одной из множества альтернатив. Хотя многонаправленное тестирование можно реализовать с помощью последовательности вложенных if-инструкций, во многих ситуациях инструкция switch оказывается более эффективным решением. Она работает следующим образом. Значение выражения последовательно сравнивается с константами из заданного списка. При обнаружении совпадения для одного из условий сравнения выполняется последовательность инструкций, связанная с этим условием. Общий формат записи инструкции switch таков.

switch(выражение) {

 case константа1:

  последовательность инструкций

  break;

 case константа2:

  последовательность инструкци

  break;

 case константа3:

  последовательность инструкций

  break;

 .

 .

 .

 default:

  последовательность инструкций

}

Элемент выражение инструкции switch должен при вычислении давать целочисленное или символьное значение. (Выражения, имеющие, например, тип с плавающей точкой, не разрешены.) Очень часто в качестве управляющего switch-выражения используется одна переменная.

Инструкция break завершает выполнение кода, определенного инструкцией switch.

Последовательность инструкций default-ветви выполняется в том случае, если ни одна из заданных case-констант не совпадет с результатом вычисления switch-выражения. Ветвь default необязательна. Если она отсутствует, то при несовпадении результата выражения ни с одной из case-констант никакое действие выполнено не будет. Если такое совпадение все-таки обнаружится, будут выполняться инструкции, соответствующие данной case-ветви, до тех пор, пока не встретится инструкция break или не будет достигнут конец switch-инструкции (либо в default-, либо в последней case-ветви).

Инструкции default-ветви выполняются в том случае, если ни одна из case констант не совпадет с результатом вычисления switch-выражения.

Итак, для применения switch-инструкции необходимо знать следующее.

■ Инструкция switch отличается от инструкции if тем, что switch-выражение можно тестировать только с использованием условия равенства (т.е. на совпадение switch-выражения с заданными case-константами), в то время как условное if-выражение может быть любого типа.

■ Никакие две case-константы в одной switch-инструкции не могут иметь идентичных значений.

■ Инструкция switch обычно более эффективна, чем вложенные if-инструкции.

■ Последовательность инструкций, связанная с каждой case-ветвью, не является блоком. Однако полная switch-инструкция определяет блок. Значимость этого факта станет очевидной после того, как вы больше узнаете о C++.

Согласно стандарту C++ switch-конструкция может иметь не более 16 384 case-инструкций. Но на практике (исходя из соображений эффективности) обычно ограничиваются гораздо меньшим их количеством.

Использование switch-инструкции демонстрируется в следующей программе. Она создает простую "справочную" систему, которая описывает назначение for-, if- и switch-инструкций. После отображения списка предлагаемых тем, по которым возможно предоставление справки, программа переходит в режим ожидания до тех пор, пока пользователь не сделает свой выбор. Введенное пользователем значение используется в инструкции switch для отображения информация по указанной теме. (Вы могли бы в качестве упражнения дополнить информацию по имеющимся темам, а также ввести в эту "справочную" систему новые темы.)

// Демонстрация switch-инструкции на примере простой "справочной" системы.

#include <iostream>

using namespace std;

Int main()

{

 int choice;

 cout << "Справка по темам:";

 cout << "1. for";

 cout << "2. if";

 cout << "3. switch";

 cout << "Введите номер темы (1-3): ";

  cin >> choice;

 cout << "";

 switch(choice) {

  case 1:

   cout << "for - это самый универсальный цикл в С++.";

   break;

  case 2:

   cout << "if - это инструкция условного ветвления.";

   break;

  case 3:

   cout <<"switch - это инструкция многонаправленного ветвления.";

   break;

  default:

   cout << "Вы должны ввести число от 1 до З.";

  }

 return 0;

}

Вот один из вариантов выполнения этой программы.

Справка по темам:

For

If

Switch

Введите номер темы (1-3) : 2

if - это инструкция условного ветвления.

Формально инструкция break необязательна, хотя в большинстве случаев использования switch-конструкций она присутствует. Инструкция break, стоящая в последовательности инструкций любой case-ветви, приводит к выходу из всей switch-конструкции и передает управление инструкции, расположенной сразу после нее. Но если инструкция break в case-ветви отсутствует, будут выполнены все инструкции, связанные с данной case-ветвью, а также все последующие инструкции, расположенные под ней, до тех пор, пока все-таки не встретится инструкция break, относящаяся к одной из последующих case-ветвей, или не будет достигнут конец switch-конструкции.

Рассмотрим внимательно следующую программу. Попробуйте предугадать, что будет отображено на экране при ее выполнении.

#include <iostream>

using namespace std;

Int main()

{

 int i;

 for(i=0; i<5; i++) {

  switch(i) {

   case 0: cout << "меньше 1";

   case 1: cout << "меньше 2";

   case 2: cout << "меньше 3";

   case 3: cout << "меньше 4";

   case 4: cout << "меньше 5";

  }

 cout << ' ';

 }

 return 0;

}

Вот как выглядят результаты выполнения этой программы.

Меньше 1

Меньше 2

Меньше 3

Меньше 4

Меньше 5

Меньше 2

Меньше 3

Меньше 4

Меньше 5

Меньше 3

Меньше 4

Меньше 5

Меньше 4

Меньше 5

Меньше 5

Как видно по результатам, если инструкция break в одной case-ветви отсутствует, выполняются инструкции, относящиеся к следующей case-ветви.

Как показано в следующем примере, в switch-конструкцию можно включать "пустые" case-ветви.

switch(i) {

 case 1:

 case 2:

 case 3: do_something();

  break;

 case 4: do_something_else();

  break;

}

Если переменная i в этом фрагменте кода получает значение 1, 2 или 3, вызывается функция do_something(). Если же значение переменной i равно 4, делается обращение к функции do_something_else(). Использование "пачки" нескольких пустых case-ветвей характерно для случаев, когда они используют один и тот же код.

Вложенные инструкции switch

Инструкция switch может быть использована как часть case -последовательности внешней инструкции switch. В этом случае она называется вложенной инструкцией switch. Необходимо отметить, что case-константы внутренних и внешних инструкций switch могут иметь одинаковые значения, при этом никаких конфликтов не возникнет. Например, следующий фрагмент кода вполне допустим.

switch(ch1) {

 case 'А': cout <<"Эта константа А - часть внешней инструкции switch";

  switch(ch2) {

   case 'A': cout <<"Эта константа A - часть внутренней инструкции switch";

    break;

   case 'В': // ...

  }

  break;

 case 'В': // ...

Цикл while

Инструкция while — еще один способ организации циклов в C++.

Общая форма цикла while имеет такой вид:

while(выражение) инструкция;

Здесь под элементом инструкция понимается либо одиночная инструкция, либо блок инструкций. Работой цикла управляет элемент выражение, который представляет собой любое допустимое С++-выражение. Элемент инструкция выполняется до тех пор, пока условное выражение возвращает значение ИСТИНА. Как только это выражение становится ложным, управление передается инструкции, которая следует за этим циклом.

Использование цикла while демонстрируется на примере следующей небольшой программы. Практически все компиляторы поддерживают расширенный набор символов, который не ограничивается символами ASCII. В расширенный набор часто включаются специальные символы и некоторые буквы из алфавитов иностранных языков. ASCII-символы используют значения, не превышающие число 127, а расширенный набор символов— значения из диапазона 128-255. При выполнении этой программы выводятся все символы, значения которых лежат в диапазоне 32-255 (32 — это код пробела). Выполнив эту программу, вы должны увидеть ряд очень интересных символов.

/* Эта программа выводит все печатаемые символы, включая расширенный набор символов, если таковой существует.

*/

#include <iostream>

using namespace std;

int main(){

 unsigned char ch;

 ch = 32;

 while(ch) {

  cout << ch;

  ch++;

 }

 return 0;

}

Рассмотрим while-выражение из предыдущей программы. Возможно, вас удивило, что оно состоит всего лишь из одной переменной ch. Но "ларчик" здесь открывается просто. Поскольку переменная ch имеет здесь тип unsigned char, она может содержать значения от 0 до 255. Если ее значение равно 255, то после инкрементирования оно "сбрасывается" в нуль. Следовательно, факт равенства значения переменной ch нулю служит удобным способом завершить while-цикл.

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

#include <iostream>

using namespace std;

Int main()

{

 int len;

 cout << "Введите длину строки (от 1 до 79): ";

  cin >> len;

 while(len>0 && len<80) {

  cout << '.';

  len--;

 }

 return 0;

}

Тело while-цикла может вообще не содержать ни одной инструкции. Вот пример:

while(rand() != 100);

Этот цикл выполняется до тех пор, пока случайное число, генерируемое функцией rand(), не окажется равным числу 100.

Цикл do-while

Цикл do-while — это единственный цикл, который всегда делает итерацию хотя бы один раз.

В отличие от циклов for и while, в которых условие проверяется при входе, цикл do-while проверяет условие при выходе из цикла. Это значит, что цикл do-while всегда выполняется хотя бы один раз. Его общий формат имеет такой вид.

do {

 инструкции;

}while(выражение);

Несмотря на то что фигурные скобки необязательны, если элемент инструкции состоит только из одной инструкции, они часто используются для улучшения читабельности конструкции do-while, не допуская тем самым путаницы с циклом while. Цикл do-while выполняется до тех пор, пока остается истинным элемент выражение, который представляет собой условное выражение.

В следующей программе цикл do-while выполняется до тех пор, пока пользователь не введет число 100.

#include <iostream>

using namespace std;

Int main()

{

 int num;

 do {

  cout << "Введите число (100 - для выхода): ";

  cin >> num;

 }while(num != 100);

 return 0;

}

Используя цикл do-while, мы можем еще более усовершенствовать программу "Угадай магическое число". На этот раз программа "не выпустит" вас из цикла угадывания, пока вы не угадаете это число.

// Программа "Угадай магическое число":

// 3-е усовершенствование.

#include <iostream>

#include <cstdlib>

using namespace std;

Int main()

{

 int magic; // магическое число

 int guess; // вариант пользователя

 magic = rand(); // Получаем случайное число.

 do {

  cout << "Введите свой вариант магического числа: ";

   cin >> guess;

  if(guess == magic) {

   cout << "** Правильно ** ";

   cout << magic <<" и есть то самое магическое число.";

  }

  else {

   cout << "...Очень жаль, но вы ошиблись.";

   if(guess > magic)

    cout <<" Ваш вариант превышает магическое число.";

   else cout <<" Ваш вариант меньше магического числа.";

  }

 }while(guess != magic);

 return 0;

}

Использование инструкции continue

Инструкция continue позволяет немедленно перейти к выполнению следующей итерации цикла.

В C++ существует средство "досрочного" выхода из текущей итерации цикла. Этим средством является инструкция continue. Она принудительно выполняет переход к следующей итерации, опуская выполнение оставшегося кода в текущей. Например, в следующей программе инструкция continue используется для "ускоренного" поиска чётных чисел в диапазоне от 0 до 100.

#include <iostream>

using namespace std;

Int main()

{

 int x;

 for(x=0; x<=100; x++) {

  if(x%2) continue;

  cout << x << ' ';

 }

 return 0;

}

Здесь выводятся только четные числа, поскольку при обнаружении нечётного числа происходит преждевременный переход к следующей итерации, и cout-инструкция опускается.

В циклах while и do-while инструкция continue передает управление непосредственно инструкции, проверяющей условное выражение, после чего циклический процесс продолжает "идти своим чередом". А в цикле for после выполнения инструкции continue сначала вычисляется инкрементное выражение, а затем— условное. И только после этого циклический процесс будет продолжен.

Использование инструкции break для выхода из цикла

Инструкция break позволяет немедленно выйти из цикла.

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

#include <iostream>

using namespace std;

Int main()

{

 int t;

 // Цикл работает для значений t от 0 до 9, а не до 100!

 for(t=0; t<100; t++) {

  if(t==10) break;

  cout << t <<' ';

 }

 return 0;

}

Эта программа выведет на экран числа от 0 до 9, а не до 100, поскольку инструкция break при значении t, равном 10, обеспечивает немедленный выход из цикла.

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

for(i=0; i<1000; i++) {

 // Какие-то действия.

 if(kbhit()) break;

}

Инструкция break приводит к выходу из самого внутреннего цикла. Рассмотрим пример.

#include <iostream>

using namespace std;

Int main()

{

 int t, count;

 for(t=0; t<100; t++) {

  count = 1;

  for(;;) {

   cout << count << ' ';

   count++;

   if(count==10) break;

  }

  cout << '';

 }

 return 0;

}

Эта программа 100 раз выводит на экран числа от 0 до 9. При каждом выполнении инструкции break управление передается назад во внешний цикл for.

На заметку. Инструкция break, которая завершает выполнение инструкции switch, влияет только на инструкцию switch, а не на содержащий ее цикл.

На примере предыдущей программы вы убедились, что в C++ с помощью инструкция for можно создать бесконечный цикл. (Бесконечные циклы можно также создавать, используя инструкции while или do-while, но цикл for — это традиционное решение.) Для выхода из бесконечного цикла необходимо использовать инструкцию break. (Безусловно, инструкцию break можно использовать и для завершения небесконечного цикла.)

Вложенные циклы

Как было продемонстрировано на примере предыдущей программы, один цикл можно вложить в другой. В C++ разрешено использовать до 256 уровней вложения. Вложенные циклы используются для решения задач самого разного профиля. Например, в следующей программе вложенный цикл for позволяет найти простые числа в диапазоне от 2 до 1000.

/* Эта программа выводит простые числа, найденные в диапазоне от 2 до 1000.

*/

#include <iostream>

using namespace std;

Int main()

{

 int i, j;

 for(i=2; i<1000; i++) {

  for(j=2; j<=(i/j); j++)

   if(!(i%j)) break; // Если число имеет множитель, значит, оно не простое.

  if(j > (i/j)) cout << i << " - простое число";

 }

 return 0;

}

Эта программа определяет, является ли простым число, которое содержится в переменной i, путем последовательного его деления на значения, расположенные между числом 2 и результатом вычисления выражения i/j. (Остановить перебор множителей можно на значении выражения i/j, поскольку число, которое превышает i/j, уже не может быть множителем значения i.) Если остаток от деления i/j равен нулю, значит, число i не является простым. Но если внутренний цикл завершится полностью (без досрочного окончания по инструкции break), это означает, что текущее значение переменной i действительно является простым числом.

Инструкция goto

Инструкция goto — это С++-инструкция безусловного перехода.

Долгие годы эта инструкция находилась в немилости у программистов, поскольку способствовала, с их точки зрения, созданию "спагетти-кода". Однако инструкция goto по-прежнему используется, и иногда даже очень эффективно. В этой книге не делается попытка "реабилитации" законных прав этой инструкции в качестве одной из форм управления программой. Более того, необходимо отметить, что в любой ситуации (в области программирования) можно обойтись без инструкции goto, поскольку она не является элементом, обеспечивающим полноту описания языка программирования. Вместе с тем, в определенных ситуациях ее использование может быть очень полезным В этой книге было решено ограничить использование инструкции goto рамками этого раздела, так как, по мнению большинства программистов, она вносит в программу лишь беспорядок и делает ее практически нечитабельной. Но, поскольку использование инструкции goto в некоторых случаях может сделать намерение программиста яснее, ей стоит уделить некоторое внимание.

Инструкция goto требует наличия в программе метки. Метка — это действительный в C++ идентификатор, за которым поставлено двоеточие. При выполнении инструкции goto управление программой передается инструкции, указанной с помощью метки. Метка должна находиться в одной функции с инструкцией goto, которая ссылается на эту метку.

Метка — это идентификатор, за которым стоит двоеточие.

Например, с помощью инструкции goto и метки можно организовать следующий цикл на 100 итераций.

х = 1;

 loop1:

  х++;

  if(х < 100) goto loop1;

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

for(...) {

 for(...) {

  while(...) {

   if(...) goto stop;

  }

 }

}

stop:

 cout << "Ошибка в программе.";

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

Важно! Инструкцию goto следует применять с оглядкой (как сильнодействующее лекарство). Если без нее ваш код будет менее читабельным или для вас важна скорость выполнения программы, то в таких случаях использование инструкции goto показано.

Итак, подведем итоги...

Следующий пример представляет собой последнюю версию программы "Угадай магическое число". В ней использованы многие средства С++-программирования, представленные в этой главе, и, прежде чем переходить к следующей, убедитесь в том, что хорошо понимаете все рассмотренные здесь элементы языка C++. Этот вариант программы позволяет сгенерировать новое число, сыграть в игру и выйти из программы.

// Программа "Угадай магическое число": последняя версия.

#include <iostream>

#include <cstdlib>

using namespace std;

void play(int m);

Int main()

{

 int option;

 int magic;

 magic = rand();

 do {

  cout << "1. Получить новое магическое число";

  cout << "2. Сыграть";

  cout << "3. Выйти из программы";

  do {

   cout << "Введите свой вариант: ";

    cin >> option;

  }while(option<1 || option>3);

  switch(option){

   case 1:

    magic = rand();

    break;

   case 2:

    play(magic);

    break;

   case 3:

    cout << "До свидания !";

    break;

  }

 }while(option != 3);

 return 0;

}

// Сыграем в игру.

Void play(int m)

{

 int t, x;

 for(t=0; t<100; t++) {

  cout << "Угадайте магическое число: ";

   cin >> x;

  if(x==m) {

   cout << "** Правильно **";

   return;

  }

  else

   if(x<m) cout << "Маловато.";

   else cout << "Многовато.";

 }

 cout << "Вы использовали все шансы угадать число. " << "Попытайтесь снова.";

}


Глава 5: Массивы и строки

В этой главе мы рассматриваем массивы. Массив (array) — это коллекция переменных одинакового типа, обращение к которым происходит с применением общего для всех имени. В C++ массивы могут быть одно- или многомерными, хотя в основном используются одномерные массивы. Массивы представляют собой удобное средство группирования связанных переменных.

Чаще всего используются символьные массивы, в которых хранятся строки. Как упоминалось выше, в C++ не определен встроенный тип данных для хранения строк. Поэтому строки реализуются как массивы символов. Такой подход к реализации строк дает С++-программисту больше "рычагов" управления по сравнению с теми языками, в которых используется отдельный строковый тип данных.

Одномерные массивы

Одномерный массивэто список связанных переменных. Для объявления одномерного массива используется следующая форма записи.

тип имя_массива [размер];

Здесь с помощью элемента записи тип объявляется базовый тип массива. Базовый тип определяет тип данных каждого элемента, составляющего массив. Количество элементов, которые будут храниться в массиве, определяется элементом размер. Например, при выполнении приведенной ниже инструкции объявляется int-массив (состоящий из 10 элементов) с именем sample.

int sample[10];

Индекс идентифицирует конкретный элемент массива.

Доступ к отдельному элементу массива осуществляется с помощью индекса. Индекс описывает позицию элемента внутри массива. В C++ первый элемент массива имеет нулевой индекс. Поскольку массив sample содержит 10 элементов, его индексы изменяются от 0 до 9. Чтобы получить доступ к элементу массива по индексу, достаточно указать нужный номер элемента в квадратных скобках. Так, первым элементом массива sample является sample[0], а последним — sample[9]. Например, следующая программа помещает в массив sample числа от 0 до 9.

#include <iostream>

using namespace std;

Int main()

{

 int sample[10]; // Эта инструкция резервирует область памяти для 10 элементов типа int.

 int t;

 // Помещаем в массив значения.

 for(t=0; t<10; ++t) sample[t]=t;

  // Отображаем массив.

  for(t=0; t<10; ++t)

   cout << sample[t] << ' ';

 return 0;

}

В C++ все массивы занимают смежные ячейки памяти. (Другими словами, элементы массива в памяти расположены последовательно друг за другом.) Ячейка с наименьшим адресом относится к первому элементу массива, а с наибольшим — к последнему. Например, после выполнения этого фрагмента кода

int i [7];

int j;

for(j=0; j<7; j++)i[j]=j;

массив i будет выглядеть следующим образом.

Для одномерных массивов общий размер массива в байтах вычисляется так:

всего байтов = размер типа в байтах х количество элементов.

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

#include <iostream>

#include <cstdlib>

using namespace std;

Int main()

{

 int i, min_value, max_value;

 int list [10];

 for(i=0; i<10; i++) list[i] = rand();

 // Находим минимальное значение.

 min_value = list[0];

 for(i=1; i<10; i++)

  if(min_value > list[i]) min_value = list[i];

 cout << "Минимальное значение: " << min_value << ' ';

 // Находим максимальное значение.

 max_value = list[0];

 for(i=1; i<10; i++)

  if(max_value < list[i]) max_value = list[i];

 cout << "Максимальное значение: " << max_value << '';

 return 0;

}

В C++ нельзя присвоить один массив другому. В следующем фрагменте кода, например, присваивание а = b; недопустимо.

int а[10], b[10];

// ...

а = b; // Ошибка!!!









Читайте также:

  1. A. Притяжения и отталкивания, силы отталкивания больше на малых расстояниях, чем силы притяжения. Б. Притяжения и отталкивания, силы отталкивания меньше на малых расстояниях, чем силы притяжения.
  2. B. 1. В США говорят по-английски. 2. Эта сумка сделана из кожи. 3. Окно разбито. 4. Владимир был построен в 10 веке. 5. Масло и сыр делают из молока. 6.Этот дом был построен моим дедом.
  3. D. Правоспособность иностранцев. - Ограничения в отношении землевладения. - Двоякий смысл своего и чужого в немецкой терминологии. - Приобретение прав гражданства русскими подданными в Финляндии
  4. D. ПРОЕКТ ДОГОВОРА ВОИС ПО УРЕГУЛИРОВАНИЮ СПОРОВ МЕЖДУ ГОСУДАРСТВАМИ В ОБЛАСТИ ИНТЕЛЛЕКТУАЛЬНОЙ СОБСТВЕННОСТИ
  5. I. Дополните предложения данными словами. Переведите предложения на русский язык.
  6. I. Наименование создаваемого общества с ограниченной ответственностью и его последующая защита
  7. I. Ультразвук. Его виды. Источники ультразвука.
  8. I. Характер отбора, лежавшего в основе дивергенции
  9. II. Вычленение первого и последнего звука из слова
  10. II. Однородные члены предложения могут отделяться от обобщающего слова знаком тире (вместо обычного в таком случае двоеточия), если они выполняют функцию приложения со значением уточнения.
  11. II. ПОЛИТИЧЕСКАЯ МЫСЛЬ ДРЕВНЕГО ЕГИПТА (по источнику «ПОУЧЕНИЕ ГЕРАКЛЕОПОЛЬСКОГО ЦАРЯ СВОЕМУ СЫНУ МЕРИКАРА»
  12. II. Приготовьтесь к проверочной работе на тему «Трудные слова»: запомните правописание слов и объясните их значение.


Последнее изменение этой страницы: 2016-03-17; Просмотров: 105;


lektsia.info 2017 год. Все права принадлежат их авторам! Главная