按值传递,引用传递
#include <iostream>
#include <string>
void printByValue(std::string val) //函数参数val是str的副本
{
std::cout << val << '\n'; // 通过副本打印值val
}
void printByReference(const std::string& ref) // 函数参数ref是绑定到str的引用
{
std::cout << ref << '\n'; // 通过引用打印值
}
int main()
{
std::string str{ "Hello, world!" };
printByValue(str); // 按值传递str,复制str
printByReference(str); //通过引用传递,不复杂str
return 0;
}
当我们按值传递参数str时,函数参数val接收参数的副本,因为参数val是副本,所有对val做任何更改,对原始数据不会有任何影响。
我们通过str引用传递时,ref绑定到实际参数,这样避免了复制参数,因为我们的参数是 const,所以我们不能改变ref. 但如果ref是非常量,我们所做的任何更改ref都会更改str。
地址传递
#include <iostream>
#include <string>
void printByValue(std::string val) //函数参数是str的副本
{
std::cout << val << '\n'; //通过副本打印值val
}
void printByReference(const std::string& ref) // 函数参数是绑定到str的引用
{
std::cout << ref << '\n'; // 通过引用打印值
}
void printByAddress(const std::string* ptr) // 函数参数是保存str地址的指针
{
std::cout << *ptr << '\n'; //间接通过地址打印值
}
int main()
{
std::string str{ "Hello, world!" };
printByValue(str); // 按值传递str,复制str
printByReference(str); // 通过引用传递str,不复制str
printByAddress(&str); //按地址传递str,不复制str
return 0;
}
printByAddress(&str); // 通过取地址符(&)获取str的地址
执行此调用时,&str将创建一个指针,该指针保存str,然后将该地址ptr作为函数调用的一部分复制到函数参数中,因为ptr现在指向的是地址str,所有函数间接引用ptr,它将获得str的值。
通过地址传递允许函数修改参数的值
当我们通过地址传递一个对象时,函数接收到传递对象的地址,可以通过解引用(*)来访问。因为这是传递实际参数对象的地址(不是副本),如果参数参数指向的是非常量指针,函数可以通过指针参数修改参数:
#include <iostream>
void changeValue(int* ptr) // note: ptr是指向的非常量指针
{
*ptr = 6; // 将值改为6
}
int main()
{
int x{ 5 };
std::cout << "x = " << x << '\n';
changeValue(&x); // 我们将x的地址传递给函数
std::cout << "x = " << x << '\n';
return 0;
}
控制台输出:
x = 5
x = 6
如您所见,参数已修改,即使在changeValue()完成运行后,此修改仍存在。
void changeValue(const int* ptr) // note:ptr现在是指向常量的指针
{
*ptr = 6; // error: 无法更改常量值
}
下面这个程序看起来很无辜
#include <iostream>
void print(int* ptr)
{
std::cout << *ptr;
}
int main()
{
int x{ 5 };
print(&x);
int* myptr {};
print(myptr);
return 0;
}
运行程序时,打印5后,然后可能会崩溃。
在调用print(myptr)时,myptr是一个空指针,所示函数参数ptr也是一个空指针,当函数体中使用空指针时,会产生未定义行为。通过地址传递参数时,应注意群指针不是空指针,然后在使用该参数地址,加一条判断语句:
#include <iostream>
void print(int* ptr)
{
if (ptr) // 如果ptr不是空指针
{
std::cout << *ptr;
}
}
int main()
{
int x{ 5 };
print(&x);
print(nullptr);
return 0;
}
更改指针参数指向的内容
#include <iostream>
void nullify(int* ptr2)
{
ptr2 = nullptr; // Make the function parameter a null pointer
}
int main()
{
int x{ 5 };
int* ptr{ &x }; // ptr points to x
std::cout << "ptr is " << (ptr ? "不为空\n" : "空\n");
nullify(ptr);
std::cout << "ptr is " << (ptr ? "不为空\n" : "空\n");
return 0;
}
ptr is 不为空
ptr is 不为空
如您所见,更改ptr2地址,对原始参数ptr没有影响。当nullify(ptr)被调用时,ptr2接收传入的是ptr地址的副本,当函数更改ptr2指向的内容时,这只影响持有的副本ptr,而不是原始参数。
是的,是一这么回事。就像我们可以通过引用传递普通变量一样,我们也可以通过引用传递指针。这是与上面相同的程序,ptr2更改为对地址的引用:
#include <iostream>
void nullify(int*& refptr) // refptr is now a reference to a pointer
{
refptr = nullptr; // Make the function parameter a null pointer
}
int main()
{
int x{ 5 };
int* ptr{ &x }; // ptr points to x
std::cout << "ptr is " << (ptr ? "non-null\n" : "null\n");
nullify(ptr);
std::cout << "ptr is " << (ptr ? "non-null\n" : "null\n");
return 0;
}
ptr is non-null
ptr is null