Правила объявления переменных в программе 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Правила объявления переменных в программе



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

Простейшая форма определения переменных:

<тип> <список имен переменных>;

где <тип> - один из рассмотренных нами типов данных,

<список_имен_переменных> - список выбранных программистом идентификаторов, разделенных запятыми.

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

Примеры:

int i, j, k;

unsigned int iCount;

double Pi, d_Square;

char cSpace;

Обратите внимание на необходимость символа "точка с запятой" в конце каждого определения переменных.

Инициализация переменных

В соответствии с синтаксисом языка С, после определения в программе переменные по умолчанию имеют неопределенные значения. Надеяться на то, что они равны, например, 0, нельзя. Однако переменным можно присваивать начальные значения, явно указывая их в определениях:

<тип> <имя переменной>=<начальное значение>;

Этот прием программирования называется инициализацией. В отличии от присваивания значений, выполняющегося при выполнении программы, инициализация выполняется при выделении для переменной участка памяти. Примеры:

float pi=3.1415, coef=2.45;

unsigned int year=2006;

char plus='+';

 

Определение именованных констант

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

Для именования констант можно воспользоваться одним из трех приемов.

1. Использование перечислимых констант, определяемых через ключевое слово enum. Такой способ позволяет именовать только целые константы.

2. Использование ключевого слова const в операторе определения переменных:

const <тип> <имя>=<значение>;

Здесь const - квалификатор типа, указывающий, что определяемый объект имеет постоянное значение и доступен только для чтения.

Например,

const long MAX_VALUE=999999;

const double E=2.718282;

const T=366;

В последнем случае тип константы не указан вовсе - по умолчанию ей будет приписан тип int.

3. Использование директивы препроцессора #define.

#define EULER 2.718282 #define WORD "Слово"

Подробно рассмотрение этой директивы будет позднее.

Структура программы

Программа на языке C++ состоит из функций, описаний и директив препроцессора (с. 16). Одна из функций должна иметь имя main. Выполнение программы начинается с первого оператора этой функции.

Структура простейшей программы имеет вид:

1) Директивы компилятора

# include <имя подключаемого файла>

2) Главная функция программы

void main(void)

{

 

}

3) внутри функции main

- объявление использованных переменных тип имя переменной

- ввод исходной информации

- обработка данных

- вывод результата

Ввод/вывод информации

 

Основные функции форматированного ввода/вывода

int scanf (const char* format....) // ввод

int printf(const char* format....) // вывод

Для их использования необходимо подключить библиотеку <stdio.h>

# include <stdio.h>

 

Синтаксис функции printf

printf(«Управляющая строка», список параметров)

Функция printf возвращает число напечатанных символов

Список параметров перечисляется через запятую.

Управляющая строка состоит из:

- обычные символы, которые выводятся на экран

- управляющие символы

- спецификация преобразования, каждая из которых вызывает вывод на экран значения очередного элемента из списка параметров. Спецификация преобразования начинается всегда из символа % и имеет след. формат:

%[флаг][ширина поля][. точность ][h/l/L]тип

Тип может принимать одно из следующих значений

 

Код Формат
c d или i u o x (X) f е илиЕ g или G s p %   Символ Знаковое десятичное целое число Беззнаковое десятичное число Беззнаковое восьмиричное число Беззнаковое шестнадцатиричное число (х-строчные буквы,Х-прописные буквы) Значение с плавающей запятой в форме –цел.часть. дроб.часть Значение с плавающей запятой в форме –цел.часть. дроб.частье степень То же что и %е только не выводятся последние нули Строка символов Вывод указателя Выводит знак %

Флаг:

- Выведенное значение прижимается к левому краю(по умочанию вправо) %-20s
+ Перед числом обязательно выводитяс знак + или- %+d
Пробел Если выводится неотрц. число, то перед ним ставится пробел % 6.2f
  заполнение пустых позиций нулями %010d, %08.3f
# Вывод первого 0 для восьмеричных, 0x или 0X для 16-ых. Для всех форм с плавающей точкой гарантируется вывод символа десятичной точки. Для форм %g %G предотвращает удаление заключительных нулей. %#o, %#8.0f, %+#10.3E

 

Модификатор формата ширина представляется целым положительным числом и служит для указания минимального количества выводимых символов. Если количество символов выводимого значения меньше width, поле будет дополняться символами в соответствии с указанными флагами. Заметим, что значение width никогда не ограничивает выводимое значение.

