Студопедия

КАТЕГОРИИ:


Архитектура-(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)

Т Е Х Н О Л О Г І Ї 9 страница




За замовчуванням усі значення, що виводяться, вирівнюються по правому краю: якщо ширина поля більше від значення, що виводиться, його буде вирівняно по правому краю поля. Щоб встановити вирівнювання по лівому краю, поставте знак "мінус" відразу після знаку %. Наприклад, рядок форматування %-10.2f забезпечить вирівнювання дійсного числа (з двома десятковими знаками у 10-символьному полі) по лівому краю. Розглянемо програму, у якій продемонстровано механізм використання специфікаторів ширини поля і вирівнювання по лівому краю.

#include <stdio.h> // Для введення/виведення

 

int main ()

{

printf ("|%11.6 f|\n", 123.23);

printf ("|%-11.6 f|\n", 123.23);

printf ("|%11.6 s|\n", "Привіт усім");

printf ("|%-11.6 s|\n", "Привіт усім");

 

getch (); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

123.230000 123.230000

Привіт Привіт

Існують два модифікатори команд форматування, які дають змогу функції printf () відображати короткі (short) і довгі (long) цілі. Ці модифікатори можуть застосовуватися до специфікаторів типу d, i, про, і, х і x. Модифікатор 1 повідомляє функцію printf () про довгий формат значення. Наприклад, рядок %ld означає, що повинно бути виведено довге ціле. Модифікатор h вказує на Додаток короткого формату. Отже, рядок %hu означає, що цілочисельне значення, що виводиться, має тип short unsigned.

Щоб позначити, що відповідний аргумент вказує на довге ціле, до специфікатора п можна застосувати модифікатор 1. Для вказівки на коротку цілу застосуєте до специфікатора п модифікатор h.

Якщо Ви використовуєте сучасний компілятор, який підтримує додані у 1995 році засоби роботи з символами широкого формату (двобайтовими символами), то можете задіювати модифікатор 1 стосовно специфікатора з, щоб повідомити про використання двобайтових символів. Окрім того, модифікатор 1 можна використовувати з командою формату s для виведення рядка двобайтових символів.

Модифікатор 1 можна також поставити перед командами форматування дійсних чисел е, Е, f, F, g і G. У цьому випадку він повідомить про виведення значення типу long double.

В.2.2. Використання функції scanf()

Функція scanf ()– це С-функція загального призначення введення даних з консольного пристрою. Вона може зчитувати дані всіх вбудованих типів і автоматично перетворить числа у відповідний внутрішній формат. Її поведінка багато в чому назад поведінці функції printf (). Загальний формат функції scanf () такий:

int scanf (const char * fmt_ string ,.);

Керівний рядок задається параметром fmt_ string, складається з символів трьох категорій:

● специфікаторів форматy;

● "пропускних" символів (пропуски, символи табуляції та порожнього рядка);

● символів, відмінних від "пропускних".

Функція scanf () повертає кількість введених полів, а під час виникнення помилки значення EOF (воно визначене у заголовку stdio.h).

Специфікатори формату ним передує знак відсотка (%) повідомляють, якого типу дане буде лічене наступним. Наприклад, специфікатор %s прочитає рядок, а %d ціле значення. Ці коди наведено в табл|. В.2.

Табл. В.2. Специфікатори формату функції scanf()

Код Значення
%c Зчитує один символ
%d Зчитує десяткове ціле
%i Зчитує ціле в будь-якому форматі (десяткове, вісімкове|, шістнадцяткове|)
Зчитує дійсне число
%f Зчитує дійсне число
%F Аналогічно коду програми %f (тільки С99)
%g Зчитує дійсне число
%o Зчитує вісімкове| число
%s Зчитує рядок
%x Зчитує шістнадцяткове| число
%p Зчитує покажчик
%n Приймає ціле значення, дорівнює кількості символів, зчитаних дотепер
%u Зчитує десяткове ціле без знаку
%[ ] Проглядає набір символів
%% Зчитує знак відсотка

Пропускні символи в рядку форматування примушують функцію scanf () пропустити один або декілька пропускних символів у вхідному потоці. Під пропускним символом маємо на увазі пропуск, символ табуляції або символ нового рядка. По суті, один пропускний символ у керівному рядку примусить функцію scanf () зчитувати, але не зберігати будь-яку кількість (нехай навіть нульове) пропускних символів до першої непропускної.

"Непропускний" символ у рядку форматування примушує функцію scanf () прочитати і відкинути відповідний символ. Наприклад, під час використання рядка форматування %d, %d функція scanf () спочатку прочитає ціле значення, потім прочитає і відкине кому і нарешті прочитає ще одне ціле. Якщо заданий символ не виявиться, робота функції scanf () буде завершена.

Всі змінні, що використовуються для прийому значень за допомогою функції scanf (), повинні передаватися за допомогою їх адрес. Це означає, що всі аргументи мають бути покажчиками на змінні. (Мова С не підтримує посилання або посилальні параметри.) Передача покажчиків дає змогу функції scanf () змінювати значення будь-якого аргументу. Наприклад, якщо потрібно рахувати цілочисельне значення у змінну count, використовується наступний виклик функції:

scanf (). scanf ("%d" & count);

Рядки звичайно зчитуються у символьні масиви, а ім'я масиву (без індексу) є адресою першого елемента у цьому масиві. Тому, щоб рахувати рядок у символьний масив address, використовують такий програмний код:

char address[80];

scanf ("%s", address);

У цьому випадку параметр address вже є покажчиком, і тому йому не потрібно передувати оператором "&".

Елементи вхідного потоку, що зчитуються функцією scanf (), мають бути розділені пропусками, символами табуляції або нового рядка. Такі символи, як кома, крапка з комою і тому подібне, не розпізнаються як роздільники. Це означає, що настанова

scanf ("%d%d" &r, &c);

прийме значення, введені як 10 20, але навідріз відмовиться від "блюда", поданого у вигляді 10,20.

Подібно до printf (), у функції scanf () специфікатори формату за порядком зіставляються із змінними, перерахованими у списку аргументів.

Символ "*", що знаходиться після знаку "%" і перед кодом формату, прочитає дані заданого типу, але заборонить їх присвоєння змінній. Отже, настанова

scanf ("%d%*c%d" &x, &y);

під час введення даних у вигляді 10/20 помістить значення 10 у змінну х, відкине знак ділення і привласнить значення 2 0 змінною у.

Команди форматування можуть містити модифікатор максимальної довжини поля. Він є ціле число, що розташовується між знаком "%" і кодом формату, яке обмежує кількість символів, що зчитуються для будь-якого поля. Наприклад, якщо виникає бажання прочитати у змінну str не більше 20 символів, використаємо таку настанову:

scanf ("%20 s", str);

Якщо вхідний потік містить більше 20 символів, то під час подальшого виконання операції введення зчитування почнеться з того місця, у якому "зупинився" попередній виклик функції scanf (). Наприклад, якщо (під час використання даного прикладу) вводиться такий рядок символів:

ABCDEFGHIJKLMNOPQRSTUVWXYZ

то у змінну str будуть прийняті тільки перші 20 символів (до букви 'Т'), оскільки команда форматування тут містить модифікатор максимальної довжини поля. Це означає, що решта символів, "UVWXYZ", не буде використана взагалі. У разі іншого виклику функції

scanf () scanf ("%s", str);

символи "UVWXYZ" помістилися б у змінній str. Внаслідок виявлення "пропускного" символу введення даних для поля може завершитися до досягнення максимальної довжини поля. У цьому випадку функція scanf () переходить до зчитування наступного поля.

Незважаючи на те, що пропуски, символи табуляції та нового рядка використовуються як роздільники полів, під час зчитування одиночного символу вони читаються подібно до будь-якого іншому символу. Наприклад, якщо вхідний потік складається з символів х у, то настанова

scanf ("%c%c%c" &а, &b, &c);

помістить символ х у змінну а, пропуск у змінну b і символ в у змінну c.

Функцію scanf () можна також використовувати як набір сканованих символів (scansei). У цьому випадку визначається набір символів, які можуть бути зчитані функцією scanf () і присвоєні відповідному масиву символів. Функція scanf () продовжує зчитувати символи і поміщати юс| у відповідний символьний масив доти, доки не трапиться символ, відсутній у заданому наборі. Після цього вона переходить до наступного поля (якщо таке є).

Для визначення такого набору необхідно помістити символи, що підлягають скануванню, у квадратні дужки. Відкриваюча квадратна дужка повинна знаходитися відразу за знаком відсотка. Наприклад, наступний набір сканованих символів вказує на те, що необхідне прочитати тільки символи x, y і z.

% [ XYZ ]

Відповідна набору змінна повинна бути покажчиком на масив символів. Під час повернення з функції scanf () цей масив міститиме рядок, що має завершальний нуль-символ, який складається з зчитаних символів. Наприклад, наведений нижче код програми використовує набір сканованих символів для зчитування цифр у масив s1. Якщо буде введений символ, відмінний від цифри, масив s1 завершиться нульовим символом, а решта символів зчитуватиметься в масив s2 доти, доки не буде введений наступний "пропускний" символ.

// Простий приклад використання набору сканованих символів.

#include <stdio.h> // Для введення/виведення

 

int main ()

{

char s1[80], s2[80];

printf ("Введіть числа, а потім декілька букв:\n");

scanf ("%[0123456789]%s", s1, s2);

printf ("%s %s", s1, s2);

 

getch (); return 0;

}

Багато компіляторів дають змогу за допомогою дефіса задати в наборі сканованих символів діапазон. Наприклад, у процесі виконання такої настанови функція scanf () прийматиме символи від А до z.

% [ A-z ]

При цьому в наборі сканованих символів можна задати навіть декілька діапазонів. Наприклад, ця програма зчитує спочатку цифри, а потім букви.

/* Демонстрація механізму використання в наборі сканованих символів

декількох діапазонів. */

#include <stdio.h> // Для введення/виведення

 

int main ()

{

char s1[80], s2[80];

 

printf ("Введіть числа, а потім декілька букв:\n");

scanf ("%[0-9]%[a-zA-z]", s1, s2);

printf ("%s %s", s1, s2);

 

getch (); return 0;

}

Якщо перший символ у наборі сканованих символів є знаком вставки (Л), то отримуємо зворотний ефект: дані, що вводяться, зчитуватимуться до першого символу із заданого набору символів, тобто знак вставки примушує функцію scanf () приймати будь-які символи, які не визначені в наборі. У наступній модифікації попередньої програми знак вставки використовують для заборони зчитування символів, тип яких вказано у наборі сканованих символів:

/* Демонстрація механізму використання набору сканованих символів для

заборони зчитування вказаних у ньому символів. */

#include <stdio.h> // Для введення/виведення

 

int main ()

{

char s1[80], s2[80];

 

printf ("Введіть не цифри, а потім не букви:\n");

scanf ("%[^0-9]%[^а-zA-z]", s1, s2);

printf ("%s %s", s1, s2);

 

getch (); return 0;

}

Важливо пам'ятати, що набір сканованих символів розрізняє прописні і рядкові букви. Отже, якщо виникає бажання сканувати як прописні, так і рядкові букви, задайте їх окремо.

Деякі специфікатори формату можуть використовувати такі модифікатори, які точно указують тип змінної, що приймає дані. Щоб прочитати довге ціле, поставте перед специфікатором формату модифікатор 1, а щоб прочитати коротке ціле модифікатор h. Ці модифікатори можна використовувати з кодами формату d, i, про, u, x і п.

За замовчуванням специфікатори f, е і g примушують функцію scanf () присвоювати дані змінним типу float. Якщо поставити перед одним з цих специфікаторів формату модифікатор 1, функція scanf () привласнить прочитане дане змінній типу double. Використання ж модифікатора L означає, що змінна, що приймає значення, має тип long, double.

Модифікатор 1 можна застосувати і до специфікатора з, щоб позначити покажчик на двобайтовий символ з типом даних whcar_t (якщо Ваш компілятор відповідає стандарту C++). Модифікатор 1 можна також використовувати з кодом формату s, щоб позначити покажчик на рядок двобайтових символів. Окрім того, модифікатор 1 можна використовувати для модифікації набору сканованих двобайтових символів.

В.3. С-система оброблення файлів

Незважаючи на те, що файлова система в C відрізняється від тієї, що використовується у мові програмування C++, між ними є багато загального. С-система оброблення файлів складається з декількох взаємопов'язаних функцій. Найбільш популярні з них перераховані в табл|. В.3.

Загальний потік, який "цементує" С-систему введення-виведення, є файловий покажчик (file pointer). Файловий покажчик це покажчик на інформацію про файл, яка містить його ім'я, статус і поточну позицію. По суті, файловий покажчик ідентифікує конкретний дисковий файл і використовується потоком, щоб повідомити всім С-функціям введення-виведення, де вони повинні виконувати операції. Файловий покажчик це змінна-покажчик типу FILE, який визначено у заголовку stdio.h.

Табл. А.3. С-функції оброблення файлів

Функція Призначення
fopen() Відкриває потік
fclose() Закриває потік
fputc() Записує символ у потік
fgetc() Зчитує символ з потоку
fwrite() Записує блок даних у потік
fread() Зчитує блок даних з потоку
fseek() Встановлює індикатор позиції файлу на заданий байт у потоці
fprintf() Робить для потоку те, що функція printf() робить для консолі
fscanf() Робить для потоку те, що функція scanf() робить для консолі ()
feof() Повертає значення true, якщо досягнуто кінець файлу
ferror() Повертає значення true, якщо виникла помилка
rewind() Встановлює індикатор позиції файлу у початок файлу
remove() Видаляє файл

В.3.1. Використання функції fopen()

Функція fopen () виконує три завдання.

● відкриває потік;

● пов'язує файл з потоком;

● повертає покажчик типу FILE на цей потік.

Найчастіше під файлом маємо на увазі дисковий файл. Функція fopen () має такий прототип:

FILE * fopen (const char * filename, const char *mode);

У цьому записі параметр filename вказує на ім'я файлу, що відкривається, а параметр mode- на рядок, що містить потрібний статус (режим) відкриття файлу. Можливі значення параметра mode показані у наведеній табл. В.4. Параметр filename повинен представляти рядок символів, які становлять ім'я файлу, яке допустимо у даній операційній системі. Цей рядок може містити специфікацію шляху, якщо діюче середовище підтримує таку можливість.

Табл. В.4. Допустимі значення параметра anode

mode Призначення
"r" Відкриває текстовий файл для зчитування
"w" Створює текстовий файл для запису
"а" Відкриває текстовий файл для запису у кінець файлу
"rb" Відкриває двійковий файл для зчитування
"wb" Створює двійковий файл для запису
"ab" Відкриває двійковий файл для запису у кінець файлу
"r+" Відкриває текстовий файл для зчитування і запису
"w+" Створює текстовий файл для зчитування і запису
" a+ " Відкриває текстовий файл для зчитування і запису у кінець файлу
"r+b" Відкриває двійковий файл для зчитування і запису
"w+b" Створює двійковий файл для зчитування і запису
"a + b" Відкриває двійковий файл для зчитування і запису у кінець файлу

Якщо функція fopen () успішно відкрила заданий файл, вона повертає покажчик FILE. Цей покажчик ідентифікує файл і використовується більшістю інших файлових системних функцій. Він не повинен піддаватися модифікації кодом програми. Якщо файл не вдається відкрити, повертається нульовий покажчик.

Як видно з табл. В.4, файл можна відкривати або в текстовому, або у двійковому режимі. Під час відкриття в текстовому режимі виконуються перетворення деяких послідовностей символів. Наприклад, символи нового рядка перетворяться у послідовності символів "повернення каретки" / "переведення рядка". У двійковому режимі подібні перетворення не виконуються.

Якщо виникає потреба відкрити файл test для запису, використаємо таку настанову.

fp = fopen ("test", "w");

У цьому записі змінна fp має тип FILE *. Проте часто для відкриття файлу використовують такий програмний код:

if ((fp = fopen ("test", "w"))== NULL) {

printf ("Не вдається відкрити файл.");

exit (1);

}

При такому методі виявляється будь-яка помилка, пов'язана з відкриттям файлу (наприклад, під час використання захищеного від запису або заповненого диска), і тільки після цього можна робити спробу запису у заданий файл. NULL це макроім'я, що є визначеним у заголовку stdio.h.

Якщо Ви використовуєте функцію fopen (), щоб відкрити файл виключно для виконання операцій виведення (записи), будь-який вже наявний файл із заданим ім'ям буде стертий, і замість нього буде створено новий. Якщо файл з таким ім'ям не існує, він буде створено. Якщо виникає потреба додавати дані у кінець файлу, використовується режим "а". Якщо опиниться, що вказано файл не існує, він буде створено. Щоб відкрити файл для виконання операцій зчитування, необхідна наявність цього файлу. Інакше функція поверне значення помилки. Нарешті, якщо файл відкривається для виконання операцій зчитування-запису, то у разі його існування він не буде видалений; але його немає, він буде створено.

В.3.2. Використання функції fputc()

Функція fputc () використовують для виведення символів у потік, заздалегідь відкрито для запису за допомогою функції fopen (). Її прототип має такий вигляд:

int fputc (int ch, FILE *fp);

У цьому записі параметр fp файловий покажчик, що повертається функцією fopen (), а параметр ch символ, що виводиться. Файловий покажчик повідомляє функції fputc (), в який дисковий файл необхідно записати символ. Незважаючи на те, що параметр ch має тип int, у ньому використовується тільки молодший байт.

При успішному виконанні операції виведення функція fputc () повертає записаний у файл символ, інакше значення EOF.

В.3.3. Використання функції fgetc()

Функція fgetc () використовують для зчитування символів з потоку, відкритого в режимі зчитування за допомогою функції fopen(). Її прототип має такий вигляд:

int fgetc (FILE *fp);

У цьому записі параметр fp файловий покажчик, що повертається функцією fopen (). Незважаючи на те, що функція fgetc () повертає значення типу int, його старший байт дорівнює нулю. Під час виникнення помилки або досягненні кінця файлу функція fgetc () повертає значення EOF. Отже, для того, щоб рахувати весь вміст текстового файлу (до самого кінця), можна використати такий програмний код:

ch = fgetc (fp);

while (ch!= EOF) {

ch = fgetc (fp);

}

В.3.4. Використання функції feof()

Файлова система у мові C може також обробляти двійкові дані. Якщо файл відкрито у режимі введення двійкових даних, то не виключено, що може бути зчитано ціле число, дорівнює значенню EOF. У цьому випадку під час використання такого коду програми перевірки досягнення кінця файлу, як ch!= EOF, буде створена ситуація, еквівалентна отриманню сигналу про досягнення кінця файлу, хоча насправді фізичний кінець файлу може бути ще не досягнутий. Щоб вирішити цю проблему, у мові C передбачена функція feof (), яка використовують для визначення факту досягнення кінця файлу під час зчитування двійкових даних. Її прототип має такий вигляд:

int feof (FILE *fp);

У цьому записі параметр fp ідентифікує файл. Функція feof () повертає ненульове значення, якщо кінець файлу був-таки досягнутий; інакше нуль. Таким чином, у процесі виконання такої настанови буде зчитаний весь вміст двійкового файлу:

while (! feof (fp)) ch = fgetc (fp);

Безумовно, цей метод застосовний і до текстових файлів.

В.3.5. Використання функції fclose()

Функція fclose () закриває потік, який був відкрито у результаті звернення до функції fopen (). Вона записує у файл усі дані, що ще залишилися у дисковому буфері, і закриває файл на рівні операційної системи. Під час виклику функції fclose () звільняється блок керування файлом, що є пов'язаним з потоком, що робить його доступним для повторного використання. Ймовірно, Вам відомо про існування обмеження операційної системи на кількість файлів, які можна тримати відкритими у будь-який момент часу, тому, перш ніж відкривати наступний файл, рекомендується закрити всі файли, вже непотрібні для роботи.

Функція fclose () має такий прототип:

int fclose (FILE *fp);

У цьому записі параметр fp файловий покажчик, що повертається функцією fopen (). При успішному виконанні функція fclose () повертає нуль; інакше повертається значення EOF. Спроба закрити вже закритий файл розцінюється як помилка. Під час видалення носія даних до закриття файлу згенерує помилка, як і у разі недоліку вільного простору на диску.

В.3.6. Використання функцій fopen(), fgetc(), fputc() і fclose()

Функції fopen (), fgetc (), fputc () і fclose () становлять мінімальний набір операцій з файлами. Їх використання продемонстровано у наведеному нижче коді програми, яка виконує копіювання файлу. Звернемо Вашу увагу на те, що файли відкриваються у двійковому режимі і що для перевірки досягнення кінця файлу використовується функція feof ().

Код програми В.1. Демонстрація копіювання вмісту одного файлу в іншій

#include <stdio.h> // Для введення/виведення

 

int main (int argc, char * argv [])

{

FILE * in, * out;

char ch;

 

if (argc!= 3) {

printf ("Bи забули ввести ім'я файлу.\n");

return 1;

}

 

if ((in = fopen (argv [1], "rb")) == NULL) {

printf ("Не вдається відкрити початковий файл.\n");

return 1;

}

 

if ((out = fopen (argv [2], "wb")) == NULL) {

printf ("Не вдається відкрити файл-приймач.\n");

return 1;

}

 

// Код копіювання вмісту файлу

while (! feof (in)) {

ch = fgetc (in);

if (! feof (in)) fputc (ch, out);

}

 

fclose (in);

fclose (out);

 

getch (); return 0;

}

В.3.7. Використання функції ferror() і rewind()

Функція ferror () використовують для визначення факту виникнення помилки у процесі виконання операції з файлом. Її прототип має такий вигляд:

int ferror (FILE *Јp);

У цьому записі параметр fp дійсний файловий покажчик. Функція ferror () повертає значення true, якщо у процесі виконання останньої файлової операції відбулася помилка; інакше значення false. Оскільки виникнення помилки можливе у процесі виконання будь-якої операції з файлом, функцію ferror () необхідно викликати відразу після кожної функції оброблення файлів; інакше інформацію про помилку можна просто втратити.

Функція rewind () переміщає індикатор позиції файлу у початок файлу, що задається як аргумент. Її прототип має такий вигляд:

void rewind (FILE *fp);

У цьому записі параметр fp дійсний файловий покажчик.

В.3.8. Використання функції fread() і fwrite()

У файловій системі мови С передбачено дві функції, fread () і fwrite (), які дають змогу зчитувати і записувати блоки даних. Ці функції подібні С++-функціям read () і write (). Їх прототипи мають такий вигляд:

size_t fread (void *buffer, size_t num_bytes,

size_t count, FILE * fp);

 

size_t fwrite (const void *buffer, size_t num_bytes

size_t count, FILE * fp);

Під час виклику функції fread () параметр buffer є покажчик на область пам'яті, яка призначена для прийому даних, що зчитуються з файлу. Функція зчитує count об'єктів завдовжки num_bytes з потоку, яка адресується файловим покажчиком fp. Функція fread () повертає кількість зчитаних об'єктів, яка може опинитися менше заданого значення count, якщо у процесі виконання цієї операції виникла помилка або був досягнуто кінець файлу.




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


Дата добавления: 2014-11-29; Просмотров: 386; Нарушение авторских прав?; Мы поможем в написании вашей работы!


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



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




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