Студопедия — ПРАКТИЧЕСКАЯ ЧАСТЬ. Пример 1. Написать программу передачи частей структуры в качестве аргументов функции на примере подсчета суммы двух вещественных чисел
Студопедия Главная Случайная страница Обратная связь

Разделы: Автомобили Астрономия Биология География Дом и сад Другие языки Другое Информатика История Культура Литература Логика Математика Медицина Металлургия Механика Образование Охрана труда Педагогика Политика Право Психология Религия Риторика Социология Спорт Строительство Технология Туризм Физика Философия Финансы Химия Черчение Экология Экономика Электроника

ПРАКТИЧЕСКАЯ ЧАСТЬ. Пример 1. Написать программу передачи частей структуры в качестве аргументов функции на примере подсчета суммы двух вещественных чисел






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

Программный код решения примера

#include <stdio.h> #include <conio.h> #define MAX 20 // Шаблон структуры struct test { char A[MAX+1]; double ax; char B[MAX+1]; double by; }; //Прототип вспомогательной функции double sum(double, double); // Главная функция int main (void) { struct test AB; // создание новой структурной переменной //Заполнение полей структуры printf("\n\t Type 1 st name: "); gets_s(AB.A, MAX); printf("\t Enter the first real number: "); scanf_s("%lf", &AB.ax); _flushall(); printf("\n\t Enter 2 nd name: "); gets_s(AB.B, MAX); printf("\t Enter the second real number: "); scanf_s("%lf", &AB.by); printf("\n\t The sum of two numbers \ %1.2f and %1.2f, %c and %c: %1.2f\n", AB.ax, AB.by, AB.A, AB.B, sum(AB.ax, AB.by)); printf("\n Press any key: "); getch(); return 0; } // Функция суммирования двух чисел double sum(double x, double y) { return (x + y); }

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


Рис. 15.1. Сумма двух чисел, переданных в качестве аргументов функции

Задание 1

1. Одним из вводимых имен примите свое имя (имя пользователя).

2. Предусмотрите предварительный подсчет суммы двух чисел по возвращаемому значению функции sum().

3. Произведите инициализацию структуры в программе и передайте ее вещественные данные в функцию для подсчета их суммы.

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

5. В программе операцию «точка» замените на операцию «стрелка».

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

Для решения данного примера следует выполнить действия с комплексными числами, заданными в алгебраической форме [4].

Суммой двух комплексных чисел z 1 = x 1 + y 1 i и z 2 = x 2 + y 2 i называется число z = x + yi такое, что справедливы равенства х = х 1 + х 2, у = у 1 + у 2, т. е.

z = (x 1 + x 2) + (y 1 + y 2) i,

где i – мнимая единица.

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

Разностью чисел z 1 и z 2 называется число z такое, что z 1 = zz 2.

Правило вычитания. При нахождении разности z 1z 2 из действительной и мнимой частей уменьшаемого z 1 вычитаются соответственно действительная и мнимая части вычитаемого:

z = (x 1x 2) + (y 1y 2) i.

Произведением двух комплексных чисел z 1 = x 1 + y 1 i и z 2 = x 2 + y 2 i называется число z = x + yi такое, что выполняются равенства:

х = х 1 х 2у 1 у 2,

у = х 1 у 2 + х 2 у 1.

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


 

Частным от деления числа z 1 на z 2 (z 2 ≠ 0) называется число z такое, что справедливо равенство z × z 2 = z 1.

Правило деления. Чтобы разделить число z 1 на z 2 (z 2 ≠ 0), следует числитель и знаменатель дроби z 1/ z 2 умножить на число, сопряженное знаменателю. Комплексные числа называются сопряженными, если у них равны действительные части, а мнимые противоположны по знаку.

Программный код решения примера

