Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Лабы / C++.Ашарина / C_function / functionC++

.htm
Скачиваний:
21
Добавлен:
17.04.2013
Размер:
51.76 Кб
Скачать

МОСКОВСКИЙ ИНСТИТУТ ЭЛЕКТРОННОЙ ТЕХНИКИ МОСКОВСКИЙ ИНСТИТУТ ЭЛЕКТРОННОЙ ТЕХНИКИ

(ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ)

 

Кафедра “Информатика и программное обеспечение вычислительных систем”

Учебная дисциплина “Информатика”

 

 

ЛАБОРАТОРНАЯ РАБОТА

Прогаммирование задач с использованием функции на языке С++.

 

 

Цель работы: изучить правила описания и получить навыки использования

функций при написании программ на языке С++.

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

Функции в С++ бывают встроенные (стандартные) и пргаммируемые пользвателем.

Стандартные функции.

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

Вызов функции приводит к выполнению некоторых действий. Например, при обращении к функции printf() осуществляется вывод данных на экран. Другие функции вычисляют некоторую величину, используемую затем в программе. Например, функция scanf() позволяет получить некоторые данные, вводимые с клавиатуры, а функция printf() – вывести необходимую информацию на экран:

scanf (“%f”, &x); {функция приема числа с клавиатуры}

y = sin(x); {функция вычисления синуса}

pintf (“%f”, y); {функция выдачи результатов на экран}

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

 

Определение функции.

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

[<тип >] <имя функции> (<тип > <имя параметра>,…, <тип > <имя параметра>)

{

<тело функции>

}

Функции, программируемые пользователем.

избавляет нас от повторного программирования;

одну и ту же функцию можно применять в различных программах;

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

Пусть нам нужно написать программу, которая:

вводит набор чисел;

сортирует эти числа;

находит их среднее значение;

выводит на печать гистограмму.

Основная программа в этом случае может иметь вид:

void main()

{

float list[50];

readlist(list); // функция ввода массива

sort(list); // функция сортировки массива

average(list); // функция нахждения среднего значения

bargraph(list); // функция вывода на экран гистограммы

}

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

Для начала создадим функцию, которая печатает 65 символов “*” в ряд. Чтобы эта функция выполнялась в некотором контексте, она включена в программу печати фирменного бланка.

Программа состоит из функций: main() и starbar().

// Фирменный бланк

#include <stdio.h>

#define Limit 65

void main()

{

starbar();

printf (“Moscow Institute Electronic Engineering \n”);

starbar();

}

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

void starbar()

{

int count;

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

putchar (‘*’);

putchar (‘\n’);

}

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

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

Синтаксис для прототипа функции с параметром:

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

Рассмотрим на примере использование параметров функции. Напишем функцию space, в качестве аргумента которой будет число пробелов, которое должна напечатать эта функция.

#define address “Zelenograd”

#define name “Moscow Institute Electronic Engineering”

#define department “Informatics and Programming”

//Определение функции starbar

#include <stdio.h>

#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 (‘ ’);

}

void main()

{

int spaces;

starbar();

space(25);

printf(“%s \n”, address);

spaces = (65-strlen(name))/2; //Вычислить, сколько пробелов

space(spaces);

printf(“%s \n”, name);

space((65-strlen(department))/2); //аргумент-выражение

printf(“%s \n”, department);

starbar();

}

Переменная number называется формальным аргументом. Указанная переменная приобретает значения фактического аргумента при вызове функции.

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

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

void printnum (int i, int j)

{

printf(“координаты точек %d%\n”, i, j);

}

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

Если предполагается, что функция будет возвращать некоторое значение, то перед именем функции вместо слова void следует указать тип возвращаемого значения.

Пример:

void main()

{

int a=10, b=0, c=-22;

int d, e , f;

d = abs(a);

e = abs(b);

f = abs(c);

printf (“%d %d %d \n”, d, e, f);

}

int abs(int x) //Функция, вычисляющая абсолютное значение числа

{

int y;

y = (x<0)? –x:x;

return y; // возвращает значение у вызывающей программе

}

