C++ 初学者指南 第五篇(8)

来源:互联网 发布:linux wget下载速度慢 编辑:程序博客网 时间:2024/06/10 05:31

必备技能5.8:给函数传入指针和数组
    在前面的示例程序中,我们传入到函数中的参数都是简单的数据,比如整型数,或者浮点数之类的。实际上,有时候我们需要把指针或者数组作为参数传入到函数中的。尽管给函数传入指针或者数组的方式是很简单的,但是其中有些特殊的事项需要注意。
传入指针
    为了给函数传入指针作为其参数,我们必须把函数的参数类型声明为指针的类型。下面就是一个示例:

//给函数传入指针作为参数#include <iostream>using namespace std;void f( int *j); //函数原型中需要指针作为参数int main(){    int i;    int *p;    p = &i;    f(p);    cout << i; //i的值现在是了    return 0;}//f()函数是接收一个指针作为参数void f(int *j){    *j = 100;}
     仔细研究上面的程序。我们可以看到,函数f()接收一个参数:一个整型数的指针。在main()函数中,p被赋值为变量i的地址。接下来,调用函数f()的时候传入参数p。当函数f()中用形参j来接收传入的p的值后,j也就指向了main()函数中的变量i。因此,赋值语句

*j = 100;
就会使得i的值变为100。可见,函数f()会把100赋值给调用时传入的任何地址的变量。
    在上面的程序中,实际上我们没有必使用指针变量p。我们在调用函数f()的时候只需要在变量i的前面加上取地址符号&,传入到函数中即可。如下所示:

//给函数传入指针作为参数#include <iostream>using namespace std;void f( int *j); //函数原型中需要指针作为参数int main(){    int i;    f(&i);    cout << i; //i的值现在是了    return 0;}//f()函数是接收一个指针作为参数void f(int *j){    *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); //给函数传入一个数组    return 0;}//打印数组中的数字//参数声明为一个指定大小的数组void display (int num[10] ){    int i;        for ( i = 0; i < 10; i++) cout << num[i] << ' ';}
    在上面的程序中,尽管参数num被声明为一个含有10个元素的整型数数组,C++编译器会自动地把它转化为一个整型指针。这样做是有必要的,因为函数的参数实际上是不能接收整个数组的。既然,传入的只是一个指针,那就得有个指针参数来接收它。

第二种方式就是把函数的参数声明为不指定大小的数组,如下:

void display (int num[] ){    int i;        for ( i = 0; i < 10; i++) cout << num[i] << ' ';}
在这里,num被声明为一个没有指定大小的数组。由于在C++中是不进行数组边界检查的,所以数组的大小就和参数没有什么关系(但不是和整个程序没有关系)。C++编译器也同样会把这种声明方式转化成整型指针。
最后一种方式就是把参数声明为指针。这也是在专业的C++程序中最常用的一种方式。如下:
void display (int *num){    int i;        for ( i = 0; i < 10; i++) cout << num[i] << ' ';}
之所以可以这样做的原因就是任何指针都可以通过[]来进行索引,就像数组一样。上述的三种方式都会产生相同的结果,那就是指针。
当我们给一个函数传入数组的时候,我们实际上传入的是数组的地址,记住这一点是非常重要的。这就意味着函数中对形参的操作或者修改实际上都是对调用时传入数组的操作和修改。例如,在下面的程序中,函数cube()把数组中的数值转换为其值的立方,调用cube()函数的时候传入数组地址作为第一个参数,数组的大小最为第二个参数。

//调用函数来修改数组的元素值#include <iostream>using namespace std;void cube( int *n, int num);int main(){    int i, nums[10];    for( i = 0; i < 10; i++)    {        nums[i] = i+1;    }    cout << "Original contents: ";    for ( i = 0; i < 10; i++)    {        cout << nums[i] << ' ';    }    cout << '/n';    cube(nums, 10);    cout << "Altered contents: ";    for ( i = 0; i < 10; i++)    {        cout << nums[i] << ' ';    }        return 0;}void cube(int *n, int num){    while(num)    {        *n = *n * *n * *n;        num--;        n++;    }}


程序的输出如下:
Original contents: 1 2 3 4 5 6 7 8 9 10
Altered contents: 1 8 27 64 125 216 343 512 729 1000
     正如我们看到的那样,在调用了函数cube()以后,main()函数中数组nums的元素值都变成了原来值的立方。也就是说,数组nums中元素的数值都被cube()函数中的语句修改了,这就是因为传入的是指针。
传入字符串
    由于字符串就是一个使用了0作为结尾的字符数组,所以当我们传入字符串到函数中的时候,实际传入的是数组的首地址,也就是传入的是类型为char *的指针。例如下面的程序中定义了函数strInvertCase(),用来对字符串中字母的大小写进行转换。

//给函数传入字符串#include <iostream>#include <cstring>#include <cctype>using namespace std;void strInvertCase(char *str);int main(){    char str[80];    strcpy(str,"This Is A Test");    strInvertCase(str);    cout << str; //输出转换后的结果字符串    return 0;}//转换字符串中字符的大小写void strInvertCase(char *str){    while(*str)    {        //进行大小写的转换        if ( isupper(*str) ) *str = tolower(*str);        else if ( islower(*str) ) *str = toupper(*str);        str++;//指针移动的下一个字符处。    }}


程序的输出如下:
tHIS iS a tEST
练习:
    1. 如何声明一个无返回值的函数,它的名称为count,它有一个整型指针参数。
    2. 当给函数传入的是一个指针的时候,函数是否可以修改指针指向对象的内容?
    3. 是否可以把数组传入到函数中?请解释为什么?

 

原创粉丝点击