学习笔记:C++ 引用 以及与指针的区别

C++中的引用

当变量声明为引用时,它将成为现有变量的替代名称。通过在声明中添加“&”,可以将变量声明为引用


#include<iostream> 
using namespace std; 
  
int main() 
{ 
  int x = 10; 
  
  // ref is a reference to x. 
  int& ref = x; 
  
  // Value of x is now changed to 20 
  ref = 20; 
  cout << "x = " << x << endl ; 
  
  // Value of x is now changed to 30 
  x = 30; 
  cout << "ref = " << ref << endl ; 
  
  return 0; 
}

 

修改函数中传递的参数

如果函数收到对变量的引用,则可以修改变量的值。例如,在以下程序变量中使用引用进行交换。


#include<iostream> 
using namespace std; 
  
void swap (int& first, int& second) 
{ 
    int temp = first; 
    first = second; 
    second = temp; 
} 
  
int main() 
{ 
    int a = 2, b = 3; 
    swap( a, b ); 
    cout << a << " " << b; 
    return 0; 
} 

 

避免复制大型结构

想象一个必须接收大型对象的函数。如果我们通过它而没有引用,则会创建它的新副本,这会浪费CPU时间和内存。我们可以使用引用来避免这种情况。


struct Student { 
   string name; 
   string address; 
   int rollNo; 
} 
  
// If we remove & in below function, a new 
// copy of the student object is created.  
// We use const to avoid accidental updates 
// in the function as the purpose of the function 
// is to print s only. 
void print(const Student &s) 
{ 
    cout << s.name << "  " << s.address << "  " << s.rollNo; 
} 

 

 

在“每个循环”中,修改所有对象

我们可以在每个循环中使用“引用”来修改所有元素。

 

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> vect{ 10, 20, 30, 40 };

    // We can modify elements if we  
    // use reference 
    for (int &x : vect)
        x = x + 5;

    // Printing elements 
    for (int x : vect)
        cout << x << " ";

    return 0;
}  

 

 

在For Each循环中,避免对象的复制

当对象很大时,我们可以在每个循环中使用以避免复制单个对象。


#include <bits/stdc++.h>  
using namespace std;  
  
int main()  
{  
    vector<string> vect{"geeksforgeeks practice",  
                     "geeksforgeeks write", 
                     "geeksforgeeks ide"};  
  
    // We avoid copy of the whole string 
    // object by using reference. 
    for (const auto &x : vect)  
       cout << x << endl;  
  
    return 0;  
} 

 

引用与指针

引用和指针都可用于更改另一个函数内部一个函数的局部变量。当作为参数传递给函数或从函数返回时,它们都还可以用于保存大对象的副本,以提高效率。
尽管有上述相似之处,但引用和指针之间仍存在以下差异。

可以将指针声明为void,但引用永远不能为void

 

 

引用没有指针强大

1. 创建引用后,以后就不能再引用另一个对象了;它无法重新放置。这通常是通过指针完成的。

2. 引用不能为NULL。指针通常被设置为NULL,以指示它们没有指向任何有效的对象。

3. 引用必须在声明时进行初始化。指针没有这种限制

由于上述限制,C ++中的引用不能用于实现链接列表,树等数据结构。在Java中,引用没有上述限制,并且可以用于实现所有数据结构。引用在Java中更强大,这是Java不需要指针的主要原因。

引用更安全且更易于使用:
1. 更安全:由于必须初始化引用,因此不太可能存在诸如野生指针之类的野生引用。仍然有引用可能不指向有效位置(请参阅下面的练习中的问题5和6)

2. 易于使用:引用不需要解引用运算符即可访问该值。它们可以像普通变量一样使用。仅在声明时才需要“&”运算符。另外,可以使用点运算符('。')访问对象引用的成员,这与需要箭头运算符(->)访问成员的指针不同。

结合上述原因,在像复制构造函数参数这样的地方很少有不能使用指针的地方。必须使用引用传递副本构造函数中的参数。类似地,必须使用引用来重载某些运算符,例如++。

 

举个练习例子

 

例一


#include<iostream> 
using namespace std; 
  
int &fun() 
{ 
    static int x = 10; 
    return x; 
} 
int main() 
{ 
    fun() = 30; 
    cout << fun(); 
    return 0; 
} 

 

 

例二

#include<iostream>
using namespace std;

int fun( int &x)
{
    return x;
}
int main()
{
    int a = 10;
    cout << fun(a);
    return 0;
}

 

例三


#include<iostream> 
using namespace std; 
  
void swap(char * &str1, char * &str2) 
{ 
  char *temp = str1; 
  str1 = str2; 
  str2 = temp; 
} 
  
int main() 
{ 
  char *str1 = "GEEKS"; 
  char *str2 = "FOR GEEKS"; 
  swap(str1, str2); 
  cout<<"str1 is "<<str1<<endl; 
  cout<<"str2 is "<<str2<<endl; 
  return 0; 
} 

 

 

例四

#include<iostream> 
using namespace std; 
  
int main() 
{ 
   int x = 10; 
   int *ptr = &x; 
   int* &ptr1 = ptr; 
} 

 

 


#include<iostream> 
using namespace std; 
  