Запись y = (x<0)? –x:x эквивалентна записи

if (x<0) y = -x;

else y = x;

Другая версия функции abs(x) может иметь вид:

int abs(int x)

{

if x<0 return –x;

return x;

}

Третья версия функции abs(x):

int abs(int x)

{

if (x<0) return –x;

return x;

printf(“А вот эта строка не напишется никогда и ни за что,” \n);

printf(“так как этому препятствует наличие оператора return.” \n);

}

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

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

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

Если функция не возвращает никакого результата посредством выполнения оператора return выражение, то ее тип определяется как void (в том числе и для функции main()). Иными словами, тип функции не определен.

Запрещается в С++ определять функции внутри других функций.

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

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

Рассмотренные раньше функции содержали объявления переменных внутри определения функции. такие переменные называются локальными и доступны только в пределах функции, в которой они определены. В следующем примере переменная var1 доступна только внутри функции func(), а var2 активна только в main().

#include <stdio.h>

void func(void)

{

int var1= 11; //локальная переменная var1

printf(“var1=%d\n”, var1);

}

int main(void)

{

int var2=22; //локальная переменная var2

printf(“var2=%d\n”, var2);

func();

printf(“var1=%d\n”, var1); //приведет к возникновению ошибки

return 0; // ‘Undefined symbol var1’

}

Переменная, объявленная вне любой из функций, называется глобальной переменной и доступна в области от точки ее объявления до конца файла. Чтоюы сделать var1 доступной как в func(), так и в main(), следует описать эу переменную в начале файла:

#include <stdio.h>

int var1= 11; //локальная переменная var1

void func(void)

{

printf(“var1=%d\n”, var1);

}

int main(void)

{

int var2=22;

printf(“var2=%d\n”, var2);

func(); // на экран будут выданы

printf(“var1=%d\n”, var1); // два одинаковых значения.

return 0;

}

 

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

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

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

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

#include <stdio.h>

void main()

{

int a, b;

puts(“Введите значения a и b”);

scanf(“%d%d”,&a, &b);

swp(&a, &b);

printf(“Измененные значения: a=%d; b=%d”,a,b);

}

swp(x, y)

int *x, *y; // x и y – указатели, *x и *y – значения, на которые они указывают

{

int c;

c = *x;

*x = *y;

*y = c;

}

Рассмотрим передачу массивов в качестве аргументов функции. Для передачи одномерного массива достаточно следующих действий. Объявим функцию, которая принимает в качестве параметра массив значений типа double. прототип этой функции можно записать следующим образом:

double SumOfData (double data [max]);

Еще лучше объявить

double SumOfData (double data [], int n);

Тогда при объявлении функции SumOfData() ей можно передать массив аргументов вместе с целым числом n, сообщающем количество элементов в передаваемом массиве.

Сама функция SumOfData может содержать, например, обычный цикл while, суммирующий элементы массива, а функция return возвращает результат:

double SumOfData (double data [], int n)

{

double sum = 0;

while (n>0)

sum++ = data[-n];

return sum;

}

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

Пусть ROWS – количество строк, COLS – количество столбцов. Объявим функцию с массивом в качестве параметра:

void AnyFn (int data [ROWS] [COLS]);

или

void AnyFn (int data [] [COLS]);

Можно передать параметр, определяющий количество строк:

void AnyFn (int data [] [COLS], int numRows);

где numRows сообщает функции число строк в массиве data.

Пример. Передача функции многомерных массивов.

#include <stdio.h>

#include <stdlib.h>

#include <time.h>

#define COLS 8

void FillArray (int data [] [COLS], int numRows);

void DisplayTable (int data [] [COLS], int numRows);

int data1 [7] [COLS];

int data2 [4] [COLS];

void main()

{

randomize(); //инициализация генератора случайных чисел

FillArray (data1, 7);

DisplayTable (data1, 7);

FillArray (data2, 4);

DisplayTable (data2, 4);

}

void FillArray (int data [] [COLS], int numRows)

{

int r, c;

for (r=0; r<numRows; r++)

for (c=0; c<COLS; c++)

data [r] [c] = rand(); // rand() – генератор случайных чисел

}

