12 按值传递,引用传递

按值传递,引用传递
#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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值