• C++中将指针传递给函数


    C++中将指针传递给函数

    指针是一种将内存空间传递给函数的有效方式,其中可包含函数完成其工作所需的数据,也可包含操作结果。将指针作为函数参数时,确保函数只能修改您希望它修改的参数很重要。例如,如果函数根据以指针方式传入的半径计算圆的面积,就不应允许它修改半径。为控制函数可修改哪些参数以及不能修改哪些参数,可使用关键字 const,如以下示例程序所示:

    #include 
    using namespace std;
    
    void CalcArea(const double* const ptrPi, // const pointer to const data
                  const double* const ptrRadius, // i.e. no changes allowed
                  double* const ptrArea)  // can change data pointed to
    {
        // check pointers for validity before using!
        if (ptrPi && ptrRadius && ptrArea) 
            *ptrArea = (*ptrPi) * (*ptrRadius) * (*ptrRadius);
    }
    
    int main()
    {
        const double Pi = 3.1416;
    
        cout << "Enter radius of circle: ";
        double radius = 0;
        cin >> radius;
    
        double area = 0;
        CalcArea (&Pi, &radius, &area);
    
        cout << "Area is = " << area << endl;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    输出:

    Enter radius of circle: 10.5
    Area is = 346.361
    
    • 1
    • 2

    分析:

    第 3~5 行演示了两种 const 指针, ptrRadius 和 ptrPi 被声明为“指向 const 数据的 const 指针”,因此不能修改指针包含的地址,也不能修改它指向的数据。 ptrArea 显然是用于存储输出的参数,因为不能修改该指针的值(地址),但可修改它指向的数据。第 8 行在使用函数的指针参数前检查其有效性。在调用者不小心将这三个参数之一设置为 NULL 指针时,您不希望函数计算面积,因为这种非法访问将导致应用程序崩溃。

    无可否认,引用变量比指针更容易处理,因为引用变量隐藏了所有的解引用和间接引用"机制"。但是,程序员仍然应该学会使用指针作为函数参数,因为有一些任务,特别是在处理 C 字符串时,最好使用指针完成、另外,C++库中还有许多使用指针作为形参的函数。

    以下是使用指针形参的函数的定义:

    void doubleValue(int *val)
    {
        *val *= 2;
    }
    
    • 1
    • 2
    • 3
    • 4

    这个函数的目的是使 val 指向的变量翻倍。当 val 被解引用时,*= 运算符对 val 指向的变量起作用。该语句可以将地址存储在 val 中的原始变量乘以 2。当然,当调用该函数时,必须使用被翻倍的变量地址作为实参,而不是变量本身作为实参。

    以下是一个调用 doubleValue 函数的示例:

    doubleValue(&number);
    
    • 1

    该语句使用了地址运算符(&)将 number 的地址传递到 val 形参中。函数执行后,number 的内容将被乘以 2。下面的程序演示了该函数的用法:

    //This program uses two functions that accept addresses of variables as arguments.
    #include 
    using namespace std;
    //Function prototypes
    void getNumber(int *);
    void doubleValue(int *);
    
    int main()
    {
        int number;
        //Call getNumber and pass the address of number
        getNumber(&number);
        // Call doubleValue and pass the address of number
        doubleValue(&number);
        // Display the value in number
        cout << "That value doubled is " << number << endl;
        return 0;
    }
    void getNumber(int *input)
    {
        cout << "Enter an integer number: ";
        cin >> *input;
    }
    
    void doubleValue(int *val)
    {
        *val *= 2;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    程序输出结果:

    Enter an integer number: 10
    That value doubled is 20
    
    • 1
    • 2

    此程序有两个使用指针作为参数的函数。请看以下函数原型:

    void getNumber(int *);
    void doubleValue(int *);
    
    • 1
    • 2

    每一个函数原型都使用符号 int * 来表示该形参是一个指向 int 的指针。与所有其他类型的形参一样,不需要在原型中指定变量的名称,但星号(*)则是必需。

    getNumber 函数要求用户输入一个整数值。以下 cin 语句可以将用户输入的值存储在内存中:

    cin >> *input;
    
    • 1

    间接运算符会使用户输入的值存储在 input 指向的变量中,而不是 input 中。

    在上面的语句中,使用间接运算符是非常重要的。没有它,则 cin 会将用户输入的值存储在 input 中,就像该值是一个内存地址一样。如果发生这种情况,则 input 将不再指向 main 函数中的 number 变量。如此一来,对该指针(input)的后续使用即使不会产生灾难性的结果,也必然出现错误。

    当调用 getNumber 函数时,函数 main 中 number 变量的地址作为实参传递。该函数执行后,用户输入的数值将被存储在 number 中。接下来,调用 doubleValue 函数,同样是将 number 的地址作为实参传递,这使得 number 被乘以 2。

    指针变量也可以用来接收数组地址作为实参,此后,无论是下标还是指针符号都可以用来处理数组的内容。下面的程序演示了这一点:

    //This program demonstrates that a pointer may be used as a parameter to accept the address of an array. Either subscript or pointer notation may be used.
    #include 
    #include 
    using namespace std;
    // Function prototypes
    void getSales(double *sales, int size);
    double totalSales(double *sales, int size);
    
    int main()
    {
        const int QUARTERS = 4;
        double sales[QUARTERS];
    
        getSales(sales, QUARTERS);
        cout << setprecision(2);
        cout << fixed << showpoint;
        cout << "The total sales for the year are $";
        cout << totalSales(sales, QUARTERS) << endl;
        return 0;
    }
    void getSales(double *array, int size)
    {
        for (int count = 0; count < size; count++)
        {
            cout << "Enter the sales figure for quarter ";
            cout << (count + 1) << ": ";
            cin >> array[count];
        }
    }
    
    double totalSales(double *array, int size)
    {
        double sum = 0.0;
        for (int count = 0; count < size; count++)
        {
            sum += *array;
            array++;
        }
        return sum;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40

    程序输出结果:

    Enter the sales figure for quarter 1: 10263.98
    Enter the sales figure for quarter 2: 12369.69
    Enter the sales figure for quarter 3: 11542.13
    Enter the sales figure for quarter 4: 14792.06
    The total sales for the year are $48967.86
    
    • 1
    • 2
    • 3
    • 4
    • 5

    请注意,该程序的 getSales 函数中,即使把形参 array 定义为一个指针,其下标符号仍然可以在 cin 语句中使用:

    cin >> array[count];
    
    • 1

    在 totalSales 函数中,array 还可以与以下语句中的间接运算符一起使用:

    sum += *array;
    
    • 1

    而在接下来的语句中,array 中的地址则可以递增,以使指向下一个元素:

    array++;
    
    • 1

    上面介绍的两个语句也可以合并成以下语句:

    sum += *array++;
    
    • 1

    * 运算符将首先解引用 array,然后 ++ 运算符将使得 array 中的地址递增。

    该文章会更新,欢迎大家批评指正。

    推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
    分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
    fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
    TCP/IP,协程,DPDK等技术内容
    点击立即学习:C/C++后台高级服务器课程

  • 相关阅读:
    基于FPGA的呼叫设备verilog开发
    vscode在ubuntu调试
    彻底理解线程
    MySQL常用指令整理
    深度学习入门(五十二)计算机视觉——风格迁移
    [一周AI简讯]OpenAI宫斗;微软Bing Chat更名Copilot;Youtube测试音乐AI
    pytorch初学笔记(九):神经网络基本结构之卷积层
    前端问题解决方法
    五.docker+jenkins自动部署项目
    STM32CubeMX 下载和安装 详细教程
  • 原文地址:https://blog.csdn.net/qq_41317716/article/details/133419650