void DisplayTable (int data [] [COLS], int numRows)

{

int r, c;

for (r=0; r<numRows; r++)

{

printf(“\n”);

for (c=0; c<COLS; c++)

printf(“%8d”, data [r][c]);

}

printf(“\n”);

}

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

Указатель- это переменная, содержащая адрес другой переменной.

Указателями в С++ являются имена массивов. Имя массива указвает на первый элемент массива, индекс которого в С++ равен нулю.

При работе с указателями используются два оператора:

“&” – унарный оператор определения адреса переменной,

“*” - унарный оператор раскрытия ссылки.

Записывая функцию С++, которая передает параметр в виде массива, можно оъявить этот параметр как указатель на базовый тип массива.

Общий синтаксис для прототипа функции с параметром в ивде указателя на массив:

возвращаемый_тип функция (базовый_тип*, <другие_типы_параметров>);

Общий синтаксис для определения этой функции:

возвращаемый_тип функция (базовый_тип *массив_параметр, <другие параметры>)

Напишем функцию, использующую массивы, а затем перепишем ее, применяя указатели.

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

printf(“Среднее из заданных значений %d \n”, mean (numbs. sizes)); /* Находит

среднее значение массива из n целых чисел. */

int mean(int array[ ], int n)

{

int index;

long sum; /* Если массив содержит много элементов, сумма может оказаться

довольно большой, поэтому long int. */

if (n>0)

{

for (index=0, sum=0; index<n; index++)

sum+ = array [index];

return sum/n; // возвращает int.

}

else

{

printf(“нет массива. \n”);

return 0;

}

}

Перепишем эту же программу с использованием указателей. Объявим pnt_arr указателем на тип int и заменим элемент массива array[index] на соответствующее значение: *(pnt_arr+index).

// Использование указателей для нахождения среднего значения массива

// n целых чисел.

int mean(int *pnt_arr, int n)

{

int index;

long sum;

if (n>0)

{

for (index=0, sum=0; index<n; index++)

sum+ = *(pnt_arr+index);

return sum/n; // возвращает целое sum/n.

}

else

{

printf(“нет массива. \n”);

return 0;

}

}

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

int iarray [10];

int *iptr = iarray; // То же самое, что iptr = &iarray[0].

В С++ указатели можно увеличивать или уменьшать. указатель, увеличенный на 3 будет указывать на четвертый элемент массива (эквивалентно &iarray[3]). Другими словами, увеличивая указатель на единицу, мы в действительности увеличиваем адрес, который он представляет, на размер объекта связанного с ним типа.

Т. к. указателям типа void не соответсвует никакой тип данных, к ним нельзя применять арифметические операции.

Указатель можно индексировать точно также, как массив. Компилятор в действительности преобразует индексацию в арифметику указателей: iarray[3]=10; представляется как *(iarray+3)=10;

В С++ имеется несколько видоизмененная форма указателя, называемая ссылкой. Ссылка на некоторую переменную может рассматриваться как указатель, который при употреблении всегда разыменовывается. Однако, для ссылки не требуется дополнительного пространства в памяти: она является просто другим именем (псевдонимом) переменной.

Для определения ссылки применяется унарный оператор &.

Пример.

#include <stdio.h>

int value = 10;

int &refval = value; //Ссылка на value

int main(void)

{

printf(“value=%d\n”, value);

refval+ =5; // Модификация через ссылку

printf(“value=%d\n”, value);

printf(“Адрес value равен %p\n”, &value);

printf(“Адрес refval равен %p\n”, &refval);

return 0;

}

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

#include <stdio.h>

void inc_val(int i) // Получает параметр-значение

{

i++; // Модификация не влияет на оригинал

}

void inc_ptr(int *i) // Получает адрес-оригинала

{

(*i)++; // Модифицирует оригинал путем косвенной адресации

}

void inc_ ref (int &i) // Получает параметр-ссылку

{

i++; // Модифицирует оригинал!

}

int main(void)

