指针
如下所示:
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
在内存中的分布如下所示:
参数传递——值传递
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
函数:
- 声明int型形参变量
iA
,重新开辟了内存空间 - 把a的值(3)赋给
iA
,也就是把a的值存在新开辟的空间 - 把4赋给
iA
,也就是把4存在iA
指向的空间 - 函数结束,释放开辟的(
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
函数:
- 声明int型指针形参变量
iA
,重新开辟了内存空间 -
把a的地址(
&a
)赋给iA
,也就是把a的地址存在新开辟的空间,如图所示: -
把4赋给
*iA
指向的内存空间,也就是把4存在*(&a)
指向的空间,如图所示: -
函数结束,释放开辟的(
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
函数:
- 声明int型指向指针的指针形参变量
iA
,重新开辟了内存空间 -
把b的地址(
&b
)赋给iA
,也就是把b的地址存在新开辟的空间,如图所示: -
把4赋给
**iA
指向的内存空间,也就是把4存在**(&b)
指向的空间,也就是把4存在*b
指向的内存空间,也就是把4存在*(&a)
指向的内存空间,也就是把4存在a指向的内存空间,如图所示: -
函数结束,释放开辟的(
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
函数:
- 声明Node型指向指针的指针形参变量
ppNode
,int型形参变量val
和int型形参变量dat
,重新开辟了内存空间 -
把pNode的地址(
&pNode
)赋给ppNode
,也就是把pNode的地址存在新开辟的ppNode
指向的地址空间;把1赋给新开辟的val
指向的地址空间;把2赋给新开辟的dat
指向的地址空间。如图所示: -
(*ppNode)
指向主函数中开辟的Node节点。把val
指向的值赋给(*ppNode)
指向的内存空间中的value
;把dat
指向的值赋给(*ppNode)
指向的内存空间中的data
。如图所示: -
函数结束,释放开辟的
ppNode
指向的空间,而对pNode
指向的内存空间的修改依然有效。