【C++ 学习】C++ 传值 传指针 传引用

C++ 传值 传指针 传引用

C++ 函数传参主要是三种方法:传值、传指针、传引用。

说在前面:

  1. 传引用相对来说是简单一点的,也更加优雅。

明确几点:

  1. 指针也是一个变量,指针中存的值是一个地址,
  2. 非main函数的其他调用函数传递的形参只在其函数范围内起作用。即单纯的形式参数,只在其调用函数范围内其作用,
  3. 由于2的原因,当我们在调用函数中改变了某些数据,并且希望这种改动能够被携带出来。我们需要使用引用& 或 指针*。
  4. 使用传值的方法,当变量在调用函数中改变时,在返回的函数中是不会改变的。(原因在于,传值方法,调用函数生成了变量的副本,改变的是变量的副本)默认的参数传递语义是值传递(pass-by-value):函数接收其参数的副本。修改这些参数后,原始实参将保持不变。

请注意本文中的很多内容来自《C++20高级编程 第5版》,感谢本书的作者和翻译人员。

引用

C++中的引用(reference)是另一个变量的别名。对引用的所有修改都会更改其引用的变量的值。可以将引用视为隐式指针,它省去了获取变量地址和解引用指针的麻烦。

引用变量必须总是在创建时初始化。

具体来说,就是

int x = 3, y = 4;
int &xRef = x;		// 其中xRef是引用变量, 该语句不能写为int &xRef; xRef = x; 这是不合法的
xRef = y; 			// 此时,x 中的值被修改,此时x = 4;

xRef = 5;		   // 这是被允许的,这相当于将 x值改为5;

xRef = &y;			// 这是不合法的,编译器报错。

该程序也表明,引用与指针非常相似。

int main() {
    std::cout << "Hello, World!" << std::endl;
    int x = 5;
    int &xrf = x;
    std::cout << x << std::endl;
    std::cout << xrf << std::endl;
    xrf = 6;
    std::cout << x << std::endl;
    std::cout<< xrf << std::endl;

    std::cout << &xrf << std::endl;
    std::cout << &x << std::endl;
    return 0;
}

const 引用

  1. 引用默认是 const(因为我们不能改变引用的指向)。
  2. 无法创建引用的引用(即不能对别名本身在起一个别名, 引用必须针对一个实体)。
int main(){
        std::cout << "Hello, World!" << std::endl;
    int x = 5, y = 4;
    int &xrf = x;
   	xrf = &y;		// 针对1的解释,即不能改变引用的指向
    int &xxrf = xrf;		//针对2的解释,即不能创建引用的引用。
    return 0;
}

针对引用使用 const,其含义为:

int z;
const int& zRef {z};
zRef = 4;		// 编译器报错

对于引用使用const,使得我们无法通过该引用来改变变量的值。然而,我们可以使用变量自身进行值的更改。

指针的引用和引用的指针

// 指向int的指针的引用
int* intP{ nullptr };
int*& ptrRef {intP};
ptrRef = new int;
*ptrRef = 5;

ptrRef是对intP的引用,intP是对int的指针,修改ptrRef会更改intP。也就是说ptrRef是一个指针的引用。

int x = 3; // int x {3};
int& xRef {x};
int* xPtr {&xRef};
*xPtr = 100;

这是一个引用的指针。也就是说,该代码通过取x的引用的地址来将xPtr设置为指向x。将100赋值给*xPtr会将x的值更改为100。

xPtr是指针,xPtr存放的是一个地址,*对该地址中的内容进行访问。xPtr==&xRef,也就是xRef不是一个地址

引用作为函数参数

C++程序员通常不使用独立的引用变量或引用数据成员,引用的最常见用途是用于函数的参数。默认的参数传递语义是值传递(pass-by-value):函数接收其参数的副本。修改这些参数后,原始实参将保持不变。

传指针:栈中变量的指针经常在C语言中使用,以允许函数修改其他栈帧中的变量。通过对指针解引用,函数可以修改表示该变量的内存,即使该变量不在当前的栈帧中。然而,指针是比较麻烦的。

传引用:C++中提供了一种更好的机制,称为引用传递(pass-by-reference),参数是引用而不是指针。

从函数返回对象的推荐方法是通过值返回,而不是使用一个输出参数。

引用传递(pass-by-reference)的好处:

  1. 效率: 复制大型的对象可能花费很长时间,引用传递知识将该对象的一个引用传给函数。
  2. 支持:不是所有的类都允许值传递。

建议多使用:const &

例子

使用引用可以比使用指针干净得多。本书中使用了一个很好的例子,该例子中使用了标准库容器vector。

void seperateOddsAndEvens(const vector<int>& arr, vector<int>& odds, vector<int>& evens){
    for (int i : arr){
        if (i % 2 == 1){
            odds.push_back(i);
        }
        else{
            evens.push_back(i);
        }
    }
}

使用引用能够让代码非常简洁,而且效率也非常高,这是可以明确的。使用引用,可以把值传递出来。

vector<int> vecUnSplit {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
vector<int> odds, evens;
separateOddsAndEvens(vecUnSplit, odds, evens)

其对应的指针版本为:

void separateOddsAndEvens(const int arr[], size_t size, int** odds, size_t* numOdds, int** evens, size_t* numEvens){
    //count the number of odds and evens
    *numOdds = *numEvens = 0;
    for(size_t i = 0; i < size; ++i){
    	if (arr[i] % 2 == 1){
            ++(*numOdds);
        }else{
            ++(*numEvens);
        }
    }
    // 指针需要先统计一下
    // Allocate two new arrays of the approriate size
    *odds = new int [*numOdds];
    *evens = new int [*numEvens];
    
    // Copy the odds and evens to the new arrays
    size_t oddsPos = 0, evenPos = 0;
    for (size_t i = 0; i < size; ++i){
        if (arr[i] % 2 == 1){
            (*odds)[oddsPos++] = arr[i];
        }else{
            (*evens)[evensPos++] = arr[i];
        }
    }
}
  • 22
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SUNX-T

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值