Модификатор формата.точность используется для чисел с плавающей точкой. Точность представляется неотрицательным целым числом, следующим за точкой и задает либо количество символов, которое должно быть выведено, либо количество цифр в дробной части числа, либо количество значащих цифр. Так "%5.2f" определяет вывод вещественного числа в поле шириной пять символов с двумя цифрами после десятичной точки.

Модификаторы, представленные в описании строки формата перечнем {h | l | L}, используются для спецификации размера аргумента:

h short int(d, i, o, x, X) и short unsigned int (u)

l long int(d, i, o, x, X) и long unsigned int (u)

L long double (e,E,f,g,G)

Функция форматированного ввода информации scanf.

В целом функция вода scanf очень подобна на функцию printf. Она также использует строку, задающую необходимые форматные преобразования. Главное различие этих функций заключается в списке параметров. Функция printf использует имена переменных, константы и выражения. Функция scanf в качестве параметров использует только указатели на переменные, т.е. адреса заполняемых переменных. Подробно мы будем изучать указатели позднее, а пока постараемся воспользоваться функцией scanf на основании двух следующих простых правил:

- если вы хотите ввести значение для одного из основных типов переменной, перед именем переменной ставьте символ &;

- если читается строка в символьный массив, знак & не ставится.

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

Спецификаторы формата для функции scanf представляются следующей таблицей

 

type Результат - Интерпретирует ввод как
%c символ
%d десятичное целое число со знаком
%e, %f, %g число с плавающей точкой
%E,%G число с плавающей точкой
%i десятичное целое число со знаком
%o восьмеричное целое число без знака
%p указатель (адрес памяти)
%s строку; ввод начинается с 1-го не служебного символа и включает все символы до следующего служебного
%u десятичное целое число без знака
%x, %X шестнадцатеричное целое число без знака

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

Модификатор Значение
* Подавление присваивания - пропуск принимаемого значения
Цифры Максимальная ширина поля; ввод закончиться либо при обнаружении первого служебного символа, либо когда достигнута максимальная ширина поля
h, l, L %hd и %hi указывают, что значение поступает в тип short. %ho, %hx и %hu - в тип unsigned short. %ld и %li - в тип long. %lo, %lx и %lu - в тип unsigned long. %le, %lf и %lg в тип double. Использование L вместо l - long double. Отсутствие предполагает: d, i, o, x - в тип int, e, f, g - в тип float

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

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

При вводе следует набирать например, 567,212.

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

567,212 567, 212 567, 212

Функция возвращает число успешно прочитанных элементов. Если она не прочла никаких элементов - возвращается значение 0. Она возвращает EOF ("End of file") - специальную константу, значение которой определено в заголовочном файле stdio.h, в случае, когда поток заканчивается раньше, чем определены все специфицированные в вызове функции переменные.

А вот как выглядит та же программа с использованием библиотеки классов C++

#include <iostream.h>

int main()

{

int i;

cout << "Введите целое число\n”;

cin>> i;

cout <<"Вы ввели число " << i<< " \nспасибо!";

return 0; }

Заголовочный файл <iostream h> содержит описание набора классов для управления вводом/выводом В нем определены стандартные объекты-потоки cm для ввода с клавиатуры и cout для вывода на экран, а также операции помещения в поток <<и чтения из потока >>.

В дальнейшем изложении будут использоваться оба способа, но в одной программе смешивать их не рекомендуется

Тема 2. Язык программирования С/С++. Выражения и операции

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

(4 х 5) - 4 представляет значение 16.

Почленная интерпретация этого выражения - "взять число 4, умножить его на 5, из результата вычесть 4".

В языке С существует три типа выражений:

- математическое выражение, дающее численный результат;

- текстовое выражение, дающее строку символов;

