c++ 指针和参数传递

指针

如下所示:
1. 定义a为一个int型变量,a的值为3
2. 定义b为一个int型的指针,b的值为变量a的地址
3. 定义c为一个指向指针的int型指针,c的值为指针b的地址。

int a = 3;
int *b = &a; // int *b; b = &a;
int **c = &b; // int **c; c = &b;

输出a,b,c的信息,如下所示:

cout << hex << "a   = " << a << endl;
cout << hex << "&a  = " << &a << endl;

cout << hex << "b   = " << b << endl;
cout << hex << "*b  = " << *b << endl;
cout << hex << "&b  = " << &b << endl;

cout << hex << "c   = " << c << endl;
cout << hex << "*c  = " << *c << endl;
cout << hex << "**c = " << **c << endl;
cout << hex << "&c  = " << &c << endl;

其中,&a表示取变量a的地址,&b表示取变量b的地址,&c表示取变量c的地址。另外,*c表示*(&b),也就是b**c表示*(*(&b)),也就是*(b),也就是*(&a),也就是a

结果如下:

a   = 3
&a  = 0x28ff0c
b   = 0x28ff0c
*b  = 3
&b  = 0x28ff08
c   = 0x28ff08
*c  = 0x28ff0c
**c = 3
&c  = 0x28ff04

在内存中的分布如下所示:

enter image description here

参数传递——值传递

c++通常按照值传递参数,这意味着将数值参数传递给函数,而后者将其赋给一个新的变量。用于接收传递值的变量称为形参(用参数argument表示)。传递给函数的值称为实参(用参量parameter表示)。

例如下面的程序:

#include <iostream>
using namespace std;
void SetA(int iA)
{
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
    iA = 4;
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
}
int main()
{
    int a = 3;

    cout << hex << "a   = " << a << endl;
    cout << hex << "&a  = " << &a << endl;

    SetA(a);

    cout << hex << "a   = " << a << endl;
    cout << hex << "&a  = " << &a << endl;
    return 0;
}

输出结果如下所示:

a   = 3
&a  = 0x28ff0c
iA   = 3
&iA  = 0x28fef0
iA   = 4
&iA  = 0x28fef0
a   = 3
&a  = 0x28ff0c

在函数中声明的变量(包括参数)是该函数私有的。在函数被调用时,计算机为这些变量分配内存,在函数结束时,计算机将释放这些变量使用的内存。

调用SetA函数:

  1. 声明int型形参变量iA,重新开辟了内存空间
  2. 把a的值(3)赋给iA,也就是把a的值存在新开辟的空间
  3. 把4赋给iA,也就是把4存在iA指向的空间
  4. 函数结束,释放开辟的(iA)指向的空间

因为SetA函数不知道a指向何处,传到函数内部的只是a里面存的值,所以SetA函数无法修改a指向的内存空间的内容。也就是说:a指向的内存空间的内容自始至终都没有改变。

参数传递——地址传递

上面已经介绍,因为在SetA函数内部不知道变量a的地址,所以没有办法修改变量a的值。那么很显然,如果把变量a的地址传入SetA函数内部,那么就可以修改变量a的值。

看下面的代码:

#include <iostream>
using namespace std;
void SetA(int *iA)
{
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
    cout << hex << "*iA  = " << *iA << endl;
    *iA = 4;
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
    cout << hex << "*iA  = " << *iA << endl;
}
int main()
{
    int a = 3;

    cout << hex << "a    = " << a << endl;
    cout << hex << "&a   = " << &a << endl;

    SetA(&a);

    cout << hex << "a    = " << a << endl;
    cout << hex << "&a   = " << &a << endl;
    return 0;
}

输出结果如下所示:

a    = 3
&a   = 0x28ff0c
iA   = 0x28ff0c
&iA  = 0x28fef0
*iA  = 3
iA   = 0x28ff0c
&iA  = 0x28fef0
*iA  = 4
a    = 4
&a   = 0x28ff0c

调用SetA函数:

  1. 声明int型指针形参变量iA,重新开辟了内存空间
  2. 把a的地址(&a)赋给iA,也就是把a的地址存在新开辟的空间,如图所示:

    enter image description here

  3. 把4赋给*iA指向的内存空间,也就是把4存在*(&a)指向的空间,如图所示:

    enter image description here

  4. 函数结束,释放开辟的(iA)指向的空间,而对a的修改依然有效

由于变量a的地址也传入了SetA函数内部,因此可以借助该地址对变量a进行修改。

参数传递——间接地址传递

