指针在函数中的使用也是十分广泛的。某些情况下,将指针作为函数的参数或函数的返回值会给我们带来方便。而某些情况下,我们又不得不将指针作为函数的参数或函数的返回值。
我们在上一章我们已经了解向函数传递数组的实质是向函数传递数组首元素的地址。我们又知道数组名是一个指向数组首元素的指针常量。所以我们认为,向函数传递数组是将指针作为参数的特殊形式。
由于指针可以直接操作内存中的数据,所以它可以用来修改实参。这个功能和引用是类似的。
下面我们来看一段程序,了解指针作为参数时的上述两个特点:(程序8.6.1)
#include "iostream.h"
void arrayCopy(int *src,int *dest,int size);//复制数组元素
void display(const int *array,int size);//输出数组元素
int main()
{
int a[]={3,4,5,6,3,1,6};
int b[7];
arrayCopy(a,b,sizeof(a)/sizeof(int));//把数组a的元素依次复制到数组b中
cout <<"The data of array a is:";
display(a,sizeof(a)/sizeof(int));
cout <<"The data of array b is:";
display(b,sizeof(b)/sizeof(int));
return 0;
}
void arrayCopy(int *src,int *dest,int size)
{
for (int i=0;i<size;i++)
{
dest[i]=src[i];//修改了实参数组元素
}
cout <<size <<" data Copied." <<endl;
}
void display(const int *array,int size)//const用来保护指针指向的数据
{
for (int i=0;i<size;i++)
{
cout <<array[i] <<" ";
}
cout <<endl;
}
运行结果:
7 data Copied.
The data of array a is:3 4 5 6 3 1 6
The data of array b is:3 4 5 6 3 1 6
根据arrayCopy函数,不难看出传递数组和传递指针是完全相同的。而通过指针的间接引用或数组操作,我们可以在函数内实现对实参的修改。这就是arrayCopy函数能够实现复制功能的原因。
不过,将指针作为函数参数的副作用仍然不容我们忽视。指针和引用虽然都能够修改实参,但是指针却更加危险。因为引用仅限于修改某一个确定的实参,而指针却可以指向内存中的任何一个数据,通过间接引用就能够在一个函数内修改函数外甚至系统中的数据了。这样一来,函数的黑盒特性就被破坏了,系统也因此变得不再安全。对于程序员来说,将指针作为函数参数可能把函数内的问题引到函数外面去,使得调试程序变得非常困难。所以,我们要认识到使用指针的两面性,谨慎对待指针做函数参数。
为了避免指针作为函数参数导致数据被意外修改,我们可以使用const来保护指针指向的数据,如程序8.6.1中的display函数。
和别的数据类型一样,指针也能够作为函数的一种返回值类型。我们把返回指针的函数称为指针函数。在某些情况下,函数返回指针可以给我们设计程序带来方便。而且此时通过间接引用,函数的返回值还可以作为左值。
下面我们来看一段程序,了解函数如何返回指针:(程序8.6.2)
#include "iostream.h"
int * max(int *array,int size);//返回值类型是int *,即整型指针
int main()
{
int array[]={5,3,6,7,2,1,9,10};
cout <<"The Max Number is " <<*max(array,sizeof(array)/sizeof(int)) <<endl;//间接引用返回的指针
return 0;
}
int * max(int *array,int size)//寻找最大值
{
int *max=array;
for (int i=0;i<size;i++)
{
if (array[i]>*max)
max=&array[i];//记录最大值的地址
}
return max;
}
运行结果:The Max Number is 10
需要注意的是,返回的指针所指向的数据不能够是函数内声明的变量。道理很简单,我们在第六章已经说明,一个函数一旦运行结束,在函数内声明的变量就会消失。就好像下课同学们都走了,教室里的某一个座位到底有没有坐着谁我们无法确定。所以指针函数必须返回一个函数结束运行后仍然有效的地址值。