- логическое выражение, дающее в результате 1 или 0 (интерпретируемые как "истина" или "ложь".

В зависимости от типа выражения в языке С используются те или иные операции.

Арность операции - это количество задействованных в операции операндов. Например

2 + 3 - бинарная (двуместная) операция, -4 - унарная (одноместная) операция.

Унарные операции

& операция получения адреса операнда

&c_Symb - адрес размещения в памяти значения переменной c_Symb.

* операция обращения по адресу (называют еще операцией разыменования (доступ по адресу к значению того объекта, на который указывает операнд).

- унарный минус (изменяет знак арифметического операнда).

+ унарный плюс (введен для симметрии с унарным минусом).

~ побитовое отрицание 0001 1100 à 1110 0011

! логическое отрицание 0 à 1, не 0 à 0.

++ увеличение на единицу (инкремент или автоувеличение), существует две формы:

префиксная - увеличение до использования

...

int result, arg=2;

result = ++arg;

после выполнения result примет значение 3.

постфиксная - увеличение после использования

...

int result, arg=2;

result = arg++;

после выполнения result примет значение 2.

-- уменьшение на единицу (декремент или автоуменьшение), также префиксная и постфиксная формы.

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

sizeof(char) = 1

sizeof(long) = 4

short Count; --- sizeof(Count) = 2

Бинарные операции

Делятся на следующие группы:

1 аддитивные и мультипликативные

2 сдвигов

3 поразрядные

4 операции отношений

5 логические

6 выбора компонента сложного объекта

7 операция "запятая"

8 скобки в качестве операций

Аддитивные и мультипликативные.

+ бинарный плюс - сложение арифметических операндов или сложение указателя с целым
- бинарный минус - вычитание арифметических операндов или вычитание указателей
* умножение операндов арифметического типа
/ деление операндов арифметического типа. При целочисленных операндах абсолютное значение результата округляется до целого. 20/3 = 6 и (-20)/3 = -6
% получение остатка от деления целочисленных операндов (деление по модулю). Знак остатка равен знаку делимого. Например: 14%3 = 2 и (-14)%3 = -2

Один нюанс, который вы должны запомнить.

float res;

res = 5/4;

Результат: res = 1.

Для того, чтобы посчитать "правильно", этот фрагмент программы должен быть

float res;

res = 5./4.;

Результат: res = 1.25.

Операции сдвига. Эти операции определены только для целочисленных операндов.

<< сдвиг влево битового представления левого операнда на число позиций равное значению правого операнда.

short res, Value = 12;

res = Value << 5;

12=0000 0000 0000 1100 - после операции 0000 0001 1000 0000 =0x180=256+128 = 384

12 * 25 = 12 * 32 = 384

>> сдвиг вправо битового представления левого операнда на число позиций равное значению правого операнда.

short res, Value = 1120;

res = Value >> 5;

1120 = 1024 + 96 = 1024 + 64 + 32 = 210 + 26 + 25 = 0000 0100 0110 0000

- после операции 0000 0000 0010 0011 =0x23=32+3 = 35

1120 / 25 = 1120 / 32 = 35

Поразрядные операции.

Выполняются над битовыми представлениями значений целочисленных операндов

& поразрядная конъюнкция (И)
| поразрядная дизъюнкция (ИЛИ)
^ поразрядное исключающее ИЛИ

Операция конъюнкция 0&0 = 0 1&0 = 0 0&1 = 0 1&1 = 1

Операция дизъюнкция 0&0 = 0 1&0 = 1 0&1 = 1 1&1 = 1

Операция поразрядное исключающее ИЛИ 0&0 = 0 1&0 = 1 0&1 = 1 1&1 = 0

Пример.

0000 0001 1100 1110

0110 0111 0110 1010

--------------------------

0000 0001 0100 1010 (&)

0110 0111 1110 1110 (|)

0110 0110 1010 0100 (^)

Операции отношений (сравнения).

< меньше, чем
> больше, чем
<= меньше или равно, чем
>= больше или равно, чем
== Равно
!= не равно

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

Результат операции целочисленный: 0 (ложь) или 1 (истина).

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

&& конъюнкция (И) арифметических операндов или отношений

|| дизъюнкция (ИЛИ) арифметических операндов или отношений

Результат 0 (ложь) или 1 (истина).

Примеры отношений и логических операций:

4 < 9 → 1

3 == 5 → 0

3!= 5 || 3==5 → 1

(3+4>5) && (3+5>4) && (4+5>3) → 1

Операции присваивания.

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

Существует одна простая операция присваивания и ряд составных.

Простое присваивание -

А = B*2; - присвоить переменной А результат вычисления выражения B*2.

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

X = XÅY; - тоже в записи составного присваивания X Å=Y;

В качестве символа Å могут быть использованы знаки операций: + - * / % << >> & | ^

Примеры. f += 5; d -=f*2; con ^=0xff71;

Операции выбора компонентов структурированного объекта.

Существует две операции (. и ->) которые мы будем рассматривать позже, вместе с определением самих структурированных объектов.

Запятая в качестве операции.

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

int x,y; y = (x=3, 3*x); (после операции х=3, y=9).

Скобки в качестве операций.

Круглые и квадратные скобки играют роль бинарных операций при вызове функций и индексировании элементов массивов.

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

<имя функции> (<список аргументов>)

где операндами служат <имя функции> и <список аргументов>.

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

<имя массива> [<индекс>]

здесь операнды <имя массива> и <индекс>

Условная операция (?:). Эта операция тернарная, то есть имеет три операнда. Ее формат:

операнд_1? операнд_2: операнд_3

Первый операнд может иметь арифметический тип или быть указателем. Он оценивается с точки зрения его эквивалентности нулю (операнд, равный нулю, рассматривается как false, не равный нулю — как true). Если результат вычисления операнда 1 равен true, то результатом условной операции будет значение второго операнда, иначе — третьего операнда. Вычисляется всегда либо второй операнд, либо третий. Их тип может различаться. Условная операция является сокращенной формой условного оператора i f (он рассмотрен на с. 40).

#include <stdio h>

int main(){

int a = 11, b = 4, max;

max = (b > a)? b:a;

printf("Наибольшее число. %d", max);

return 0; }

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

Наибольшее число 11

Другой пример применения условной операции. Требуется, чтобы некоторая целая величина увеличивалась на 1, если ее значение не превышает п, а иначе принимала значение 1:

i = (i < n)? i + 1: 1,

Приоритет операций. Порядок вычисления выражений.

Сейчас мы рассмотрели весь набор операций языка С. И остался не решенным такой вопрос: в какой последовательности применяются записанные в выражении операции?

Что будет результатом вычисления 4 + 3 * 5? 35 или 19?

Очевидно, предполагая определение языка С как "удобного" мы вправе ожидать получения 19. Однако откуда это следует?

Да, действительно результат будет 19 и следует это из системы приоритетов операций языка С. Каждой операции языка приписан определенный приоритет выполнения (ранг) и операции выполняются в порядке увеличения ранга: в первую очередь операции с приоритетом 1, потом 2 и т.д.

Если операций одного ранга в выражении несколько, то они выполняются в соответствии с правилом ассоцмативности либо слева направо (à), либо справа налево (ß). Если какой-либо знак операции появляется в таблице дважды (например *), то его первое вхождение (меньший ранг) соответствует унарной операции.

Составим таблицу приоритетов операций.

Ранг Операции
  () [ ] ->.
  ! ~ + - ++ -- & * (тип) sizeof
  * / % (мультипликативные бинарные)
  + - (аддитивные бинарные)
  << >> (операции поразрядного сдвига)
  < <= >= > (отношения)
  ==!= (отношения)
  & (поразрядная конъюнкция "И")
  ^ (поразрядное исключающее "ИЛИ")
  | (поразрядная дизъюнкция "ИЛИ")
  && (логическая операция "И")
  || (логическая операция "ИЛИ")
  ?: (операция условной трансляции)
  = += -= *= /= %= &= |= ^= <<= >>= (присвоения)
  , (операция "запятая")

Для работы с математическими выражениями используется встроенные функции, которые находятся в стандартной библиотеке (math.h) и приведены в таблице.

Функция Выполняемые действия
Abs(n) Возвращаемый модуль целого числа
fabs (x) Возвр. модуль вещественного числа
acos(x) asin(x) atan (x) atan 2(x) Arcos x Arsin x Arctg x Возвращаем arctg x/y
cos(x) sin(x) tan(x) exp(x) log(x) log10(x) pow(x,y) sqrt(x) floor() ceil fmod(x,y) modf   Cos x Sin x Tag x Степень числа е Натуральный логарифм Логарифм по основанию 10 Возводит число в степень Квадратный корень из числа Округляет вниз Округляет вверх Остаток от деления х на у разбивает число на целую и дробную часть

 

Преобразование типов

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

int x;

char ch;

float f;

void func(void)

{

ch = x; /* 1 */

x = f; /* 2 */

f = ch; /* 3 */

f = x; /* 4 */

}

В строке 1 левые (старшие) биты целочисленной переменной x обрубаются, оставляя в ch младшие 8 битов. Если х содержит число между 256 и 0, то ch и х будут иметь одинаковое значение. Иначе значение ch будет содержать только младший набор битов переменной х. В строке 2 х получает целую часть переменной f. В строке 3 f получает 8-битное целое число, хранящееся в ch, преобразованное к формату с плавающей точкой. В строке 4 f получает значение целочисленной переменной х, преобразованное к формату с плавающей точкой.

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

Следует помнить два важных момента, которые могут повлиять на переносимость создаваемого кода:

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

2) Преобразование из int в float или из float в double и тому подобное не добавляет точности. Такого рода преобразования только изменяют формат представления значения.

2. Преобразование типов в выражениях. Когда операнды различных типов смешиваются в выражениях, то происходит преобразование к одному типу. Компилятор преобразует все операнды «вверх», к типу большего операнда. Ниже описываются правила преобразования типов.

1) Все переменные типа char и short int преобразуются к типу int. Все переменные типа float – к типу double.