int main() 
{ 
   int *ptr = NULL; //    error 
   int *ptr = &p;
   int &ref = *ptr; 
   cout << ref; 
} 

 

 


例五


#include<iostream> 
using namespace std; 
  
int &fun() 
{ 
    int x = 10; 
    return x; 
} 
int main() 
{ 
    fun() = 30; 
    cout << fun(); 
    return 0; 
} 

 

 

 

2020/02/20补充

 

      引用:从宏观上可以理解为扩展了变量的作用域,传参后,就像是在本地解决问题一样避免了传n级指针,解决了n-1级的问题,即平级内解决问题。

提高

引用的本质是指针,也就是说C++对裸露的内存地址(指针)做一次包装

1. 指针的引用有,引用的指针无

int *& t1;    //ok

int &* t2;    //error

2. 指针的指针有, 引用的引用无

        指针的指针,即是二级指针,C++为了避免C语言设计指针的“失误”, 避免了引用的引用这种情况。有次也避免了引用的引用的。。。。。。

3. 指针的数组有, 引用的数组无

int* arr[] = {&a, &b, &c};    //ok

int& arr[] = {a,b,c};    //error

 

常引用

C++中 const 定义的变量称为常变量。变量的形式,常量的作用,用作常量,常量取代#define宏定义。

注意:#define 是预处理的时候替换。。。const是在汇编的时候替换。

 

常引用的特性

      const 的本意,即是不可修改。所以const对象,只能声明为const引用,使其语义保持一致性。non-const对象,既可以声明为const引用,也可以声明为no-const引用。声明const引用,则不可以通过const引用修改数据



int main(int argc, char** argv){

    const int t1 = 10;    /* 1 */
    
    const int& t2 = t1;


    
    int b1 = 100;    /* 2 */

    int &b2 = b1;

    const int &b3 = b1; 



    const int d1  = 100;    /* 3 */
    
    d1 = 100;    //error
    

}

 

 

临时对象的常引用

         临时对象通常指不可以取地址的对象(如:常量),即CPU中计算产生的中间变量能常称为右值。常见临时值有常量,表达式(如:a+b),函数返回值等。

1. 常量

const int& q = 10;

2. 表达式

int a = 3, b = 5;

const int &ret = a+b;

 

3. 函数返回值

int foo(){
    int a = 100;
    return a;
}


int main(int argc, char **argv){

    int &ra = foo();    //直接赋值给引用是有问题的
    const int &ra = foo(); 
    
}

 

4. 类型不同的变量

double d = 3.14;
//产生中间变量
const int& t = d;
//这里哪怕再次修改d的值但是t也不会变,因为const

 

 

引用的本质

 

例子如下:

#include <time.h>
#include <iostream>

using namespace std;

struct typeA{
    char a;
};

struct typeB{
    char* b;
};

struct typeC{
    char& c;
};


int main(){

    cout <<sizeof(typeA) << " " <<sizeof(typeB) << " "<<sizeof(typeC) << " "<<endl;

}


/**
    结果是:
            1 4 4
*/

字节大小跟指针都是一样是4个字节,而且引用必须要初始化,说明什么?

这说明引用的本质可能是指针,必须初始化,可能是常指针。引用可以改变吗?引用一经声明不可改变。

 

 

在这里就不得不说说const int *,const int * const和int const *之间的区别了

 

const int * 等同于 int const *:是指向常量整型的指针。

这就说明我们声明的变量是指向常量整数的指针。实际上,这就意味着指针指向了一个不应修改的值。在这种情况下,const限定符不会影响指针,因此允许该指针指向其他地址。

第一个const关键字可以位于数据类型的任何一侧,因此int const *等同于const int *。

例子下:


#include <iostream>

int main(){
    const int q = 5;
    int const* p = &q;

    //Compilation error 
    *p = 7;

    const int q2 = 7;

    //Valid 
    p = &q2;

    return 0;
} 

 

int * const 是指向整型的常量指针。实际上,这意味着指针不应指向其他地址。在这种情况下,常量限定符不会影响整数的值,因此允许更改存储在地址中的值。


例子下:

nclude <stdio.h> 
  
int main(){ 
    const int q = 5; 
    //Compilation error 
    int *const p = &q; 
  
    //Valid 
    *p = 7;  
  
    const int q2 = 7; 
  
    //Compilation error 
    p = &q2;  
  
    return 0; 
} 

 

 

const int* const:指向常量整数的常量指针

这意味着声明的变量是指向常量整数的常量指针。有效地,这意味着常数指针指向常数值。因此,指针既不应指向新地址,也不应更改所指向的值。

第一个const关键字可以位于数据类型的任何一侧,因此const int * const等效于int const * const


#include <stdio.h> 
  
int main(){ 
    const int q = 5; 
  
    //Valid 
    const int* const p = &q; 
  
    //Compilation error 
    *p = 7; 
      
    const int q2 = 7; 
  
    //Compilation error 
    p = &q2; 
      
    return 0; 
} 

 

 

本博文部分是根据优快云学院,王桂林老师的课程内容。主要是自己为了学习而记下来的笔记,如有不妥联删

部分参考:https://www.geeksforgeeks.org/difference-between-const-int-const-int-const-and-int-const

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值