通过地址传递可以在函数内部实现修改函数外的变量,通过间接地址传递也可以实现这样的目的。

看下面的代码:

#include <iostream>
using namespace std;
void SetA(int **iA)
{
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
    cout << hex << "*iA  = " << *iA << endl;
    cout << hex << "**iA = " << **iA << endl;
    **iA = 4;
    cout << hex << "iA   = " << iA << endl;
    cout << hex << "&iA  = " << &iA << endl;
    cout << hex << "*iA  = " << *iA << endl;
    cout << hex << "**iA = " << **iA << endl;
}
int main()
{
    int a = 3;
    int *b = &a; // int *b; b = &a;

    cout << hex << "a    = " << a << endl;
    cout << hex << "&a   = " << &a << endl;

    cout << hex << "b    = " << b << endl;
    cout << hex << "*b   = " << *b << endl;
    cout << hex << "&b   = " << &b << endl;

    SetA(&b);

    cout << hex << "a    = " << a << endl;
    cout << hex << "&a   = " << &a << endl;

    cout << hex << "b    = " << b << endl;
    cout << hex << "*b   = " << *b << endl;
    cout << hex << "&b   = " << &b << endl;

    return 0;
}

输出结果如下所示:

a    = 3
&a   = 0x28ff0c
b    = 0x28ff0c
*b   = 3
&b   = 0x28ff08
iA   = 0x28ff08
&iA  = 0x28fef0
*iA  = 0x28ff0c
**iA = 3
iA   = 0x28ff08
&iA  = 0x28fef0
*iA  = 0x28ff0c
**iA = 4
a    = 4
&a   = 0x28ff0c
b    = 0x28ff0c
*b   = 4
&b   = 0x28ff08

调用SetA函数:

  1. 声明int型指向指针的指针形参变量iA,重新开辟了内存空间
  2. 把b的地址(&b)赋给iA,也就是把b的地址存在新开辟的空间,如图所示:

    enter image description here

  3. 把4赋给**iA指向的内存空间,也就是把4存在**(&b)指向的空间,也就是把4存在*b指向的内存空间,也就是把4存在*(&a)指向的内存空间,也就是把4存在a指向的内存空间,如图所示:

    enter image description here

  4. 函数结束,释放开辟的(iA)指向的空间,而对a的修改依然有效

参数传递——指针传递

为什么要用间接地址传递,是因为有些时候只知道一个指针,而又要有效的把指针传入到函数内部,例如结构体。

看下面代码:

#include <iostream>
using namespace std;
struct Node
{
    int value;
    int data;

    Node()
    {
        this->value = 0;
        this->data = 0;
    }
};
void InitNode(Node **ppNode, int val, int dat)
{
    (*ppNode)->value = val;
    (*ppNode)->data = dat;

    cout << "ppNode  = " << ppNode << endl;
    cout << "&ppNode = " << &ppNode << endl;
}
int main()
{
    Node *pNode = new Node();

    cout << "value   = " << pNode->value << endl;
    cout << "data    = " << pNode->data << endl;
    cout << "pNode   = " << pNode << endl;
    cout << "&pNode  = " << &pNode << endl;

    InitNode(&pNode, 1, 2);

    cout << "value   = " << pNode->value << endl;
    cout << "data    = " << pNode->data << endl;
    cout << "pNode   = " << pNode << endl;
    cout << "&pNode  = " << &pNode << endl;
    return 0;
}

输出结果如下所示:

value   = 0
data    = 0
pNode   = 0x502fb8
&pNode  = 0x28ff0c
ppNode  = 0x28ff0c
&ppNode = 0x28fef0
value   = 1
data    = 2
pNode   = 0x502fb8
&pNode  = 0x28ff0c

调用InitNode函数:

  1. 声明Node型指向指针的指针形参变量ppNode,int型形参变量val和int型形参变量dat,重新开辟了内存空间
  2. 把pNode的地址(&pNode)赋给ppNode,也就是把pNode的地址存在新开辟的ppNode指向的地址空间;把1赋给新开辟的val指向的地址空间;把2赋给新开辟的dat指向的地址空间。如图所示:

    enter image description here

  3. (*ppNode)指向主函数中开辟的Node节点。把val指向的值赋给(*ppNode)指向的内存空间中的value;把dat指向的值赋给(*ppNode)指向的内存空间中的data。如图所示:

    enter image description here

  4. 函数结束,释放开辟的ppNode指向的空间,而对pNode指向的内存空间的修改依然有效。

代码

GitHub

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值