C++引用(&)和指针的用法

目录

//引用调用(实现两个变量的交换)

拓:引用(&)变量

函数返回两个及以上的值(通过引用 / 指针 / 全局变量实现)

独立(常)引用 

//返回引用 

不要返回局部变量引用!!!(虽然编译可以通过) 

引用变量概念

拓:实参和形参 


//引用调用(实现两个变量的交换)

1.用值调用的方式(无法实现,函数无法更改a,b所在地址的值)

#include<iostream>
using namespace std;
void swap(int a,int b);
int main(){
    int a=1,b=2;
    cout<<"a:"<<a<<" b:"<<b<<endl;
    swap(a,b);
    cout<<"a:"<<a<<" b:"<<b<<endl;
    return 0;
}
void swap(int a,int b){
    int temp;
    temp=a;
    a=b;
    b=temp;
}


2.用指针方式

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

3.用引用调用方式实现

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

拓:引用(&)变量

//引用(&)变量 
#include<iostream>
using namespace std;
int main(){
	int j=0,k=10;
	int &i=j; //变量i成为变量j的别名
	cout<<"i:"<<i<<" j:"<<j<<endl;
	cout<<&i<<" "<<&j<<endl; 
	i=k;  //变量i获得变量k的值 
	k=12;
	cout<<"i:"<<i<<" j:"<<j<<" k:"<<k<<endl;
	cout<<&i<<" "<<&k<<endl;  //证明 i=k 没有让变量i成为变量k的别名 
	return 0;
}

函数返回两个及以上的值(通过引用 / 指针 / 全局变量实现)

 引用 调用

#include<iostream>
using namespace std;
void extremum(const int a[],int n,int &max,int &min);
int main(){
    int max,min;
    int a[]={12,34,56,7,3,99,67,45,3,80};
    extremum(a,sizeof(a)/sizeof(a[0]),max,min);
    cout<<"max="<<max<<" min="<<min<<endl;
    return 0;
}
void extremum(const int a[],int n,int &max,int &min){
    max=min=a[0];
    for(int i=0;i<n;i++){
        if(max<a[i]) max=a[i];
        if(min>a[i]) min=a[i];
    }
}


指针-法一

#include<iostream>
using namespace std;
int main(){
    int *max,*min;  //这个方法不能用函数(反正我不会),(具体原因分析在下面)
                    //麻烦且没必要
    int a[]={12,34,56,7,3,99,67,45,3,80};
    max=&a[0];
    min=&a[0];
    for(int i=0;i<sizeof(a)/sizeof(a[0]);i++){
        if(*max<a[i]) max=&a[i];  //将max变为a[i]的别名
        if(*min>a[i]) min=&a[i];
    }
    cout<<"max="<<*max<<" min="<<*min<<endl;
    return 0;
}


/*****引用函数造成错误(无法输出)*****
#include<iostream>
void extremum(int a[],int n,int *max,int *min);
using namespace std;
int main(){
    int *max,*min;  
    int a[]={12,34,56,7,3,99,67,45,3,80};
    extremum(a,sizeof(a)/sizeof(a[0]),max,min);
    cout<<"max="<<*max<<" min="<<*min<<endl;  //无法输出
    return 0;
}
void extremum(int a[],int n,int *max,int *min){
    max=&a[0];
    min=&a[0];
	for(int i=0;i<n;i++){
    if(*max<a[i]) max=&a[i];  //将max变为a[i]的别名
    if(*min>a[i]) min=&a[i];
    }
}
***************************************/


/*****原因分析*****/  
//在extremum函数中sizeof(a)=4,主函数中sizeof(a)=40,
//反正它应该是发生了啥不为我所知的变化就是不行
#include<iostream>
using namespace std;
int main(){
	int *a;
	*a=8;    //指针不能直接指向整数 
	cout<<*a<<endl;  //无法输出 
	return 0;
}

#include<iostream>
using namespace std;
int main(){
	int *a,i=8;
	*a=i;
	cout<<*a<<endl;  //输出8 
	return 0;
}


指针-法二

