Студопедия

КАТЕГОРИИ:


Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748)

Приоритет переменных с файловой и локальной областями действия. 1 страница




Использование переменной с файловой областью действия.

Неопределенные символы в программе на С.

Многоточие (..).

Перегрузка (overloading).

Встраивание (inline).

Числа с плавающей точкой.

Целые числа.

Строки.

Функции типа double.

Функции типа float.

Функции типа long.

Функции типа int.

Функции типа char.

Функции типа void.

Массивы в качестве параметров.

Параметры в формате чисел двойной длины.

Параметры в формате чисел с плавающей точкой.

Целочисленные параметры.

Символьные параметры.

Аргумент типа void.

Формальные и фактические параметры.

Использование указателей для связи между функциями

14.7. Рекурсия.

14.8. Аргументы функции.

14.9. Возвращение значения функцией: оператор return.

14.10. Типы функций.

14.11. Аргументы функции main().

14.12. Важные возможности C++.

14.13. Сложности в правилах области действия (scope rules).

14.13.4. Проблемы области действия в C++.

14.13.5. Операция уточнения области действия в C++.

14.14. Равноправность функций в языке Си.

14.15. Компиляция программ, состоящих из двух или более функций.

 

10. Использование функций.

Функция — самостоятельная единица программы, спроектированная для реализации конкретной задачи. Функции в языке Си играют ту же роль, какую играют функции, подпрограммы и процедуры в других языках, хотя детали их структуры могут быть разными. Вызов функций приводит к выполнению некоторых действий. Например, при обращении к функции printf() осуществляется вывод данных на экран. Другие же функции позволяют получать некоторую величину, используемую затем в программе. К примеру, функция strlen() «сообщает» программе длину конкретной строки. В общем, функции могут выполнять различные действия и получать значения величин, используемых в программе.

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

7.25. Создание и использование простой функции.

Наша первая скромная цель — создание функции, которая печатает 65 символов» в ряд. Чтобы эта функция выполнялась в некотором контексте, мы включили ее в программу, которая печатает простой титул фирменного бланка. Ниже приведена полная соответствующая программа. Она состоит из функций main() и starbar().

 

/* титул фирменного бланка! */

#include<stdio.h>

#define NAME "MEGATHINK, INC."

#define ADDRESS "10 Megabuck Plaza"

#define PLACE "Megapolis, CA 94904"

void starbar();

void main()

{

starbar();

printf("%s\n", NAME);

printf("%s\n", ADDRESS);

printf("%s\n", PLACE);

starbar();

}

 

/* далее следует функция starbar() */

#define LIMIT 65

void starbar()

{

int count;

for (count=1; count<=LIMIT; count++)

putchar('*');

putchar('\n');

}

 

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

 

 

При рассмотрении этой программы необходимо обратить внимание на следующие моменты:

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

 

starbar();

 

Это одна из форм вызова функции, но далеко не единственная. При написании функции starbar() мы следовали тем же правилам, что и при написании main(): вначале указывается имя, затем идет открывающая фигурная скобка, приводится описание используемых переменных, даются операторы, определяющие работу функции, и, наконец, закрывающая фигурная скобка. Мы даже поместили перед описанием функции starbar() директивы #define и #include, требующиеся для нее, а не для функции main().

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

 

7.26. Прототипы функций.

Согласно стандарту ANSI С все функции должны иметь прототипы. Прототипы могут располагаться либо в самой программе на С или C++, либо в заголовочном файле. Большинство прототипов функций находятся в самих программах. Объявление функции в С и C++ начинается с ее прототипа. Прототип функции достаточно прост; обычно он включается в начало программы для того, чтобы сообщить компилятору тип и количество аргументов, используемых некоторой функцией. Использование прототипов обеспечивает более строгую проверку типов по сравнению с той, которая была при прежних стандартах С.

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

 

возвращаемый_тип имя_функции(тип_аргумевта(-ов)) (имя_аргумента(-ов));

 

Функция может иметь тип void, int, float и так далее и определяется возвращаемым типом. Имя_функции() — это любое значимое наименование, выбранное вами для определения этой функции.

 

7.27. Вызов по значению и вызов по ссылке.

В предыдущих примерах аргументы передаются функциям по значению. Когда переменные передаются по значению, в функцию передается копия текущего значения этой переменной. Поскольку передается копия переменной, сама эта переменная внутри вызывающей функции не изменяется. Вызов по значению — наиболее распространенный способ передачи информации (параметров) в функцию, и этот метод в С и C++ задан по умолчанию. Главным ограничением вызова по значению является то, что функция обычно возвращает только одно значение.

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