#include <stdio.h> #include <conio.h> #include <locale.h> // Шаблон структуры struct comp { long double Re; long double Im; }; // Прототип функции с аргументами: // структура и симольная переменная void complex (struct comp ri[2], char op); int main (void) { long double x, y; char op; // Определение структурной переменной struct comp ri[2]; setlocale(LC_ALL, ".1251"); // для русских шрифтов //Для определения чисел с десятичной точкой setlocale(LC_NUMERIC, "English"); printf("\n\t ДЕЙСТВИЯ С КОМПЛЕКСНЫМИ ЧИСЛАМИ\n"); printf("\n Введите действительную часть 1-го комплексного числа: "); scanf_s("%lf", &x); _flushall(); ri[0].Re = x; printf(" Введите мнимую часть 1-го комплексного числа: "); scanf_s("%lf", &y); _flushall(); ri[0].Im = y; printf("\n Введите действительную часть 2-го комплексного числа: "); scanf_s("%lf", &x); _flushall(); ri[1].Re = x; printf(" Введите мнимую часть 2-го комплексного числа: "); scanf_s("%lf", &y); _flushall(); ri[1].Im = y; printf("\n Введите арифметический оператор: "); scanf_s("%c", &op, 1); _flushall(); //Вызов функции расчета комплексных чисел printf("\n Результат действия (\"%c\") над двумя комплексными числами\n (результат с десятичной запятой):", op); // Для русских шрифтов с числами с десятичной запятой setlocale(LC_ALL, ".1251"); complex (ri, op); //Для определения числа с десятичной точкой setlocale(LC_NUMERIC, "English"); //Вызов функции расчета комплексных чисел printf("\n Результат действия (\"%c\") над двумя комплексными числами\n (результат с десятичной точкой):", op); complex (ri, op); printf("\n Нажмите любую клавишу (Press any key): "); getch(); return 0; } // Вспомогательная функция void complex (struct comp ri[2], char z) { double num1, num2, den; // вспомогательные переменные // Выбор арифметического действия switch (z) { case '+': if ((ri[0].Im + ri[1].Im) >= 0) printf("\n\t %1.4f + %1.4fi\n", ri[0].Re + ri[1].Re, ri[0].Im + ri[1].Im); if ((ri[0].Im + ri[1].Im) < 0) printf("\n\t %1.4f - %1.4fi\n", ri[0].Re + ri[1].Re, -(ri[0].Im + ri[1].Im)); break; case '-': if ((ri[0].Im - ri[1].Im) >= 0) printf("\n\t %1.4f + %1.4fi\n", ri[0].Re - ri[1].Re, ri[0].Im - ri[1].Im); if ((ri[0].Im - ri[1].Im) < 0) printf("\n\t %1.4f - %1.4fi\n", ri[0].Re - ri[1].Re, -(ri[0].Im - ri[1].Im)); break; case '*': if ((ri[0].Re*ri[1].Im + ri[1].Re*ri[0].Im) >= 0) printf("\n\t %1.4f + %1.4fi\n",\ ri[0].Re * ri[1].Re - ri[0].Im*ri[1].Im, ri[0].Re*ri[1].Im + ri[1].Re*ri[0].Im); if ((ri[0].Re*ri[1].Im + ri[1].Re*ri[0].Im) < 0) printf("\n\t %1.4f - %1.4fi\n",\ ri[0].Re * ri[1].Re - ri[0].Im*ri[1].Im, -(ri[0].Re*ri[1].Im + ri[1].Re*ri[0].Im)); break; case '/': if (ri[1].Re!= 0 && ri[1].Im!= 0) { den = ri[1].Re*ri[1].Re + ri[1].Im*ri[1].Im; num1 = (ri[0].Re*ri[1].Re - ri[0].Im*(-ri[1].Im))/den; num2 = (ri[0].Re*(-ri[1].Im) + ri[1].Re*ri[0].Im)/den; if (num2 >= 0) printf("\n\t %1.4f + %1.4fi\n",num1, num2); if (num2 < 0) printf("\n\t %1.4f - %1.4fi\n",num1, -num2); } else printf("\n\t Ошибка! Деление на нуль.\n"); break; default: printf("\n\t Ошибка! Неизвестный оператор.\n"); break; } }


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