2) Если один из пары операндов имеет тип long double, другой операнд также преобразуется к long double.

3) Если один из пары операндов имеет тип double, другой операнд (кроме long double) также преобразуется к типу double.

4) Если один из операндов имеет тип long, другой операнд также преобразуется к long.

5) Если один из операндов имеет тип unsigned, другой операнд также преобразуется к типу unsigned.

В результате применения этих правил преобразования каждая пара операндов будет иметь тип и результат каждой операции будет совпадать по типу с операндами. Рассмотрим преобразование типов, показанное на рисунке 3.1.

Как показано на данной схеме сначала символ ch преобразуется к целому int, а вещественная переменная с одинарной точностью f преобразуется к типу double. Затем ch/i преобразуется к типу double, поскольку f*d имеет тип double. Конечный результат имеет тип double, поскольку оба операнда типа double.

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

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

или

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

где тип – это один из стандартных типов данных языка С или определяемый пользователем тип. Например, чтобы выражение x/2 имело тип floa t (остаток сохранится), следует написать:

(float) x/2;

или

float (x/2);

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

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

#include <stdio.h>

int main(void)

{

int i;

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

printf(“%d / 2 есть: %f\n”, i, (float) i/2);

return 0;

}

Без принудительного преобразования (float) будет вычисляться только целая часть, а благодаря (float) получим также и дробную часть.

 

