在C++编程中,指针和引用是两个非常强大的特性,它们允许程序员直接操作内存地址。然而,正确理解并使用指针和引用的高级形式,如指针到指针(ptr-to-ptr)和引用到指针(ref-to-ptr),对于编写高效且可维护的代码至关重要。本文将详细探讨这些概念,并提供实例代码,帮助读者更好地理解它们在函数中传递指针时的重要性。
当通过指针传递参数给函数时,实际上传递的是指针的副本。这意味着,如果函数内部修改了指针,那么修改的只是指针的副本,原始指针并不会受到影响。这在某些情况下会导致问题。以下是一个C++示例,展示了这种行为:
int g_n = 42;
void example_ptr() {
int n = 23;
int *pn = &n
std::cout << "example_ptr()" << std::endl;
std::cout << "Before :" << *pn << std::endl; // 显示 23
func_ptr(pn);
std::cout << "After :" << *pn << std::endl; // 显示 23
}
void func_ptr(int *pp) {
pp = &g_n;
}
在这个例子中,尽管函数func_ptr
修改了指针pp
,但原始指针pn
并没有改变。这是因为pp
只是pn
的一个副本。
指针到指针允许在函数内部修改指针的地址。以下是如何使用指针到指针参数调用函数的示例:
int g_n = 42;
void example_ptr_to_ptr() {
int n = 23;
int *pn = &n
std::cout << "example_ptr_to_ptr()" << std::endl;
std::cout << "Before :" << *pn << std::endl; // 显示 23
func_ptr_to_ptr(&pn);
std::cout << "After :" << *pn << std::endl; // 显示 42
}
void func_ptr_to_ptr(int **pp) {
*pp = &g_n;
}
在这个例子中,函数func_ptr_to_ptr
通过指针到指针参数修改了指针pn
的地址,从而使得pn
指向了全局变量g_n
。
引用到指针是C++特有的语法,它允许通过引用直接修改指针。以下是如何使用引用到指针参数调用函数的示例:
int g_n = 42;
void example_ref_to_ptr() {
int n = 23;
int *pn = &n
std::cout << "example_ref_to_ptr()" << std::endl;
std::cout << "Before :" << *pn << std::endl; // 显示 23
func_ref_to_ptr(pn);
std::cout << "After :" << *pn << std::endl; // 显示 42
}
void func_ref_to_ptr(int *&pp) {
pp = &g_n;
}
在这个例子中,函数func_ref_to_ptr
通过引用到指针参数直接修改了指针pn
,使其指向了全局变量g_n
。
另一种修改指针的方法是直接在函数中返回新的指针。以下是如何实现的示例:
int g_n = 42;
void example_ret_ptr() {
int n = 23;
int *pn = &n
std::cout << "example_ret_ptr()" << std::endl;
std::cout << "Before :" << *pn << std::endl; // 显示 23
pn = func_ret_ptr();
std::cout << "After :" << *pn << std::endl; // 显示 42
}
int *func_ret_ptr() {
return &g_n;
}
在这个例子中,函数func_ret_ptr
返回了全局变量g_n
的地址,然后在函数example_ret_ptr
中,将指针pn
更新为这个新地址。
与返回指针类似,也可以通过返回引用来修改指针。以下是如何实现的示例:
int g_n = 42;
void example_ret_ref() {
int n = 23;
int *pn = &n
std::cout << "example_ret_ref()" << std::endl;
std::cout << "Before :" << *pn << std::endl; // 显示 23
pn = &func_ret_ref();
std::cout << "After :" << *pn << std::endl; // 显示 42
}
int& func_ret_ref() {
return g_n;
}
在这个例子中,函数func_ret_ref
返回了全局变量g_n
的引用,然后在函数example_ret_ref
中,将指针pn
更新为这个引用。
指针到指针和引用到指针都可以用于修改指针,但它们之间并没有明显的优劣之分。选择使用哪一种通常取决于个人偏好。有些程序员认为引用到指针的语法更“干净”,而有些程序员则认为指针到指针的语法更清晰。
不要将所有的指针到指针参数都视为纯粹的指针到指针。例如,有些人会将int main(int argc, char *argv[])
误写为int main(int argc, char **argv)
,但实际上**argv
是一个指针数组。在使用指针到指针参数时,一定要先查阅库文档。
void test(int *& rpInt) {
std::cout << "type of *&rpInt: " << typeid(rpInt).name() << std::endl;
// 将显示 int *
}