Рис. 15.2. Результат действия над двумя комплексными числами

Задание 2

1. Дополните программу вычислением модуля комплексного числа, полученного в результате произведенного арифметического действия.

2. Консольный вывод запишите в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

3. Напишите программу ввода комплексных чисел в виде одной строки, например (4 + 5.5 i) – первое вводимое число как строка, (2 – 3.3 i) – второе вводимое число как строка. Предусмотрите также арифметические действия над комплексными числами.

4. Напишите программу возведения комплексного числа в степень (см. формулу бинома Ньютона).


 

Пример 3. Написать программу имитатора случайного таймера с помощью указателей на структуру [2].

Программный код решения примера

#include <stdio.h> #include <conio.h> #include <time.h> #include <stdlib.h> // Глобальный шаблон структуры struct mtime { int hours; // часы int minutes; // минуты int seconds; // секунды }; // Прототипы вспомогательных функций void update (struct mtime *t); void display (struct mtime *t); // Главная функция int main (void) { int i; //Создание переменной структурного типа struct mtime systime; // Для изменения псевдослучайной последовательности srand((unsigned) (long)time(NULL)); // Начальная инициализация структурной переменной systime.hours = 0; systime.minutes = 0; systime.seconds = 0; // Цикл вывода расчетного времени for (i = 0; i < 10; ++i) { update(&systime); display(&systime); } printf("\n\n Press any key: "); getch(); return 0; } // 1-я вспомогательная функция void update (struct mtime *t) { // Заполнение полей структуры случайными числами t -> hours = (int)(24*rand()/RAND_MAX); t -> minutes = (int)(60*rand()/RAND_MAX); t -> seconds = (int)(60*rand()/RAND_MAX); // Условия расчетного времени t -> seconds += 1; if (t -> seconds == 60) { t -> seconds = 0; t -> minutes++; } if (t -> minutes == 60) { t -> minutes = 0; t -> hours++; } if (t -> hours == 24) t -> hours = 0; } // 2-я вспомогательная функция void display (struct mtime *t) { printf("\n System time: "); printf("%02d:", t -> hours); printf("%02d:", t -> minutes); printf("%02d\n", t -> seconds); }

В программе аргументами функций update() и display() являются указатели на структуру с дескриптором (этикеткой) mtime. При этом в главной функции main() создается структурная переменная systime по шаблону struct mtime и она передается в функции update() и display() через свой адрес, т. е. &systime. Так происходит 10 раз (в цикле).

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

void update (struct mtime *);

void display (struct mtime *);


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

Рис. 15.3. Пример вывода полей структуры на консоль


Задание 3

1. Проверьте работу программы без начальной инициализации полей структурной переменной systime.

2. Результат выполнения программы запишите в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

3. В программу добавьте нумерацию итераций цикла: 1), 2), ¼, 10).

4. Напишите программу по вводу своих фамилии, имени и подсчета в них количества букв. При этом создайте шаблон структуры с полями для имени, фамилии и количества букв. Ввод имени и фамилии должна выполнять одна функция, подсчет количества букв – вторая, печать результата – третья. Для связи между функциями примените указатели на структуру.

Пример 4. Написать программу, в которой используются функции, имеющие на входе структуру и возвращающие структуру.

Создадим программу расчета средней успеваемости студента за последнюю экзаменационную сессию (или другим экзаменам) с использованием структурного типа данных.

Программный код решения примера

