C++中的引用详解及引用与指针的区别

1.引用的定义

引用:给变量取一个别名,编译器不会为引用变量开辟内存空间,它与引用的变量共用同一块内存空间。

语法:

类型 & 引用变量名 = 引用实体

 注意:引用必须初始化

            引用一旦初始化 就不能再次修改别名

int num = 10;
int &a = num;    //num的别名为a

int data = 20;
a = data;    //不是data别名为a 而是将data值赋值a(num)

2.引用作用于普通变量

int num = 10;
int &a = num;//a就是num的别名 a==num

cout<<"num = "<<num<<endl;//10
//对a赋值 == 对num赋值
a=100;
cout<<"num = "<<num<<endl;//100

//a是num的别名 所以num和a具有相同的地址空间
cout<<"a 的地址:"<<&a<<endl;
cout<<"num 的地址:"<<&num<<endl;

 3.引用作用于数组

方式1:

void test02()
{
    int arr[5] = {10,20,30,40,50};
    //需求:给arr起个别名
    int (&my_arr)[5] = arr;//my_arr就是数组arr的别名

    int i=0;
    for(i=0;i<5;i++)
    {
        cout<<my_arr[i]<<" ";
    }
        cout<<endl;
}

方式2:配合typedef

 void test03()
{
    int arr[5] = {10,20,30,40,50};
    //1、用typedef 给数组类型 取个别名
    //TYPE_ARR就是一个数组类型(有5个元素 每个元素位int)
    typedef int TYPE_ARR[5];

    //myArr就是数组arr的别名
    TYPE_ARR &myArr=arr;

    int i=0;
    for(i=0;i<5;i++)
    {
        cout<<myArr[i]<<" ";
    }
        cout<<endl;
}

上面的TYPE_ARR就表示是一个有5个元素 每个元素为int型的 数组类型

TYPE_ARR &myArr=arr; 就表示给arr取了一个myArr的别名

 4.引用作用于函数的参数

void my_swap2(int *a, int *b)//a=&data1,b =data2;
{
    int tmp = *a;
    *a = *b;
    *b = tmp;
}
int main()
{
    int data1 = 10;
    int data2 = 20;
    my_swap2(&data1, &data2);
    cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl; //20 10
}

在C++中可以用以上这种指针的方式交换两个数的值。

void my_swap3(int &a, int &b)  //a=data1,b=data2
{
    int tmp = a;
    a = b;
    b= tmp;
}
int main()
{
    int data1 = 10;
    int data2 = 20;
    my_swap3(data1,data2);//交换成功(推荐)
    cout<<"data1 = "<<data1<<", data2 = "<<data2<<endl;
}

如上用引用的方式也能交换两个数,并且比用指针的方式更简单。

5.引用作用于函数的返回值

//引用作为函数的返回值类型

int& my_data(void)
{
    int data = 10;
    static int num = 200;
    return num;    //函数返回啥变量 引用就是该变量的别名
    //函数的返回值是引用时 不要返回局部变量
}
int main()
{
    //ret是别名 ret是num的别名

    int &ret = my_data();//ret1是num的别名
    cout<<"ret = "<<ret<<endl;
}

这里要注意的是,将引用作为函数的返回值时,函数返回的变量不能是一个局部变量。

例如在上面代码中return data;    这样就不行,因为局部变量在函数return后就被销毁了,系统为它所开辟的空间也没了,此时打印ret会造成非法访问内存。

6.指针的引用

void my_str1(char **p_str)//p_str = &str
{
    //*p_str == *&str == str
    *p_str = (char *)calloc(1,32);
    strcpy(*p_str, "hello world");

    return;
}

void my_str2(char* &my_str)//char* &my_str = str;my_str等价str
{
    my_str = (char *)calloc(1,32);
    strcpy(my_str, "hello world");
    return;
}
int main()
{
    char *str = NULL;
    //需求:封装一个函数 从堆区 给str申请一个空间 并赋值为"hello world"
    //my_str1(&str);
    my_str2(str);
    cout<<"str = "<<str<<endl;    
    free(str);
}

str2函数跟str1函数相比,语法更加清晰,函数参数变成指针的引用,用不着取地址。

7.常引用

既降低开销,又防止函数内部修改

typedef struct
{
    int num;
    char name[32];
}STU;
void myPrintSTU1(STU tmp)//普通结构体变量作为形参 开销太大
{
    cout<<sizeof(tmp)<<endl;
    cout<<"学号:"<<tmp.num<<", 姓名:"<<tmp.name<<endl;
}
void myPrintSTU2(const STU &tmp)//STU &tmp=lucy;tmp是lucy的别名 tmp没有开辟独立空间
{
    //tmp.num = 2000;//err 因为tmp为常引用
    cout<<"学号:"<<tmp.num<<", 姓名:"<<tmp.name<<endl;
}
int main()
{
    STU lucy = {100,"lucy"};

    //需求:定义一个函数 遍历lucy成员(读操作)
    myPrintSTU2(lucy)
    return 0;
}

以上代码中我们想遍历lucy成员,可以用myPrintSTU1的方式,但是开销太大,一个形参tmp就有36字节,于是我们可以用引用的方式来做形参(myPrintSTU2的方式),因为tmp没有开辟独立的空间,这样开销就会小很多。然而我们为了防止lucy里的数据被修改,就可以在引用前加一个const修饰,于是tmp.num的值就不能被修改,这就是常引用。

8.引用与指针的区别

相同点:

                都是地址的概念;

                指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。

不同点:

                程序为指针变量分配内存区域;而不为引用分配内存区域;

                指针解引用时要在前加“ * ”,引用可以直接使用;

                引用只能在定义时被初始化一次,之后不可变;指针可变;

                “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本 身的大小;

                不存在引用的引用,但可以有指针的指针;

                引用是类型安全的,而指针不是(引用比指针多了类型检查;

               

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值