В результате выполнения операции & определяется адрес ячейки памяти, которая соответствует переменной. Если pooh — имя переменной, то &рooh — ее адрес. Можно представить себе адрес как ячейку памяти, но можно рассматривать его и как метку, которая используется компьютером для идентификации переменной. Предположим, мы имеем оператор

 

pooh = 24;

 

Пусть также адрес ячейки, где размещается переменная pooh, — 12126. Тогда в результате выполнения оператора

 

printf(%d %d\n", pooh, &pooh);

 

получим

 

24 12126

 

Более того, машинный код, соответствующий первому оператору, словами можно выразить приблизительно так: «Поместить число 24 в ячейку с адресом 12126».

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

 

/* контроль адресов */

#include<stdio.h>

void mikado(int);

void main()

{

int pooh = 2, bah = 5;

printf(" B main(), pooh = %d u &pooh = %u\n", pooh, &pooh);

printf(" B main(), bah = %d u &bah = %u\n", bah, &bah);

mikado(pooh);

}

 

void mikado(int bah)

{

int pooh = 10;

printf(" B mikado(), pooh = %d u &pooh = %u\n", pooh, &pooh);

printf(" B mikado(), bah = %d u &bah = %u\n", bah, &bah);

}

 

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

 

В main(), pooh = 2 и &pooh = 56002

В main(), bah = 5 и &bah = 50004

В mikado(), pooh = 10 и &pooh = 55994

В mikado(), bah = 2 и &bah = 56000

 

7.28. Указатели.

В языке Си имеются и переменные типа указатель. Точно так же как значением переменной типа char является символ, а значением переменной типа int — целое число, значением переменной типа указатель служит адрес некоторой величины. Если мы дадим указателю имя ptr, то сможем написать, например, такой оператор

 

ptr = &pooh; /* присваивает адрес pooh переменной ptr */

 

Мы говорим в этом случае, что ptr «указывает на» pooh. Различие между двумя формами записи: ptr и &pooh, заключается в том, что ptr — это переменная, в то время как &pooh — константа. В случае необходимости мы можем сделать так, чтобы переменная ptr указывала на какой-нибудь другой объект:

 

ptr = &bah; /* ptr указывает на bah, а не на pooh */

 

Теперь значением переменной ptr является адрес переменной bah.

 

7.29. Операция косвенной адресации: *.

Предположим, мы знаем, что в переменной ptr содержится ссылка на переменную bah. Тогда для доступа к значению этой переменной можно воспользоваться операцией «косвенной адресации» (*).

(Не путайте эту унарную операцию косвенной адресации с бинарной операцией умножения*.)

 

val = *ptr; /* определение значения, на которое указывает ptr */

 

Последние два оператора, взятые вместе эквивалентны следующему:

 

val = bah;

 

Использование операций получения адреса и косвенной адресации оказывается далеко не прямым путем к результату; отсюда и появление слова «косвенная» в названии операции.

Пример

 

nurse = 22,

ptr = &nurse, /* указатель на nurse */

val = *ptr;

 

Результатом выполнения этою фрагмента является присваивание значения 22 переменной val

 

7.30. Описание указателей.

Мы знаем, как описывать переменные типа int и других типов. Но как описать переменную типа «указатель»? На первый взгляд это можно сделать так:

 

pointer ptr; /* неправильный способ описания указателя */

 

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

 

int *pi; /* указатель на переменную типа целого */

char *pc; /* указатель на символьную переменную */

float *pf,*pg;/* указатели на переменные с плавающей точкой */

 

 

7.30.1. Использование указателей для связи между функциями

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

 

#include<stdio.h>

void interchange(int *,int *);

 

void main()

{

int x = 5, y = 10;

printf(" At the beginning x = %d and y = %d.\n", x, y);

interchange(&x,&y); /* передача адресов функции */

printf(" And now x = %d and y = %d.\n", x, y);

}

 

void interchange(int *u, int *v) /* u и v являются указателями */

{

int temp;

temp = *u; /* temp присваивается значение, на которое указывает u */

*u = *v;

*v = temp;

}

 

После всех встретившихся трудностей, проверим, работает ли этот вариант!

 

 

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

 

interchange(&x, &y);

 

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

 

interchange(u,v)

 

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

 

int *u, *v;

 

Далее в теле функции оператор описания

 

int temp

 

используется с целью резервирования памяти. Мы хотим поместить значение переменной х в переменную temp, поэтому пишем

 

temp = *u;

 

Вспомните, что значение переменной u — это &х, поэтому переменная и ссылается на х. Это означает, что операция *u дает значение х, которое как раз нам и требуется. Мы не должны писать, например, так:

 

temp = u; /* неправильно */

 

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

Точно так же, желая присвоить переменной у значение переменной х, мы пользуемся оператором

 

*u = *v;

 

который соответствует оператору

 

х = у;

 

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

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

 

function1(х);

 

происходит передача значения переменной х. Если же мы используем форму обращения

 

function2(&x);

 

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

 

function1(num)

int num;

 

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

 

function2(ptr)

int *ptr;

 

 

7.31. Рекурсия.

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

 

8*7*6*5*4*3*2*1= 40320

 

Необходимо внимательно выбирать тип данных, так как произведение растет очень быстро: факториал 15 равен 1307674368000.

 

/*08FACTR.C

Программа на С, использующая рекурсивные вызовы функции.

Вычисляет факториал числа.

Пример: 7! =7x6x5x4x3x2x1= 5040*/

 

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

using namespace std;

 

double dfactorial(double danswer);

 

main()

{

double dnumber=15.0;

double dresult;

dresult=dfactorial(dnumber);

printf("The factorial of %.0lf is: %.0lf\n",dnumber,dresult);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

double dfactorial(double danswer)

{

if(danswer <= 1.0)

return(1.0);

else

return(danswer*dfactorial(danswer-1.0));

}

 

Возникает рекурсия, так как внутри функции dfactorial() имеется вызов ее самой.

 

7.32. Аргументы функции.

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

Рассмотрим это более конкретно. В строке, состоящей из звездочек, 65 символов, а в строке MEGATHINK, INC. — 15. Поэтому в нашем первом варианте программы вслед за этим сообщением шло 50 пробелов. Чтобы сместить текст к центру, нужно сначала напечатать 25 пробелов, а потом текст, в результате чего слева и справа от данной фразы окажется по 25 пробелов. Следовательно, необходимо иметь возможность передать величину «25» функции, печатающей пробелы. Мы применяем тот же способ, что и при передаче символа '*' функции putchar(): используем аргумент. Тогда запись space(25) будет означать, что необходимо напечатать 25 пробелов. 25 — это аргумент. Мы будем вызывать функцию sрасе() три раза: один раз для каждой строки адреса. Вот как выглядит эта программа:

 

/* титул фирменного бланка2 */

#include<stdio.h>

#include<string.h>

#define NAME "MEGATHINK, INC."

#define ADDRESS " 10 Megabuck Plaza"

#define PLACE "Megapolis, CA 94904"

void starbar();

void space(int);

void main()

{

int spaces;

starbar();

space(25); /* space() использует в качестве аргумента константу */

printf("%s\n", NAME);

spaces = (65 - strlen(ADDRESS))/2;

/* мы заставляем программу вычислять, сколько пропустить пробелов */

space(spaces); /* аргументом является переменная */

printf("%s\n", ADDRESS);

space((65-strlen(PLACE))/2); /* аргументом является выражение */

printf("%s\n", PLACE);

starbar();

}

 

/* определение функции starbar() */

#define LIMIT 65

void starbar()

{

int count;

for (count=1; count<=LIMIT; count++)

putchar('*'); putchar('\n');

}

 

/* определение функции space() */

void space(int number)

{

int count; /* дополнительная переменная описывается после фигурной скобки */

for (count=1; count<=number; count++)

putchar(' ');

}

Обратите внимание на то, как мы экспериментировали при вызовах функции space(): мы задавали аргумент тремя различными способами. Являются ли все они работоспособными? Да — и вот доказательство.

 

 

Определение нашей функции начинается с двух строк:

 

space(number)

int number;

 

Первая строка информирует компилятор о том, что у функции space() имеется аргумент и что его имя number. Вторая строка — описание, указывающее компилятору, что аргумент number имеет тип int. Обратите внимание: аргумент описывается перед фигурной скобкой, которая отмечает начало тела функции. Вообще говоря, вы можете объединить эти две строки в одну:

 

space(int number;)

 

Независимо от формы записи переменная number называется «формальным» аргументом. Фактически это новая переменная, и в памяти компьютера для нее должна быть выделена отдельная ячейка.

Посмотрим, как можно пользоваться этой функцией.

Задача в данном случае состоит в том, чтобы присвоить некоторую величину формальному аргументу number. После того как эта переменная получит свое значение, программа сможет выполнить свою задачу. Мы присваиваем переменной number значение фактического аргумента при вызове функции. Рассмотрим наш первый случай использования функции space():

 

space(25);

 

Фактический аргумент здесь 25, и эта величина присваивается формальному аргументу — переменной number, т. е. вызов функции оказывает следующее действие:

 

number = 25;

 

Короче говоря, формальный аргумент — переменная в вызываемой программе, а фактический аргумент — конкретное значение, присвоенное этой переменной вызывающей программой.

 

7.32.1. Формальные и фактические параметры.

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

Если какая-то программа вызывает функцию, то она передает этой функции список параметров, называемый списком фактических параметров. Если программа соответствует стандарту ANSI С, то списки формальных и фактических параметров полностью совпадают, хотя на практике строгая проверка не выполняется.

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

 

printf("This is hexadecimal %x and octal %o",ians);

 

В данном примере функции printf() передается только один параметр, хотя ожидаются два. Если список параметров неполон, то недостающие параметры инициализируются произвольными значениями. В C++ эта проблема отчасти решена: в списке формальных параметров можно указывать значения по умолчанию.

 

7.32.2. Аргумент типа void.

В соответствии с ANSI С, отсутствие списка аргументов функции должно быть указано явно при помощи ключевого слова void. В C++ использование void пока не обязательно, но считается целесообразным. В следующей программе имеется простая функция voutput(), не имеющая параметров и не возвращающая никакого значения. Функция main() вызывает voutput(). При выходе из voutput() управление возвращается функции main(). Трудно придумать более простую функцию

 

/*08FVOID.C

Программа на С печатает сообщение при помощи функции.

В функции используются параметр типа void и стандартная

библиотечная функция С sqrt()*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

using namespace std;

 

void voutput(void);

 

main()

{

/* Программа определяет квадратный корень */

printf("This programm will find the square root\n\n\n");

voutput();

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

void voutput(void)

{

double dt=12345.0;

double du;

du=sqrt(dt);

printf("The squre root of %lf is %lf\n",dt,du);

}

 

Обратите внимание, что функция voutput() вызывает библиотечную функцию С, называемую sqrt(). Прототип sqrt() находится в файле math.h. У функции один параметр в формате числа двойной длины, и возвращает она результат извлечения квадратного корня тоже в виде числа двойной длины.

 

7.32.3. Символьные параметры.

Функции можно передавать символьные значения. В следующем примере в функции main() одиночный символ считывается с клавиатуры и передается функции voutput(). Символ считывается функцией getch(). В стандартной библиотеке С имеются другие функции, тесно связанные с функцией getch(): getc(), getcharQ и getcheQ Эти функции можно использовать и в C++, однако во многих случаях предпочтительнее пользоваться cm. Функция getch() получает символ от стандартного устройства ввода (клавиатуры) и возвращает символьное значение, не отображая его на экране:

//08FCHAR.C

/*Программа на С считывает символ с клавиатуры, передает его функции

и печатает сообщение, использующее этот символ*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

using namespace std;

 

void voutput(char c);

 

main()

{

char cyourchar;

/* Введите один символ с клавиатуры */

printf("Enter one character from the keyboard. \n");

cyourchar=getch();

voutput(cyourchar);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

void voutput(char c)

{

int j;

for(j=0;j<=16;j++)

/* Введен символ... */

printf("The character typed is %c \n",c);

}

 

7.32.4. Целочисленные параметры.

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

//08FINT.C

/*Программа на С вычисляет значения на основании введенной длины.

Функция получает параметр типа int, введенный с

клавиатуры при помощи функции scanf()*/

#include "stdafx.h"

#include <iostream>

#include <conio.h>

#include <stdio.h>

#include <process.h>

#include <ctype.h>

#include <stdlib.h>

#include <math.h>

using namespace std;

 

void vside(int is);

 

main()

{

int iyourlength=0;

/* Введите с клавиатуры длину как целое число */

printf("Enter the length, as an integer from the keyboard. \n");

scanf("%d",&iyourlength);

vside(iyourlength);

 

printf ("\n\nPress any key to finish\n");

_getch();

return(0);

}

 

void vside(int is)

{

int iarea, ivolume,isarea;

iarea=is*is;

ivolume=is*is*is;

isarea=6*iarea;

/* Длина стороны равна */

printf("The lenth of a side is %d \n",is);

/* Квадрат будет иметь площадь */

printf("The square would have an area of %d \n",iarea);

/* Куб будет иметь объем */

printf("The cube would have a volume of %d \n",ivolume);

/* Площадь поверхности куба */

printf("The surface area of the cub would have a square of %d \n",isarea);

}

 

 

7.32.5. Параметры в формате чисел с плавающей точкой.

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




Поделиться с друзьями:


Дата добавления: 2015-01-03; Просмотров: 1576; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.313 сек.