#include <stdio.h> #include <conio.h> #define MAX 79 // Шаблон структуры struct table { char name[MAX+1]; char surname[MAX+1]; char subject_1[MAX+1]; char subject_2[MAX+1]; char subject_3[MAX+1]; char subject_4[MAX+1]; int mark[4]; float mean; } student = { // инициализация структурной переменной "Peter", "Bobrov", "Mathematics", "Informatics", "Programming", "Physics", {0,0,0,0}, 0.0f }; // Прототип вспомогательной функции struct table infor(struct table student); // Главная функция int main (void) { // Объявление и инициализация структурной переменной struct table infor2 = {" "," "," "," "," "," ", {0,0,0,0},0.0f}; infor2 = infor(student); // присвоение структуры от функции printf("\n The level of knowledge a student of %c %c is: \ %1.2f\n", infor2.name, infor2.surname, infor2.mean); printf("\n\n Press any key: "); getch(); return 0; } // Вспомогательная функция с аргументом структурного типа // и возвращающая структуру struct table infor(struct table student) { float x = 0.0f; int i; printf("\n\t Enter a name: "); gets_s(student.name, MAX); printf("\t Enter a surname: "); gets_s(student.surname, MAX); printf("\t Enter 1-st academic subject: "); gets_s(student.subject_1, MAX); printf("\t Enter a mark in the first subject: "); scanf_s("%d",&student.mark[0]); _flushall(); printf("\t Enter 2-nd academic subject: "); gets_s(student.subject_2, MAX); printf("\t Enter a mark in the second subject: "); scanf_s("%d",&student.mark[1]); _flushall(); printf("\t Enter 3-rd academic subject: "); gets_s(student.subject_3, MAX); printf("\t Enter a mark in the third subject: "); scanf_s("%d",&student.mark[2]); _flushall(); printf("\t Enter 4-th academic subject: "); gets_s(student.subject_4, MAX); printf("\t Enter a mark in the fourth subject: "); scanf_s("%d",&student.mark[3]); // Расчет средней оценки по 4 предметам for (i = 0; i < 4; ++i) { x += student.mark[i]; student.mean = x/4; } // Возвращение структурной переменной return (student); }

В программе приведена инициализация структурной переменной student для наглядности. Инициализация переменной типа float выполнена с суффиксом f. Присвоение одной структурной переменной другой может реализовано только в случае, когда они принадлежат одному и тому же шаблону структур. Функции _flushall() введены для того, чтобы устранить пустую строку перед использованием функции gets_s() (или gets()) после ввода с помощью функции scanf_s (или scanf()).


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

Рис. 15.4. Пример расчета средней успеваемости студента

Задание 4

1. Проверьте содержимое структурной переменной student.

2. Вместо структурной переменной student в аргументе вспомогательной функции используйте собственную фамилию.

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

4. В программу добавьте вывод в главной функции main() всех полей структуры.

5. Запишите результаты заполнения полей структуры в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

6. Проверьте работу программы без начальной инициализации структурной переменной.

7. Примените оператор typedef при создании шаблона структуры.

Пример 5. Написать программу, в которой функция возвращает указатель на структуру при поиске служебных слов языка С, вводимых с клавиатуры пользователем [3; 8].

Программный код решения примера

#include <stdio.h> #include <conio.h> #include <string.h> #define MAX 1000 // Функция ввода строки с клавиатуры void getLine(char str[], int m) { int c, i; for (i = 0; i < m-1 && (c = getchar())!= EOF && c!= '\n'; i++) str[i] = c; // После цикла str[i] = '\0'; // завершение символом окончания строки } // Создание структуры глобального типа struct key { char**keyword; //int keycount; } tab[] = { "for", "if", "do", "if", "else", "switch", "case", "break", "default" }, *bam;// указатель на структуру // Вспомогательная функция // с указателем на структуру key struct key *PTR_ANALYSE(char**word, struct key tab[], int n) { int i; struct key *PTR; for (i = 0; i < n; ++i) if (strcmp(tab[i].keyword, word) == 0) { PTR = &tab[i]; // возвращение указателя на структуру типа key return (PTR); } return NULL; // служебное слово не найдено } // Главная функция int main (void) { int c; char str[MAX]; printf("\n The analysis of input of syntactic words\n of the programming language C\n\n"); printf("\n The end of the session: press Ctrl+Z after pressing Enter\n\n"); // Цикл с постусловием do { printf("\t Enter a new line: "); getLine(str, MAX); printf(" "); bam = PTR_ANALYSE(str, tab, 9); // 9 - число слов if (bam!= NULL) printf("\t String found: %c\n press Enter to continue or Ctrl+Z to quit: ", bam->keyword); else printf("\t STRING NOT FOUND:\n press Enter to continue or Ctrl+Z to quit: "); } if ((c = getchar())!= EOF); printf("\n Press any key: "); getch(); return 0; }

