Выбрать главу

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

■ Использование глобальной переменной в "роли", с которой легко бы "справилась" локальная переменная, делает такую функцию менее универсальной, поскольку она полагается на необходимость определения данных вне этой функции.

■ Использование большого количества глобальных переменных может привести к появлению ошибок в работе программы, поскольку при этом возможно проявление неизвестных и нежелательных побочных эффектов. Основная проблема, характерная для разработки больших С++-программ, — случайная модификация значения переменной в каком-то другом месте программы. Чем больше глобальных переменных в программе, тем больше вероятность ошибки.

Передача указателей и массивов в качестве аргументов

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

Вызов функций с указателями

В C++ разрешается передавать функции указатели. Для этого достаточно объявить параметр типа указатель. Рассмотрим пример.

// Передача функции указателя.

#include <iostream>

using namespace std;

void f (int *j);

int main()

{

 int i;

 int *p;

 p = &i; // Указатель p теперь содержит адрес переменной i.

 f(p);

 cout << i; // Переменная i теперь содержит число 100.

 return 0;

}

void f (int *j)

{

 *j = 100; // Переменной, адресуемой указателем j, присваивается число 100.

}

Как видите, в этой программе функция f() принимает один параметр: указатель на целочисленное значение. В функции main() указателю р присваивается адрес переменной i. Затем из функции main() вызывается функция f(), а указатель р передается ей в качестве аргумента. После того как параметр-указатель j получит значение аргумента р, он (так же, как и р) будет указывать на переменную i, определенную в функции main(). Таким образом, при выполнении операции присваивания

*j = 100;

переменная i получает значение 100. Поэтому программа отобразит на экране число 100. В общем случае приведенная здесь функция f() присваивает число 100 переменной, адрес которой был передан этой функции в качестве аргумента.

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

// Передача указателя функции -- исправленная версия.

#include <iostream>

using namespace std;

void f (int *j);

int main()

{

 int i;

 f(&i);

 cout << i;

 return 0;

}

void f (int * j)

{

 *j = 100; // Переменной, адресуемой указателем j, присваивается число 100.

}

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

Вызов функций с массивами

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