#include<iostream>
void extremum(int a[],int n,int *max,int *min);
using namespace std;
int main(){
    int a[]={12,34,56,7,3,99,67,45,3,80};
    int max,min;
    extremum(a,sizeof(a)/sizeof(a[0]),&max,&min);  //通过引用(&)将整型int变为指针带入到函数中
    cout<<"max="<<max<<" min="<<min<<endl;
    return 0;
} 
void extremum(int a[],int n,int *max,int *min){
    *max=*min=a[0];
    for(int i=0;i<n;i++){
        if(*max<a[i]) *max=a[i];
        if(*min>a[i]) *min=a[i];
    }
}

指针-法三

#include<iostream>
int max,min;
void extremum(int a[],int n);
int main(){
    int a[]={12,34,56,7,3,99,67,45,3,80};
    extremum(a,sizeof(a)/sizeof(a[0]));
    std::cout<<"max="<<max<<" min="<<min<<std::endl;
    return 0;
}
void extremum(int a[],int n){
    int *p;
    max=min=*a;  //对于数组a,*a的就是指向a数组中的第一个数 
    for(p=a+1;p<a+n;p++){  //p=a+n的意思是指针p指向数组a的最后一位的后一位 
                    //从a+1即a数组中第二个数开始,因为max和min的初始化值为a[0] 
        if(max<*p) max=*p;
        if(min>*p) min=*p;
    }
}

全局变量

#include<iostream>
int _max,_min;       //不能命名为 max(min) , max 和标准库的 std::max 同名了
void extremum(int a[],int n);
using namespace std;   //就是有这个的时候,全局变量定义中不能有max和min 
int main(){
    int a[]={12,34,56,7,3,99,67,45,3,80};
    extremum(a,sizeof(a)/sizeof(a[0]));
    cout<<"max="<<_max<<" min="<<_min<<endl;
    return 0;
} 
void extremum(int a[],int n){
    _max=_min=a[0];
    for(int i=0;i<n;i++){
        if(_max<a[i]) _max=a[i];
        if(_min>a[i]) _min=a[i];
    }
} 

独立(常)引用 

/*  非参数的独立引用很少使用,因为它们很容易混淆并会破坏程序的结构。
    常(独立)引用(const 类型 &引用名=变量名;)  */

#include <iostream> 
using namespace std; 
int main() 
{ 
    int j,k; 
    const int &i=j; //(独立)常引用,变量i成为变量j的一个别名
    j=10; 
    cout<<"j="<<j<<" i="<<i<<endl;  //输出 j=10 i=10 
    k=20; 
    //i=k;  //错误,不允许通过常引用修改变量的值! 
    j=k;    //通过j间接修改是可以的!
    cout<<"j="<<j<<" i="<<i<<endl;   //输出 j=20 i=20
}


//返回引用 

//实例:利用返回引用创建有界数组 

#include<iostream>
int &put(int i);  //将一个值放入数组中 
int get(int i);   //从数组中获得一个值 
int error=-1;  //不能使用const修饰符,因为它是返回引用的返回值(错误情况) 
const int MAX=10;  //定义最大数组长度(数组的最大下标为MAX-1) 
int a[MAX];
using namespace std;
int main(){
    put(0)=5;
    put(2)=20;
    put(9)=1314;
    cout<<a[0];
    cout<<a[2]<<endl; 
    cout<<a[9]<<endl;
    
    //下面有意产生错误
    put(MAX+2)=6;  //数组越界
    int i=get(MAX+2);  //数组越界
    return 0;
}
int &put(int i){
    if(i>=0&&i<MAX){
        return a[i];
    }
    else{
        cout<<"边界错误(put)"<<endl; 
        return error;
    }
}
int get(int i){
    if(i>=0&&i<MAX){
        return a[i];
    }
    else{
        cout<<"边界错误(get)"<<endl;
        return error;
    }
 
}

不要返回局部变量引用!!!(虽然编译可以通过) 

#include <iostream> 
int &func();
using namespace std;
int main() {
  cout<<(func()=5)<<func()<<endl;  //输出520
}
int &func() {
  int x=20;  //局部变量
  return x; //编译可以通过,但不能使用!!
  //warning C4172: returning address of local variable or temporary
}