В программе ввод слов осуществляется посимвольно с помощью специальной функции getLine(). Шаблон структуры – это struct key, для него определяется переменная tab[] как массив структур. Одновременно создается указатель на эту структуру *bam.

Функция struct key *PTR_ANALYSE() возвращает указатель на структуру. Параметрами этой функции являются указатель на тип char, массив структур и целая переменная. Цикл do – if применен для того, чтобы тело цикла выполнялось хотя бы один раз. Массив структур с именем tab[] инициализирован служебными словами – операторами управления. Результат выполнения функции struct key *PTR_ANALYSE() присваивается указателю *bam, который определен по шаблону глобальной структуры.

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


Рис. 15.5. Пример интерактивного поиска служебных слов

Задание 5

1. В программе используйте прототипы вспомогательных функций.

2. В качестве служебных слов задайте основные типы данных и их производных языка программирования С.

3. Дополните программу подсчетом количества символов служебных слов с выводом на консоль как самого слова, так и его длины.

4. Функцию анализа вводимых с клавиатуры слов напишите без дополнительного указателя на структуру типа key.

5. В программе предусмотрите копирование консольного содержания в текстовый файл с именем compX.txt, где Х – номер компьютера, на котором выполняется лабораторная работа.

Пример 6. Написать программу сравнения введенного целого числа с имеющимися целыми случайными числами одномерного массива на основе структурного типа данных и двоичного поиска (метода половинного деления) для упорядоченного массива.

Программный код решения примера

#include <stdio.h> #include <conio.h> #include <stdlib.h> #include <time.h> #include <locale.h> #define MAX 1000 // Функция ввода числа как строки с клавиатуры void getLine(int num[], int m) { int i, j, k; time_t tic; srand((unsigned) time(&tic)); for (i = 0; i < m; ++i) num[i] = (int)m*rand()/RAND_MAX; printf("\n\t The initial array of numeric data:\n"); for (i = 0; i < m; ++i) printf(" %3d", num[i]); puts(" "); // Сортировка массива по возрастанию for (i = 1; i < m; ++i) { for (j = 0; j < m-1; ++j) { if (num[j] > num[j+1]) { k = num[j]; num[j] = num[j+1]; num[j+1] = k; } } } printf("\t Assorted array of numerical data:\n"); printf(" "); for (i = 0; i < m; ++i) printf(" %3d", num[i]); puts(" "); } // Создание структуры глобального типа struct numb { int index; int numbers; } tab, *bam;// указатель на структуру // Вспомогательная функция // с указателем на структуру numb struct numb *PTR_ANALYSE(int x, int mass[], int n) { int min = 0; int max = n - 1; int mid; struct numb *PTR = &tab; // Бинарный поиск if (min <= max) { mid = (max + min)/2; // переход в середину массива if (x == mass[mid]) { PTR->numbers = mass[mid]; PTR->index = mid; return (PTR); // возвращение указателя на структуру } else if (x < mass[mid]) max = mid - 1; else min = mid + 1; } // End if return NULL; // число не найдено } // End function // Главная функция int main (void) { int c, x; int N, arr[MAX]; // Русские шрифты setlocale(LC_ALL, ".1251"); printf("\n УГАДЫВАНИЕ ЧИСЛА В ЧИСЛОВОМ ОТСОРТИРОВАННОМ МАССИВЕ\n"); // Латинские шрифты setlocale(LC_ALL, "English"); printf("\n The end of the session: press Ctrl+Z after pressing Enter\n"); printf("\n\t Enter the dimension of the array of more than 3: "); scanf_s("%d", &N); _flushall(); getLine(arr, N); puts(" "); do { printf("\t Enter an integer: "); scanf_s("%d", &x); _flushall(); printf(" "); bam = PTR_ANALYSE(x, arr, N); if (bam!= NULL) { printf("\t The number is found: %d\n ", bam->numbers); printf("\t The index number of assorted array: %d\n", bam->index+1); printf("\n\t Press Enter to continue or Ctrl+Z to quit: "); } else printf("\t The number is not found.\n Press Enter to continue or Ctrl+Z to quit: "); } if ((c = getchar())!= EOF); printf("\n Press any key: "); getch(); return 0; }

