Learn C++学习笔记:第七章— 函数参数和通过值、引用和地址传递参数

函数的参数

形参:函数声明中表示的变量,比如下面的x

void foo(int x)
{
}

实参:函数调用时实际传递到函数的参数,比如下面的y

void foo(int x)
{
}
foo(y);

将参数传递给函数的主要方法有3种:按值传递,按引用传递和按地址传递。

通过值传递函数参数

通过值进行传递是最直观方式,示例:

#include <iostream>
 
void foo(int y)
{
    std::cout << "y = " << y << '\n';
}
 
int main()
{
    foo(5); // first call
 
    int x = 6;
    foo(x); // second call
    foo(x+1); // third call
 
    return 0;
}

将数字5xx+1的值直接传递给函数,其特点就是将这些值赋值到函数的形参y里,所以函数不会对原数据产生更改。

  • When to use按值传递:除了结构和类,基本上可以传递所有。
  • 优点:①不会修改参数;②传递类型很多
  • 缺点:需要复制进函数,所以性能可能存在下降,在变量比较大或者运算次数较多时。

通过引用传递函数参数

为了解决变量传递函数参数的两个问题①复制会导致的性能变慢,②无法修改外部值只能通过返回值跟调用者交互;则通过引用传递函数参数可以解决这个问题。
语法:只需要函数声明时变成引用声明即可。

void addOne(int &ref) // ref is a reference variable
{
    ref = ref + 1;
}

int main()
{
    int value = 5;
 
    cout << "value = " << value << '\n';
    addOne(value);
    cout << "value = " << value << '\n';
    return 0;
}

由于引用可以修改外部参数,所以如果函数要返回多个值,除了结构体之外,还可以使用引用。但是这在语义上是不明显的,输出参数放到输入参数上,容易出错,所以并不推荐,如果要使用此功能,最好在需要更改的参数上加上前缀out-

const引用
如果只是想利用它不复制性能快的优点,但是不希望这个参数可以被改变,则可以给引用前加上const限制。并且const引用可以传递变量也可以传递常量,并且还能传递右值。

指针引用
可以通过引用传递指针,并使函数完全更改指针的地址。

#include <iostream>
 
void foo(int *&ptr) // pass pointer by reference
{
	ptr = nullptr; // this changes the actual ptr argument passed in, not a copy
}
 
int main()
{
	int x = 5;
	int *ptr = &x;
	std::cout << "ptr is: " << (ptr ? "non-null" : "null") << '\n'; // prints non-null
	foo(ptr);
	std::cout << "ptr is: " << (ptr ? "non-null" : "null") << '\n'; // prints null
 
	return 0;
}

数组引用
引用数组时,如果涉及到for-each循环、排序这种需要知道数组具体大小,则在引用时需要写明数组大小,并且&符号用括号隔开如(&array)[4],要不然如果是&array[4]则会变成对数组元素array[4]的引用。

#include <iostream>
 
// Note: You need to specify the array size in the function declaration
void printElements(int (&arr)[4])
{
  int length{ sizeof(arr) / sizeof(arr[0]) }; // we can now do this since the array won't decay
  
  for (int i{ 0 }; i < length; ++i)
  {
    std::cout << arr[i] << std::endl;
  }
}
 
int main()
{
    int arr[]{ 99, 20, 14, 80 };
    
    printElements(arr);
 
    return 0;
}

通过指针传递函数参数

指针也是变量的一种类型,所以也可以用于传递函数参数。

通过地址传递的优点:

  • 通过地址传递允许函数更改参数的值,这有时很有用。否则,可以使用const来确保函数不会更改参数。(但是,如果要使用非指针执行此操作,则应改用按引用传递)。
  • 由于未复制参数,因此即使与大型结构或类一起使用时,它也很快速。
    我们可以通过out参数从一个函数返回多个值。

通过地址传递的缺点:

  • 因为文字和表达式没有地址,所以指针参数必须是普通变量。
    必须检查所有值以查看它们是否为空。尝试取消引用空值将导致崩溃。很容易忘记这样做。
  • 因为取消引用指针比直接访问值要慢,所以访问由地址传递的参数要比访问由值传递的参数慢。

何时使用按地址传递:

  • 传递内置数组时(如果您可以接受它们会衰减为指针的事实)。
  • 在传递指针和nullptr时,在逻辑上是有效的参数。

传递结构或类时(使用按引用传递)。
传递基本类型时(使用按值传递)。
如您所见,按地址传递和按引用传递具有几乎相同的优点和缺点。由于按引用传递通常比按地址传递更安全,因此在大多数情况下应首选按引用传递。

普通的按指针传递函数的示例:

#include <iostream>
 
void foo(int *ptr)
{
    *ptr = 6;
}
 
int main()
{
    int value = 5;
 
    std::cout << "value = " << value << '\n';
    foo(&value);
    std::cout << "value = " << value << '\n';
    return 0;
}

关于指针传递的几个注意事项:
①由于传递数组时数组会衰减成指针,所以长度参数必须单独传递。

//输出数组的每一个数字
void printArray(int *array, int length)
{

    if (!array)
        return;
 
    for (int index=0; index < length; ++index)
        cout << array[index] << ' ';
}
 
int main()
{
    int array[6] = { 6, 5, 4, 3, 2, 1 };
    printArray(array, 6);
}

②如果传入的指针参数不可修改,则使用const关键字,比如上面的子函数定义可以改为:

void printArray(const int *array,int length)

③指针也是一种变量,所以把指针当成变量的话很容易理解,传入函数的实参实际上是复制进形参的,也就是形参这个变量在函数内部可以被改变指向其他的地址,这并不会对外部的指针及其它指向的变量产生影响。
如果对形参解引用才会对该位置的变量产生影响。

#include <iostream>

void setToNull(int *tempPtr)
{
    tempPtr = nullptr; 
}
 
 void setToNull_2(int *tempPtr)
{
    *tempPtr = 6; 
}
 
int main()
{ 
    // First we set ptr to the address of five, which means *ptr = 5
    int five = 5;
    int *ptr = &five;
	
    // This will print 5
    std::cout << *ptr;
 
    // tempPtr is set as a reference to ptr
    setToNull(ptr);
    if (ptr)
        std::cout << *ptr;
    else
        std::cout << " ptr is null";
 
     setToNull_2(ptr);
    if (ptr)
        std::cout << *ptr;
    else
        std::cout << " ptr is null";
    return 0;
}

输出:
55
6
④如果就是想通过函数修改实参指针的指向呢?正好,这就是引用的功能,使用引用指针即可。
将上述子函数改成:

void setToNull(int *&tempPtr)
{
    tempPtr = nullptr; // use 0 instead if not C++11
}

以值、引用和指针方式函数return






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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值