Передача параметров функции
Обрабатывая вызов функции, компилятор вставляет в код программы последовательность машинных команд, выполняющих следующие действия:
1) запись в стек копий переменных или констант, перечисленных в списке аргументов (если поле «список_аргументов» в прототипе функции не void);
2) вызов процедуры с возвратом (либо «близкий», либо «далекий» в зависимости от заданного явно или неявно типа функции).
Функция в процессе исполнения извлекает копии аргументов из стека. Таким образом, формальные и фактические аргументы изолируются друг от друга.
При передаче параметров в функцию (при их записи в стек) выполняется дополнительно преобразование типов фактических аргументов к типу, который указан в прототипе функции. Преобразование не выполняется, если используется классическое задание прототипа. В этом случае несоответсвие типов фактических и формальных параметров может служить причиной ошибок. Ошибки такого типа не возникают, если задается полный прототип вызываемой функции.
В общем случае существуют два стиля передачи параметров функции:
1) вызов функции с передачей значений (Call-By-Value);
2) вызов функции с передачей адресов переменных (Call-By-Reference).
Вызов с передачей значений – это простая передача копий переменных в функцию, не оставляющая никаких возможностей для воздействия функции на переменные в точке вызова. Например:
/* Prim6_2.cpp */
#include <stdio.h>
int sum( int, int);
void main( void)
{int a = 5, b = 4, c;
c = sum( a, b);
printf( "%d\n", c);
}
int sum( int k, int l)
{int m;
m = k + l;
return m;
}
Функции sum() передаются копии переменных a и b. Эти копии используются функцией в качестве значений для аргументов k и l.
Вызов с передачей адресов предполагает, что в качестве параметров функции передаются не копии переменных, а копии адресов переменных. Используя указатель, функция осуществляет доступ к нужным ячейкам памяти. Так как известен адрес в памяти, можно изменить его значение. Поэтому при вызове с передачей адресов функция может изменить значение переменных в точке вызова. Приведенная ранее программа при вызове с передачей адресов выглядит так:
/* Prim6_3.cpp */
#include <stdio.h>
int sum( int*, int*);
void main( void)
{int a = 5, b = 4, c;
c = sum( &a, &b);
printf( "%d\n", c);
}
int sum( int* k, int* l)
{int m;
m = *k + *l;
return m;
}
В приведенном примере в функцию передаются копии указателей на ячейки памяти (другими словами, адреса в памяти). Эти адреса используются для доступа к памяти.
Вызов функции с передачей адресов позволяет разрабатывать функции, имеющие доступ к массивам и другим протяженным объектам данных. Если в список переменных включено имя массива, то в функцию передается только адрес начала массива. Например, так выглядит функция, выполняющая копирование строки из одного места в памяти в другое (т.е. действия, аналогичные библиотечной функции strcpy()):
/* Prim6_4.cpp */
char* my_strcpy( char* destination, char* source)
{char* ret_ptr = destination;
while( *source)
*destination ++= *source++;
*destination = ‘\0’; /* перенос символа ‘\0’ */
return ret_ptr;
}
Если программисту привычнее манипулировать с элементами массива, предыдущую программу можно записать так:
/* Prim6_5.cpp */
char* my_strcpy( char destination[], char source[])
{char* ret_ptr = destination;
while( *source)
*destination ++= *source++;
*destination = ‘\0’; /* перенос символа ‘\0’ */
return ret_ptr;
}
Первую строку функции my_strcpy() можно записать и так:
char* my_strcpy( char* destination, char* source)
а для доступа к элементам по-прежнему использовать индекс.
Язык программирования С++ допускает использование переменного числа аргументов. Признаком функции с переменным числом аргументов является многоточие … в списке параметров прототипа функции. Встретив (…), компилятор прекращает контроль соответствия типов параметров для такой функции. Функция с переменным числом параметров должна имет способ определения точного их числа при каждом вызове.
Ниже приводится пример функции example, которая принимает переменное число аргментов и выводит на печать их количество и принятые значения. Число действительно переданных через стек значений задает первый аргумент:
/* Prim6_6.cpp */
#include <stdio.h>
void example( int, …);
void main( void)
{int var1 = 5, var2 = 6, var3 = 7, var4 = 8, var5 = 9;
example( 2, var1); /* вызов функции с двумя аргументами */
example( 3, var1, var2); /* та же функция имеет три аргумента */
example( 6, var1, var2, var3, var4, var5); /* а теперь – шесть */
}
void example( int arg1, …)
{int* ptr = &arg1; /* установка указателя на первый аргумент */
printf("\n Функции EXAMPLE передано всего %d аргумента(ов):\n", arg1); /* печать всех переданных в функцию фактических аргументов */
for( ; arg1; arg1--) {printf("%d", *ptr); ptr++;}
Запуск программы на выполнение дает такие результаты:
Функции EXAMPLE передано всего 2 аргумента(ов):
2 5
Функции EXAMPLE передано всего 3 аргумента(ов):
3 5 6
Функции EXAMPLE передано всего 6 аргумента(ов):
6 5 6 7 8 9
В данном примере первый аргумент используется, как счетчик количества аргументов.
Дата добавления: 2017-01-29; просмотров: 530;