Тема 3. Язык программирования С/С++. Представление основных управляющих структур

Алгоритм.

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

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

1 Графический

2 Вербальный –описательный

3 Псевдокод – частично формализованная запись алгоритма на естеств. языке.

4 Алгоритмический язык программирования.

Для представления алгоритма графически по ГОСТу используются след. символы:

1. Данные входные или выходные

 

2. Процесс – действия над данными

 

 

3. Предопределенный процесс – действия над данными, определенные в другом алгоритме(вызов функции)

 

 

4. Подготовка – описывается подготовка данных для выполнения повторяющихся действий.

 

 

5. Решение – запись логического выражения

 

 

6. Завершение – символ начала или конца алгоритма

 

 

7. Соеденитель(узел)

 

8. Линия –поток данных или передача управления

 

9. Комментарии

 

 

1)Символы в схеме д. б. расположены равномерно.

2) Символы должны быть одного размера. Если объем текста внутри символа превышает его размеры, то следует использовать символ комментарий.

Потоки данных и потоки управления показаны линиями. Направления слева-направо и сверху-вниз явл-ся стандартныыми. Нестандартные направления обозначены стрелками.

Следует избегать пересечения линий.

Разрыв линий

 

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

Следованием называется конструкция, представляющая собой последовательное выполнение двух или более операторов (простых или составных). Ветвление задает выполнение либо одного, либо другого оператора в зависимости от выполнения какого-либо условия. Цикл задает многократное выполнение оператора (рис. 1.3). Особенностью базовых конструкций является то, что любая из них имеет только один вход и один выход, поэтому конструкции могут вкладываться друг в друга произвольным образом, например, цикл может содержать следование из двух ветвлений, каждое из которых включает вложенные циклы (рис. 1.4).Какова бы не была глубина вложения, любая конструкция имеет один вход и один выход.

 



Поделиться:


Последнее изменение этой страницы: 2017-02-07; просмотров: 519; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.147.65.65 (0.153 с.)