{

int j=10;

printf(“J = %d\n”,j);

inc_val(j);

printf(“После inc_val(j) J = %d\n”,j);

inc_ptr(&j);

printf(“После inc_ptr(j) J = %d\n”,j);

inc_ref(j);

printf(“После inc_ref(j) J = %d\n”,j);

return 0;

}

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

вызывающей функции не требуется применять операцию взятия адреса (&);

вызываемая функция избавляет от использования косвенных операций(*);

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

Пример. Ссылка как возвращаемый функцией тип.

#include <stdio.h>

const int array Size = 0xF;

static int valArray [array Size];

int &valueAt(int indx)

{

return valArray[indx];

}

int main(void)

{

for (int i =0; i<arraySize; i++)

valueAt(i) =1<<j;

for (i = 0; i<arraySize; i++)

printf(“Значение [%02d]=%-6d \n”, i, valueAt(i));

return 0;

}

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

Рассмотрим теперь двумерный массив как параметр функции.

Описание двумерного массива a из 2 строк и 4 столбцов в списке параметров функции может задано одним из следующих способов:

int fun (int a[2][4]);

int fun (int a[][4]);

int fun (int a(*[4]));

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

Обращение к функции fun может быть следующим:

y = fun(a); //передается адрес

y = fun(&a[0][0]); // начала массива

y = fun(a+i); //передается адрес i-го элемента массива.

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

#include <stdio.h>

#include <conio.h>

void main()

{

int a [2][4] = {{1, 2, -8, -7}, {-1, 2, 8, 7}};

*pa = *a; //или *pa = &a [0][0];

int i, j, x1, x2, x3, x4, x5, *pi;

int fun(int (*)[ ]); // или fun(int (*a[ ])); или int fun(int a[ ][ ]);

// или int fun(int a[2][4]); - описание прототипа функции fun

i =1; j=2;

pi = &a [i][j];

// далее следует эквивалентные с точки зрения результата операторы;

// в результате их выполнения получим x1=x2=x3=x4=x5=8

x1 = a[i][j]; x2 = pi; x3 = *(pa+i*4+j); x4 = *(*a+i*4+j); x5 = pa[i*4+j];

clrscr;

printf (“x1=%3d; x2=%3d; x3=%3d; x4=%3d; x5=%3d \n”,x1, x2, x3, x4, x5);

printf (“x0=%3d \n”, fun(a)); // x0 = a[0][0];

for (i=0; j<4; j++)

printf (“x=%3d \n”, a[i][j])); // -1 –2 8 7

for (i=0; j<4; j++) // в функцию fun передается адрес

printf (“x=%3d \n”, fun(&a[i][j])); // -1 –2 8 7

// другой способ доступа к элементам двумерного массива

pa = *a + 4;

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

printf (“x=%3d \n”, fun(pa+j)); // -1 –2 8 7

int fun (int a[ ][4]); // или fun (int(*a)[4]);

{return a[0][0];}

}

 

 

 

 

 

Требования к отчету.

Отчет должен содержать:

название и цель работы;

краткие теоретические сведения;

задание для варианта задания, соответствующего номеру Фамилии студента в группе (если студент закреплен за определенной ЭВМ, имеющей номер, то номеру ЭВМ);

схему алгоритма для задачи своего варианта;

текст программы для задачи своего варианта;

результаты выполнения программы.

 

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

Каков допустимый уровень вложенности функции в языке С?

Как определить функцию? Что такое прототип функции? Всегда ли обязательно объявление прототипов?

Как передать информацию фцнкции?

В чем разница между формальными и фактическими аргументами? Где описываются аргументы?

Где описываются локальные переменные функции?

Для чего служит оператор return? Обязательно ли его использование?

Все ли правильно в следующем определении функции:

hallo (num)

{

int num, count;

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

printf (“Hallo, my friend! \n”);

} ?

 

 

 

 

 

ВАРИАНТЫ ЗАДАНИЙ.

Задать значения вещественным элементам массивов

и вычислить

2. Задать значения целочисленным элементам массивов

и вычислить

3. Задать значения целочисленным элементам массивов

и вычислить

