C++中关于*、&、*&以及&*的解析.md

由一道牛客网《剑指offer》的编程题引发的思考,题目如下:

二叉搜索树与双向链表:输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的节点,只能调整树中结点指针的指向。

按照递归的解题思路,有如下解答:

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
/*
struct TreeNode {
int val;
struct TreeNode *left;
struct TreeNode *right;
TreeNode(int x) :
val(x), left(NULL), right(NULL) {
}
};*/
class Solution {
public:
TreeNode* Convert(TreeNode* pRootOfTree)
{
if(pRootOfTree==nullptr) return nullptr;
TreeNode* prenode = nullptr;
recurve(pRootOfTree,prenode);
while(pRootOfTree->left!=nullptr)
pRootOfTree = pRootOfTree->left;
return pRootOfTree;

}

void recurve(TreeNode* root, TreeNode*& prenode){
if(root->left!=nullptr)
recurve(root->left,prenode);

root->left = prenode;
if(prenode!=nullptr) prenode->right = root;
prenode = root;

if(root->right!=nullptr)
recurve(root->right,prenode);
}
};

代码中23行使用了TreeNode*& prenode,这里,如果缺少了&,则结果会出错!

以下,对C++中*、&、*&以及&* 四种形式展开讨论。

* 代表指针

& 代表引用、别名

指针和引用的区别之一:

参数传递时,不管是传值还是传指针,函数都会产生一个临时副本变量,但在传引用时,不会生成临时变量。

*& 首先是一个指针,然后前面的&代表是这个指针的引用。 指针的引用其实就是指针的一个别名,和指针具有相同的地址。

&* 首先是一个变量的引用,然后是指向这个引用的指针,但是,因为引用不是对象,没有实际的地址,因此 不能定义指向引用的指针

问题:向函数中传递指针和传递指针的引用的区别

如果传递的是指针,那么会先复制该指针,在函数内部使用的是复制后的指针,这个指针与原来的指针虽然指向相同的地址,但是如果在函数内部将复制后的指针指向了另外的地址,那么不会影响原来的指针。

但是对于传递指针的引用,如果将传递进来的指针指向了新的地址,那么原始的指针也会指向新的地址,这也是为什么在该题中,必须使用指针的引用,而不能使用指针的原因。就是因为在这段代码中,要对指针指向的值进行更改,而在递归的函数中,又需要保证prenode指向的值保持统一,因此,必须使用指针的引用来使在不同层的递归函数中,prenode指向的值都是一样的。

在传递指针的引用时,还有另外一个问题,那就是如果由于原始的指针不再指向原始对象了,所以如果没有其他指针指向该原始对象的话,就会造成内存泄漏。同理,如果在函数内释放了指针的引用,那么在函数外部就不能在使用原来的指针了,因为原来的内存已经被释放了。