Передача массива
Передача указателя
Передача в функции указателей и массивов
В предыдущих примерах в качестве аргументов использовались простые значения типов int или double. Однако часто в качестве аргументов приходится использовать указатели и массивы. Хотя передача в функцию таких аргументов осуществляется так же, как и любых других, однако при их использовании возникают проблемы, которые следует рассмотреть особо.
Для того, чтобы передать указатель в качестве аргумента, вы должны объявить параметр типа указателя. Вот пример:
// Передача функции указателя.
#include <iostream>
using namespace std;
#include <conio>
//f() принимает указатель int * в качестве параметра.
void f (int *j); // f() объявляет параметр-указатель
int main () {
int i;
int *p;
p = &i; // p теперь указывает на i
f(p); // передача указателя
cout << i; // i теперь равно 100
getch();
return 0 ;
}
// ft) получает указатель на int.
void f (int * j ) {
*j = 100; // переменной, на которую указывает j,
// теперь присвоено значение 100
}
Рассмотрим внимательно эту программу. Мы видим, что функция f( ) принимает один параметр: указатель на int. Внутри main( ) указателю р присваивается значение адреса переменной i. Далее вызывается f( ) с р в качестве аргумента. Когда параметр-указатель j получает значение р, он так же указывает на i внутри main( ). Таким образом, предложение
*j = 100;
присваивает значение 100 переменной i. В общем случае f( ) запишет значение 100 по любому адресу, который будет ей передан при вызове.
В предыдущем примере фактически не было необходимости использовать переменную-указатель р. Достаточно при вызове f( ) указать в качестве аргумента i, предварив это имя значком &. В результате в функцию f() будет передан адрес i. Модифицированная программа имеет такой вид:
// Передача функции указателя.
#include <iostream>
using namespace std;
#include <conio>
void f(int *j ) ;
int main() {
int i ;
f (&i); //Нет необходимости в p. В f( ) непосредственно
// передается адрес i.
cout << i ;
getch();return 0;
}
void f(int *j ) {
*j = 100; // переменной, на которую указывает j,
// теперь присвоено значение 100
}
Существенно, чтобы вы усвоили важное обстоятельство, связанное с передачей в функции указателей: когда вы выполняете внутри функции операцию, использующую указатель, вы фактически работаете с переменной, на которую этот указатель указывает. Это дает возможность функции изменять значение объекта, на который указывает аргумент-указатель.
Когда в качестве аргумента функции выступает массив, в функцию передается не копия всего массива, а адрес его первого элемента. (Вспомним, что имя массива без индекса является указателем на первый элемент массива.) Соответственно, объявление параметра в функции должно быть совместимым с этим адресом по типу. Имеются три способа объявить параметр, который должен будет принять указатель на массив. Первый способ заключается в том, что этот параметр объявляется как массив того же типа и размера, что и массив, передаваемый в функцию при ее вызове. Этот способ использован в приведенном ниже примере.
#include <iostream>
using namespace std;
void display (int num[10] ) ;
int main (){
int t[10] , i;
for(i=0; i < 10; ++i) t[i]=i;
display(t) ; // передача в функцию массива t
return 0;
}
// Выведем несколько чисел.
void display ( int num [ 10 ] ){
for(int i = 0; i < 10; i++) cout << num[i] << ' ';
}
Несмотря на то, что параметр num объявлен как целочисленный массив из 10 элементов, компилятор С++ автоматически преобразует его в указатель на int. Это преобразование необходимо, потому что никакой параметр не может принять целый массив. Поскольку в функцию будет передан указатель на массив, в функции должен быть такой же параметр-указатель для его получения.
Второй способ объявить параметр-указатель состоит в задании параметра в виде массива неопределенной длины, как это показано ниже:
void display ( int num [ ] ) {
for(int i=0; i < 10; i++) cout << num[i] << ' ';
}
Здесь параметр num объявлен как массив неопределенной длины. Поскольку С++ не выполняет проверку на выход за границы массива, фактический размер массива не существенен для параметра (но, разумеется, не для программы). При таком способе объявления компилятор так же автоматически преобразует параметр в указатель на int.
Наконец, num можно объявить как указатель. Этот метод чаше других используется в профессионально написанных программах. Вот пример такого объявления:
void display ( int *num) {
for(int i=0; i < 10; i++) cout << num[i] << ' ';
}
Возможность объявления параметра как указателя проистекает из того, что любой указатель можно индексировать как массив, используя квадратные скобки [ ] . Заметьте себе, что все три метода объявления массива в качестве параметра дают один и тот же результат: указатель.
Важно понимать, что когда массив используется в качестве аргумента функции, в функцию передается его адрес. Это означает, что код внутри функции будет воздействовать и, возможно, изменять фактическое содержимое этого массива. В качестве примера рассмотрим входящую в приведенную ниже программу функцию cube( ), которая преобразует значение каждого элемента массива в его куб. При вызове функции cube() ей в качестве первого аргумента передается адрес массива, а в качестве второго — его размер:
// Измерение содержимого массива с помощью функции.
#include <iostream>
using namespace std;
#include <conio>
void cube(int *n, int num);
int main() {
int i, nums[10];
for(i=0; i < 10; i++) nums[i]= i+1;
cout << "Исходное содержимое: ";
for(i = 0; i < 10; i ++) cout << nums[i] << ' ';
cout << '\n';
cube (nums, 10) ; // вычисление кубов
cout << "Измененное содержимое: ";
for(i = 0; i<10; i ++) cout << nums[i] << ' ' ;
getch();
return 0;
}
// Возведение в куб элементов массива.
void cube(int *n, int num){
while (num) {
*n = *n * *n * *n;
num-- ;
n++;
}
}
Ниже приведен вывод этой программы:
Исходное содержимое: 1 2 3 4 5 6 7 8 9 10
Измененное содержимое: 1 8 27 64 125 216 343 512 729 1000
Мы видим, что после вызова функции cube() массив nums в main() содержит кубы первоначальных значений его элементов. Таким образом, значения элементов nums были модифицированы программными предложениями внутри функции cube(). Это стало возможным потому, что параметр функции n указывает на nums.