4. Задать значения вещественным элементам массивов

и вычислить

5. Задать значения целочисленным элементам матриц

где i = 1,2,3,4; j = 1,2,…,7 и сформировать массивы C и D, состоящие из

максимальных элементов столбцов матриц A и B соответственно.

6. Задать значения вещественным элементам массивов

где i = 1,2,…,9 и вычислить элементы массивов

по формулам:

Функция f вычисляется по формуле

с точностью ε =0,001.

7. Задать значения целочисленным элементам матриц

где i = 1,2,…,8; j = 1,2,…,6 и сформировать массивы C и D, состоящие из

максимальных элементов строк матриц M и N соответственно.

8. Задать значения вещественным элементам матриц

где i = 1,2,…,7; j = 1,2,…,5 и сформировать массивы B и R, состоящие из

минимальных элементов строк матриц A и Q соответственно.

9. Задать значения целочисленным элементам матриц

где i = 1,2,…,5; j = 1,2,…,8 и сформировать массивы R и T, состоящие из

отрицательных элементов строк матриц P и Q соответственно.

10. Задать значения вещественным элементам матриц

где i = 1,2,…,6; j = 1,2,…,6 и сформировать массивы X и Y, из положительных элементов строк матриц C и D соответственно.

11. Задать значения целочисленным элементам матриц

где i = 1,2,3; j = 1,2,…,8 и сформировать массивы T и S соответственно из

элементов матриц W и Z, больших заданного числа P.

12. Задать значения вещественным элементам матриц

где i = 1,2,…,7; j = 1,2,3 и сформировать массивы Y и Z соответственно из

элементов матриц B и D, меньших заданного числа R.

13. Задать значения вещественным элементам матриц

где i = 1,2,…,5; j = 1,2,…,8 и сформировать массивы R и T, состоящие из

минимальных элементов столбцов матриц P и Q соответственно.

14. Задать значения целочисленным элементам массивов

где i = 1,2,…,6 и вычислить элементы массивов

по формулам:

Функция f вычисляется по формуле

с точностью ε =0,01 (|t|>1).

15. Задать значения вещественным элементам массивов

где i = 1,2,…,6 и вычислить

16. Задать значения целочисленным элементам массивов

где i = 1,2; j = 1,2,3 и вычислить элементы матриц

по формулам:

Для вычисления интеграла использовать метод Симпсона, описанный в лабораторной работе №3.

17. Задать значения целочисленным элементам массивов

где i = 1,2,…,5; j = 1,2,3 и вычислить элементы массивов

по формулам:

Для вычисления интеграла использовать метод Симпсона, описанный в лабораторной работе №3.

18. Задать значения целочисленным элементам массивов

где i = 1,2,…,10 и сформировать массив N = {n[i]}, i-ый эоемент которого равен числу корней уравнения sin x = 1/x на интервале a[i]<x<b[i]. Для определения числа корней уравнения составить программу.

19. Сформировать массив X из корней уравнений

и найти максимальный из этих корней. Для решения уравнений использовать метод деления отрезка пополам, описанный в лабораторной работе №3.

20. Задать значения вещественным элементам массивов

и вычислить

если

21. Задать значения вещественным элементам четырех квадратных матриц

5-го порядка и вычислить квадрат той из матриц, укоторой наибольшая

сумма диагональных элементов.

22. Задать значения целочисленным элементам матриц

где i = 1,2,3; j = 1,2,…,5 и вычислить величины

где x[i], y[i] –максимальные элементы i-ых строк матриц A и B

соответственно.

23. Задать целочисленные значения элементам квадратных матриц

и векторам (матриц-столбцам)

где i = 1,2,…,4; j = 1,2,…,4 и вычислить вектор W = AX + BY – CZ.

24. Задать значения 9-элементам вещественным векторам X, Y, Z и вычислить

величину D = (A,A) – (B,C), где A обозначает тот из векторов X, Y, Z, в котором наименьший максимальный элемент, B и C обозначают два других вектора, а (V1,V2) – скалярное произведение векторов V1 и V2.

 

 

 

 

Соседние файлы в папке C_function