指针和引用

本文深入讲解了C++中引用的概念及应用,包括引用的基本定义、特点、与指针的区别,以及如何利用引用提高程序效率。并通过实例展示了引用作为函数参数和返回值的应用场景。

首先我们来介绍一下什么是引用:
- 引用

引用不是定义一个新的变量,而是给一个已经定义的变量重新起一个别名。

定义的格式:
类型 &引用变量名 = 已定义过的变量名

void TestReferencl()
 {
    int a = 1;
    int b = a;

    cout<<"a:address->"<<&a<<endl;
    cout<<"v:address->"<<&b<<endl;

    a = 2;
    b = 3;
    int& c = b;
    c = 4;
}

引用的特点:
1. 一个变量可以取多个别名
2. 引用必须初始化
3. 引用只能在初始化的时候引用一次,不能再改变为引用其他的变量。

const引用
void reReferenc2()
{
    int a = 4;
    const int& b = a;
    cout<<"b="<<b<<endl;
    a = 5;
    cout<<"a="<<a<<endl<<"b="<<b<<endl;

    const int c = 4;
    const int& d = c;

    const int& e = 10;//常量具有常性,只有常引用可以引用常量
    cout<<"c="<<c<<endl<<"d="<<d<<endl<<"e="<<e<<endl;

    double f = 1.1;
    //int& g = f;
    //f是double类型,g是整形,f在赋值给g时要生成一个临时变量
    //这个临时变量具有常性
    //因此不能直接赋值
    const int& g = f;
    cout<<"f="<<f<<endl<<"g="<<g<<endl;
}

const引用要注意下面三点
1. 常量具有常性,只有常引用可以引用常量。
2. f是double类型,g是整形,f在赋值给g时要生成一个临时变量这个临时变量具有常性
因此不能直接赋值。
3. 引用只能使权限变小,不能使权限变大。

引用作为参数

首先我们来看下面的代码。

void Swap1(int left, int right){
    int temp = left;
    left = right;
    right = temp;
}

int main(){
    size_t a = 1;
    size_t b = 2;
    Swap1(a,b);
    cout<<"a="<<a<<endl<<"b="<<b<<endl;
    return 0;
}

那么问题来了,上面的代码可以完成a,b的交换吗?

显然不可以,形参作为非引用的方式传值,则生成临时变量接受实参的值,所以形参作为实参的拷贝是无法改变实参的内容的。

那么,下面这个代码可以吗?

void Swap2(int* pLeft, int* pRight){
    int temp = *pLeft;
    *pLeft = *pRight;
    *pRight = temp;
}

int main(){
    int a = 1;
    int b = 2;
    //Swap1(a,b);
    Swap2(&a, &b);
    cout<<"a="<<a<<endl<<"b="<<b<<endl;
    return 0;
}

嗯,不错,我们传指针就可以成功的交换两数的值。那么继续看下面的代码,思考可以吗?

void Swap3(int& left, int& right){
    int temp = left;
    left = right;
    right = temp;
}

int main(){
    int a = 1;
    int b = 2;
    //Swap1(a,b);
    //Swap2(&a, &b);
    Swap3(a, b);
    cout<<"a="<<a<<endl<<"b="<<b<<endl;
    return 0;
}

咦,等等,写到这里我们似乎可以发现一些规律。

无论引用还是指针,在函数交换的时候就是直接对实参进行操作,所以可以交换成功。而直接传参,形参是实参的拷贝,貌似是对实参进行操作,其实改变的只是拷贝的值,所以无法完成交换。

利用引用传参可以提高程序的效率。

另外,当不希望在函数内改变参数x的值时,尽量使用常引用传参。

void ReadBigData(const bigData& x){
    int a = x.array[100];
}
传值作为返回值&传引用作为返回值
int& Add(int d1, int d2){
//int Add(int d1, int d2){
    static int ret = d1 + d2;
    return ret;
}

int main(){
    int a = 5, b = 4;
    int c = Add(a, b);
    cout<<"c="<<c<<endl;
    return 0;
}

因为ret在Add的函数栈帧内临时存在,在函数调用结束之后就会销毁,所以返回这块内存的引用,可能有时候结果正确,但是会造成访问非法内存。

综上所述,我们可以得到下面的结论:
- 不要返回一个临时变量的引用。
- 如果返回对象出了当前函数的作用域仍然存在,则最好使用引用返回,因为这样更高效。

引用和指针的区别
  1. 引用只能在定义的时候初始化一次,之后不能改变其指向的的值(从一而终),指针变量的值可以改变。
  2. 引用必须指向有效的变量,指针可以为空。
  3. sizeof指针对象值得是对象地址的大小,sizeof引用指的是引用所指向的变量的大小。
  4. 指针和引用自增自间的意义不一样。
  5. 相对而言,指针比引用更安全。
指针引用在编程中都用于间接访问操作内存中的数据,但它们在定义、初始化、可变性以及使用场景等方面存在显著的区别。 指针是一种变量,其值为另一个变量的地址,即内存地址。指针可以在声明后初始化为空,并且可以重新赋值指向不同的变量。这意味着指针可以在程序执行期间改变其所指向的对象。此外,指针可以被设置为`NULL`,表示它不指向任何有效的对象。当使用指针时,需要通过解引用操作符`*`来访问指针所指向的值。指针还可以进行算术运算,例如自增操作,这使得指针非常适合用于遍历数组等数据结构的操作。指针的大小通常取决于系统的架构,而不是它所指向的数据类型[^4]。 相比之下,引用更像是一个变量的别名,它必须在声明时初始化,并且一旦初始化后不能改变。这意味着引用始终绑定到初始化时指定的对象上。引用不能为`NULL`,因此在使用引用时不需要担心空引用的问题。由于引用直接操作被引用的变量,所以不需要解引用操作符。引用的大小与被引用的变量相同,因为引用本质上是一个别名[^4]。 在C++中,相比于指针更推荐使用引用,特别是在函数参数传递返回值的情况下,因为引用提供了更清晰的语法并且避免了空指针的风险。然而,在需要动态内存分配或者处理数组时,通常会使用指针。另外,当需要返回函数内部局部变量的引用时应当特别小心,因为这会导致悬空引用的问题[^5]。 下面是一个简单的例子,展示了如何声明使用指针引用: ```cpp int main() { int value = 10; int* ptr = &value; // 指针指向value的地址 int& ref = value; // 引用ref绑定到value // 通过指针修改value的值 *ptr = 20; // 通过引用修改value的值 ref = 30; return 0; } ``` 在这个例子中,无论是通过指针还是引用,都可以成功地修改`value`的值。但是需要注意的是,如果尝试返回一个局部变量的引用,那么这个引用将在函数返回后变成无效,因为局部变量的生命期随着函数的结束而结束。 综上所述,选择使用指针还是引用取决于具体的应用场景。如果需要一个能够改变指向不同对象的机制,并且可能需要处理空指针的情况,则应使用指针。如果希望确保总是有一个有效的对象被引用,并且希望获得更加直观的语法,则应使用引用
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值