C++之值传递&指针传递&引用传递详解

九路
• 阅读 644

C++之值传递&指针传递&引用传递详解

目录


1.函数基础

一个函数由以下部分组成:

  • 返回类型
  • 函数名
  • 参数(0个或多个)
  • 函数体

其中,函数的参数叫做形参,函数执行的操作的语句块叫做函数体


2.值传递

像一个这样swap函数,调用的时候,会用实参_初始化_swap函数对应的形参

void Swap(int a, int b)
{
  int tmp = a;
  a = b;
  b = tmp;
}

在内存中会拷贝一份实参的值,但是修改形参的值并不影响实参的值

  • 测试用例
#include <iostream>

void Swap(int a, int b)
{
    int tmp = a;
    a = b;
    b = tmp;
}

int main()
{

    int n = 0;
    int i = 1024;

    Swap(n, i);
    std::cout << "n: " << n << "\ni: " << i << std::endl;

    // 运行结果
    // n: 0
    // i: 1024

    return 0;
}
int n = 0;
int i = n; // i是n的值的副本
i = 42;

3.指针传递

指针的行为和其他非引用类型一样。当执行指针拷贝操作时,拷贝的是指针的值。

拷贝之后,两个指针是不同的指针。因为指针使我们可以间接地访问它所指的对象,所以通过指针可以修改它所指对象的值

void SwapPoniter(int *a, int *b)
{
  int tmp = *a;
  *a = *b;
  *b = tmp;
}
  • 测试用例
#include <iostream>

void SwapPoniter(int *a, int *b)
{
    int tmp = *a;
    *a = *b;
    *b = tmp; // 修改了指针b指向的对象的值
    b = 0; // 只改变了函数体中的内存拷贝,实参并没有被修改
}

int main()
{

    int n = 0;
    int i = 1024;
    int *j = &n;
    int *k = &i;

    SwapPoniter(j, k);
    std::cout << "j: " << *j << "\nk: " << *k << std::endl;

    // 运行结果
    // j: 1024
    // k: 0

    return 0;
}
int n = 0, i = 1024;
int *p = &n, *q = &i;      // p指向n;q指向i
*p = 1024;                 // n的值被修改;p不变
p = q;                     // p现在指向了i;但是n与i的值都不变

传递指针,就是拷贝一个指针,它储存的值是一样的,解引用后是指向同一个对象,但是修改指针的值就是修改拷贝对象的值

在C语言中,大多数程序员都用得指针类型的形参去访问函数的外部对象,在C++中,建议使用引用类型的形参代替指针


4.引用传递

引用传递跟指针传递有点类似,使用引用传参,允许函数访问,改变一个或多个实参的值

void SwapQuote(int &a, int &b)
{
  int tmp = a;
  a = b;
  b = tmp;
}
  • 测试用例
#include <iostream>

void SwapQuote(int &a, int &b)
{
  int tmp = a;
  a = b;
  b = tmp;
}

int main()
{

  int n = 0;
  int i = 1024;

  SwapQuote(n, i);
  std::cout << "n: " << n << "\ni: " << i << std::endl;

  // 运行结果
  // n: 1024
  // i: 0

  return 0;
}
  • 使用引用传递可以避免拷贝
  1. 拷贝大的类类型对象或者容器对象比较低效,甚至有的类类型(包括IO类型在内)根本就不支持拷贝操作。当某种类型不支持拷贝操作时,函数只能通过引用形参访问该类型的对象。

举个例子,我们准备编写一个函数比较两个string对象的长度。因为string对象可能会非常长,所以应该尽量避免直接拷贝它们,这时使用引用形参是比较明智的选择。又因为比较长度无须改变string对象的内容,所以把形参定义成对常量的引用

  1. 当我们只是单纯读取实参,并不打算修改时,尽量使用常量引用
#include <iostream>

void testprint(const int &a)
{
  std::cout << "a: " << a << std::endl;
}

int main()
{
  int num = 111;
  testprint(num);
    // 输出结果 a: 111

  return 0;
}
  • 使用引用传递返回额外信息

一个函数只能返回一个值,然而有时函数需要同时返回多个值,引用形参为我们一次返回多个结果提供了有效的途径

