Сделай Сам Свою Работу на 5

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





Обращение к функции (вызов) имеет вид:

имя(список фактических аргументов)

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

a=max(4.8, b+18.);

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

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

В нашем примере при вызове функции max значения фактических аргументов (число 4.8и значениеb+18.) заносятся в соответствующие им по порядку формальные параметры, для которых отводится место в памяти (соответственно в x и y). Затем образуется локальная переменная z, в которую далее заносится большее из x и y. По достижении оператора return значение z передается на точку вызова функции и заносится в переменную a. Место в памяти, выделенное под x, y и z, освобождается.



Эту же функцию можно описать короче без использования локальной переменной z с помощью условной операции:

float max(float x,float y)

{return (x>y) ? x : y;}

Используя функцию max, можно вычислить большее из 4-х значений, вызвав ее несколько раз в одном операторе, например:

a=max( max(b, c), max(d, e) );

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

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



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

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

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

Правила соответствия формальных параметров и фактических аргументов.

Фактические аргументы и формальные параметры должны соответствовать друг другу по

¨ порядку следования;

¨ типу;

¨ количеству.

Примечание: соответствия по имени не требуется!

Передача данных по значению и по адресу. Функция scanf().

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

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



Пример 22. Напишем функцию обмена значениями двух переменных.

void change_var1(float *var1, float *var2)

{ float c;

c = *var1;

*var1 = *var2;

*var2 = c;

}

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

f = 2.8; d = 12.0;

change_var1(&d, &f);

  Основная программа Функция change_var1
Имя d f var1 var2 c
Адрес
Значение 2.8 12.0 2.8

При вызове функции change_var1 адреса фактических аргументов (переменныхdи f) заносятся в указатели var1 и var2, для которых отводится место в памяти. Затем образуется локальная переменная c, которая используется в качестве буферной переменной, чтобы поменять местами значения по адресам, находящимся в var1 и var2.

Функция scanf() для форматного ввода данных с клавиатуры требует передачи ей адресов тех переменных, в которые надо ввести значения с клавиатуры:

scanf(строка формата, список ввода) , где

¨ список ввода - перечисленные через ',' адреса переменных, значения которых хотим ввести с клавиатуры через пробел или <Enter>.

¨ строка формата - символьная строка, указывающая форматы, в соответствии с которыми будут интерпретироваться вводимые с клавиатуры данные;

Например, для чтения с клавиатуры даты вида 12 марта 1999 в целые переменные day, year и строку month_name обращение к функции scanf будет выглядеть так:

scanf("%d%s%d",&day, month_name, &year);

Знак & перед month_name не требуется, поскольку имя массива является адресом.

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

Пример 23. Рассмотрим, как будет выглядеть функция обмена значени­ями двух переменных (см. Пример 22) в этом случае.

void change_var2(float &var1, float &var2)

{ float c;

c = var1;

var1 = var2;

var2 = c;

}

Обращение к такой функции может выглядеть так:

f = 2.8; d = 12.0;

change_var2(d, f);

  Основная программа Функция change_var
Имя d f var1 var2 c
Адрес
Значение 2.8 12.0 2.8 12.0 2.8

При вызове функции change_var2 адреса фактических аргументов (переменныхdи f) становятся адресами переменных var1 и var2, для которых место в памяти не отводится. Таким образом, var1 и var2 являются просто другими именами переменных dи f из вызывающей функции. Затем образуется локальная переменная c, которая используется в качестве буферной переменной, чтобы поменять местами значения var1 и var2, т.е. dи f.

Использование массивов в качестве аргументов функции.

Поскольку имя массива означает адрес его 0-го элемента, то массив всегда передается по ссылке. Оформим в виде функции вычисление суммы элементов массива, описанное в разделе 4.1.4.

float summ(int n, float *mas);

{ int i;

float s=0;

for (i=1;i<n;i++) // Для каждого элемента

s+=mas[i]; // Увеличение суммы на mas[i]

return s;

}

Сравним теперь средние арифметические двух массивов, введенных с клавиатуры, используя функцию summ. Здесь vvod_mas1() - функ­ция для ввода одномерного массива, которую нужно написать самостоятельно.

#define MAX_SIZE 100

Void main(void)

{

float a[MAX_SIZE],b[MAX_SIZE]; // описание массивов

float sa, sb; // их средние значения

int na, nb; // количества введенных элементов этих массивов

 

vvod_mas1(&na,a) // Ввод количества элементов na и массива a

vvod_mas1(&nb,b) // Ввод количества элементов nb и массива b

sa=summ(na,a)/na; // среднее арифметическое массива a

sb=summ(nb,b)/nb; // среднее арифметическое массива b

········· // обработка sa и sb

}

Если в функцию надо передать двумерный массив, то в качестве соответствующего формального параметра надо использовать указатель на одномерный массив с размером, равным длине строки передаваемого массива, например, int (*mas)[4]. Вместо такого указателя можно использовать и просто двумерный массив, указав только количество его столбцов - int mas[ ][4].

Такое описание необходимо транслятору, чтобы знать, в каком месте одномерной памяти начинается новая строка двумерного массива, и уметь находить элемент с заданными индексами:

2 байта                      
                       
Строка 1 Строка 2 Строка 3

Пример 24. Напишем, как будет выглядеть заголовок описания функции vvod_mas2() ввода с клавиатуры двумерного массива, количество столбцов для которого было отведено в памяти в соответствии с именованной константой K_STOLB. Функция должна также заполнять значения количеств строк и столбцов вводимого массива по адресам, находящимся в указателях n_str и n_stlb, вводя их с клавиатуры:

void vvod_mas2(int *n_str, int *n_stlb, int mas[][K_STOLB])

или (см. Пример 23)

void vvod_mas2(int &n_str, int &n_stlb, int (*mas)[K_STOLB])

Пример 25. Оформим в виде функции password() ввод с клавиатуры пароля и сравнение его с образцом (см. Пример 19). В функцию передается образец пароля, а возвращается истина, если введенный пароль верен.

int password(char *parol)

{ int i

unsigned char mas[81];

 

gets(mas); // Ввели пароль

for (i=0; mas[i] == *(parol+i);i++) ;

if (mas[i] == '\0' ) // Строки совпали полностью

return 1;

return 0;

}

Обращение к функции может выглядеть так:

if password("Мой пароль")

cout << "Пароль верный, доступ открыт";

Пример 26. Оформим функцию wrd_let(), определяющую количество букв и слов в передаваемой ей строке (см. Пример 20). Поскольку определяются значения двух параметров, то в функцию передаются адреса переменных, а не их значения.

void wrd_let(int *k_sl, int *k_sim, char *mas)

{ int i=0; // Номер текущего символа

unsigned char ch; // Текущий символ

 

*k_sl=1,*k_sim=0; // Количество слов и символов

gets(mas);

while ( (ch = *mas++) != '\0' )

if (ch==' ') // Текущий символ - пробел -

*k_sl++; // увеличили кол-во слов

else if (ch>64 && ch<240) // Текущий символ - буква -

*k_sim++; // увеличили кол-во букв

}

После такого обращения к функции:

wrd_let(&slova, &bukvy, "Мы изучаем Си!");

переменные slova и bukvy примут значения соответственно 3 и 11.

 








Не нашли, что искали? Воспользуйтесь поиском по сайту:



©2015 - 2024 stydopedia.ru Все материалы защищены законодательством РФ.