При двоичном алгоритме поиска после каждого сравнения исключается половина элементов массива, в котором производится поиск [5]. Алгоритм находит средний элемент массива и сравнивает его с ключом поиска (в программе переменная х). Если они равны, ключ считается найденным и возвращается индекс этого элемента. Если они не равны, задача упрощается до поиска в одной половине массива.

Если ключ поиска меньше среднего элемента, поиск производится в первой половине массива, в противном случае – во второй половине. Если ключ в указанном подмассиве не найден, алгоритм повторяется для четверти массива. Поиск продолжается до тех пор, пока ключ не окажется равен среднему элементу подмассива или пока подмассив не будет состоять из одного элемента, не равного ключу (это означает, что ключ поиска не найден).


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

Рис. 15.6. Результат двоичного поиска по совпадению ключей

Задание 6

1. Перед началом бинарного поиска по заданному ключу отсортируйте массив случайных чисел по убыванию.

2. Организуйте случайный массив из 5Х целых чисел. Интервал формирования случайных чисел примите от Х до 5Х, где Х – номер компьютера, на котором выполняется лабораторная работа. Выведите отсортированный массив на консоль. Введите число (ключ поиска), соответствующее последнему элементу массива. Подсчитайте количество итераций (количество сравнений в двоичном поиске), которое потребуется для поиска заданного ключа.

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


 

Контрольные вопросы

1. Какие операции над структурами разрешены в языке С?

2. Как осуществляется передача частей структуры в качестве аргументов функции?

3. Как осуществляется возврат частей структуры из функции?

4. Как реализуется возвращение измененной структуры из функции?

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

6. Допустимо ли объявление переменных глобальной структуры и переменных структуры функции одними и теми же идентификаторами?

7. Как распределить структуру в динамической памяти?

8. Как осуществляется возврат данных структурного типа из пользовательской функции?

 







Дата добавления: 2015-09-06; просмотров: 566. Нарушение авторских прав; Мы поможем в написании вашей работы!



Расчетные и графические задания Равновесный объем - это объем, определяемый равенством спроса и предложения...

Кардиналистский и ординалистский подходы Кардиналистский (количественный подход) к анализу полезности основан на представлении о возможности измерения различных благ в условных единицах полезности...

Обзор компонентов Multisim Компоненты – это основа любой схемы, это все элементы, из которых она состоит. Multisim оперирует с двумя категориями...

Композиция из абстрактных геометрических фигур Данная композиция состоит из линий, штриховки, абстрактных геометрических форм...

Ведение учета результатов боевой подготовки в роте и во взводе Содержание журнала учета боевой подготовки во взводе. Учет результатов боевой подготовки - есть отражение количественных и качественных показателей выполнения планов подготовки соединений...

Сравнительно-исторический метод в языкознании сравнительно-исторический метод в языкознании является одним из основных и представляет собой совокупность приёмов...

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

Индекс гингивита (PMA) (Schour, Massler, 1948) Для оценки тяжести гингивита (а в последующем и ре­гистрации динамики процесса) используют папиллярно-маргинально-альвеолярный индекс (РМА)...

Методика исследования периферических лимфатических узлов. Исследование периферических лимфатических узлов производится с помощью осмотра и пальпации...

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

Studopedia.info - Студопедия - 2014-2024 год . (0.014 сек.) русская версия | украинская версия