举个例子, 在刚刚的swap函数增加返回最小值与最大值

void SwapQuote(int &a, int &b, int &mix, int &max)
{
  int tmp = a;
  a = b;
  b = tmp;
  a < b ? mix = a, max = b : max = a, mix = b;
}

这样我们只需要调用的时候传入实参,即可修改实参的值


今天是1024程序员的节日,enjoy it ~

点赞
收藏
评论区
推荐文章
Wesley13 Wesley13
3年前
Java对象的浅拷贝和深拷贝&&String类型的赋值
Java中的数据类型分为基本数据类型和引用数据类型。对于这两种数据类型,在进行赋值操作、方法传参或返回值时,会有值传递和引用(地址)传递的差别。浅拷贝(ShallowCopy):①对于数据类型是基本数据类型的成员变量,浅拷贝会直接进行值传递,也就是将该属性值复制一份给新的对象。因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,
Wesley13 Wesley13
3年前
Java里的按值传递与引用传递
按值传递还是按引用传递这个在Java里面是经常被提起的问题,也有一些争论,似乎最后还有一个所谓的结论:“在Java里面参数传递都是按值传递”。事实上,这很容易让人迷惑,下面先分别看看什么是按值传递,什么是按引用传递,只要能正确理解,至于称作按什么传递就不是个大问题了。1:按值传递是什么指的是在方法调用时,传递的参
Wesley13 Wesley13
3年前
Java到底是引用传递还是值传递
前言前段时间在群里看到类似这样一个问题,下面的代码会输出什么呢?public void test(){   String str  "hello";   change(str);   System.out.println(str);}private void change(String str){  
Stella981 Stella981
3年前
ShellScript值传递参数
Shell传递参数摘自菜鸟教程:http://www.runoob.com/linux/linuxshellpassingarguments.html(https://www.oschina.net/action/GoToLink?urlhttp%
Wesley13 Wesley13
3年前
12、ES6形参默认值
当定义函数的时候,可以给参数设置默认值。调用的时候不传递参数值,就使用默认值。例子1:普通函数,不传递参数值。默认全是undefined。functionadd(a,b,c){console.log(a,b,c);}add();//不传递参数是,默认参数值全是undef
Stella981 Stella981
3年前
26 函数形参值回传问题——C++解决多个return的一般方法
0引言在使用数组和vector作为函数的参数进行参数传递并希望得到值的回传时,由于不知道怎么写数组函数形参的引用形式,一直采用vector的引用形式。但是,刚刚测试了一下,发现数组作为参数本身就是指针,根本不需要采用引用形式把值回传啊,把测试结果写下来。1 关于数组作为函数参数的值传递问题——数组和容器的对比  数组直接作为
Wesley13 Wesley13
3年前
Java只有值传递(Java值传递还是引用传递?)
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/10830521.html(https://www.oschina.net/action/GoToLink?urlhttps%3A%2F%2Fwww.cnblogs.com%2Fygj0930%2Fp%2F10830521.html)一:区分Java数据类型、变
Wesley13 Wesley13
3年前
Java面试中的值传递与引用传递
一、前言Java是值传递的,对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。对于对象型变量而言的,传递的是该对象地址的一个副本,,并不是原对象本身,这里也有人说是引用传递。由于副本的地址和原对象地址一致,因此对副本的值进行操作时,会同步改变原对象值。_但是一旦副本的地址被改变,副本的值的操作则不会影响原对象地址。(
Easter79 Easter79
3年前
Swift3.0 类和结构体的选择
结构体实例总是通过值传递,类实例总是通过引用传递先说说值类型和引用类型的区别值类型被赋予给一个变量、常量或者被传递给一个函数的时候,其值会被拷贝在Swift中,所有的结构体和枚举类型都是值类型。这意味着它们的实例,以及实例中所包含的任何值类型属性,在代码中传递的时候都会被复制。引用类型在被赋予到一个变量、常
Stella981 Stella981
3年前
JavaScript深入之参数按值传递
定义在《JavaScript高级程序设计》第三版4.1.3,讲到传递参数:ECMAScript中所有函数的参数都是按值传递的。什么是按值传递呢?也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。按值传递举个简单的例子:varvalue1;fun