引用变量概念

/*  
1.引用变量定义时必须进行初始化
在程序中对引用的存取都是对它所引用的变量的存取。也不能再指向别的变量!
2.引用与指针不同:
指针的内容或值是某一变量的内存单元地址,
而引用则与初始化它的变量具有相同的内存单元地址。 
3.返回引用必须保证返回的引用变量有合法的内存空间,并且不在函数的运行栈中
一般只能返回全局变量和静态变量
4.使用const常引用的目的就是提高性能(不需要制作数据的副本)。
使用引用参数而不加const就应该认为该参数将被修改!
5.当函数需要返回多于1个值,或希望修改实参的值时必须使用引用调用。 
6.如果条件允许,就应将引用形参声明为const形参
这样可以避免无意间修改数据而导致编程错误,
此外使用const形参使得函数能够接受const和非const实参,否则只能处理非const数据。
eg.

#include<iostream>
void func(const int &i);
using namespace std;
int main(){
    int a=1314;
    func(a);
    return 0;
}
void func(const int &i){
    cout<<i<<endl;
}


7.对比总结:
void func1(int n){
    //可以修改n,但值不会返回调用者
}   //可用值或变量调用
void func2(int &n){  
    //可以修改n,值会返回调用者
}   //只能用同类型的变量调用该函数
void func3(const int &n){ 
    //根本就不允许修改n
}   //可用值或变量调用

 //func1/2/3具体如下

#include<iostream>
int func1(int n);
using namespace std;
int main(){
    cout<<"4!="<<func1(4)<<endl;
    int n=5;
    cout<<"5!="<<func1(n)<<endl;
    return 0;
}
int func1(int n){   //可用值或变量n调用,2个n(形参和实参)的地址是不一样的!
    int fac;
    for(fac=1;n>0;n--){
        fac*=n;
    }
    return fac;
}  //可以修改n,但值不会返回调用者
#include<iostream>
int func2(int &n);
using namespace std;
int main(){
    //cout<<"4!="<<func2(4)<<endl;  错误,只能同类型调用
    int n=5,fac=func2(n);
    cout<<n<<"!="<<fac<<endl; //输出  0!=120
    cout<<&n<<endl;  
    return 0;
}
int func2(int &n){   //只能用同类型的变量调用该函数
    cout<<&n<<endl;  //func2的n和main的n的(实参地址传递给形参)地址一致!
    int fac;
    for(fac=1;n>0;n--){
        fac*=n;
    }

    return fac;
}   //可修改n,修改后的值会返回调用者
#include<iostream>
int func3(const int &n);
using namespace std;
int main(){
    cout<<"4!="<<func3(4)<<endl;
    int n=5,fac=func3(n);  
    cout<<n<<"!="<<fac<<endl;
    return 0;
}
int func3(const int &n){  //可用值或变量调用
    int fac=1;
    for(int i=n;i>0;i--){ //func2的n和main的n的(实参地址传递给形参)地址当然也一致!
        fac*=i;
    }
    return fac;
}  //根本就不允许修改n


拓:实参和形参 

/*

1、值传递
实参是变量,表达式等值。
    find(int x){}
    y= find(z);
上面的例子中,z是实参,x是形参。x变z不变。
在值传递过程中,实参和形参位于内存中两个不同地址中,
实参先自己复制一次拷贝,再把拷贝复制给形参。
所以,在值传递过程中,形参的变化不会对实参有任何的影响。
2、地址传递(也称引用传递)
实参是指针。
在函数调用的时候,实参传递给你的是指针地址,地址一样也就意味着实参和形参是一样的,
当你的形参发生改变时,实参也会发生改变。
    find(int  &x){}
    y= find(z);
上面的例子中,z是实参,x是形参。z随x而改变。
3、const引用传递
    find(const int  &x){}
    y= find(z);
上面的例子中,z是实参,x是形参。z不随x而改变。
(const引用和值传递不一样)在值传递中要进行两次拷贝,浪费内存资源是相当可耻的,
const的出现有效避免了这种情况的出现,只需拷贝一次就够了。 */ 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值