[C++潜心修炼] 小试牛刀

       打怪打怪打怪……………………




缺省参数


       你是否有这样的烦恼,传参的时候少传参数甚至没传参数这种粗心问题烦恼,没事让函数缺省参数拯救你,只要不忘记写缺省参数

       缺省参数:你可以在声明函数的时候给形参定义,你没有有传参的时候会自动补上

代码:

int add(int x=1,int y =2)
{
    
    
 return x+y;
}
int main ()
{
    
    
  cout<<add();//不传参数就为3
}

       但是有时候记性可能稍微好点,传了几个,或者全部都传了

代码:

int add(int x=1,int y =2int z=20)
{
    
    
 return x+y;
}
int main ()
{
    
    
  cout<<add(4,5,6);//这样传可以
  cout<<add(4);//这样也可以
 
}

       总有人会想玩点高操作,你看我我就想给 x ,z 传值怎么说

代码:

int add(int x=1,int y =2int z=20)
{
    
    
 return x+y;
}
int main ()
{
    
    
  cout<<add(4, ,6);
 
}

       显然是不行,因为这涉及一个逻辑问题,你看编译去觉得是传了空呢?还是没有传呢?这个空的话这个6是给 y 还是z
在这里插入图片描述


正确与错误的示范

       总之缺省参数,就是你最后的一层保障就如家一样,给你十足的安全感,传参要依次给,函数定义缺省参数一定要给全



指针空值nullptr

       NULL我的那么完美又那么老实你为啥要找人换我,我要做生产线上的螺丝钉

在这里插入图片描述


       真的吗,NULL在定义的时候为有俩种情况,为0或者无类型指针(void*)的0

宏定义:

#ifndef NULL
 #ifdef __cplusplus 
 #define NULL 0 
 #else 
 #define NULL ((void *)0)//把0强制类型转换为void*,
 #endif #endif

       NULL可能是一个没有引爆器的核弹,一般情况下没事但是存在安全隐患整不定哪天就……

void f(int)
 {
    
     
     cout<<"f(int)"<<endl;
  }
  void f(int*) 
 {
    
    
    cout<<"f(int*)"<<endl; 
 } 
 int main()
  {
    
     
      f(0);//"f(int)"
      f(NULL); //"f(int)"
      f((int*)NULL);//"f(int*)"
      return 0; 
   }

       你看这不就炸了吗,虽然有点挑刺,但是被发现了就是问题,我本来传NULL给我的结果是区调用 void f(int*)
(函数重载,简单来说他同名的函数会根据参数调用相对应的函数接口)



       为了严谨C++就推出了nullptr,他就代表是空指针常量(nullptr==(void *)0) ,给你放心的保障。



引用

       不知道大家有没有看过火影忍者,里面主角鸣人,他的招牌忍术叫多重影分身之术

在这里插入图片描述

       其中一幕让我印象深刻,他没有朋友,所以用忍术搞了三个分身并给他取了名字…………



       不追忆了,进入正题,引用就是给变量取别名,他和变量共用一块空间的,这个就和联合体很像。他是是C++中指针的进阶版


用法

类型 +&+变量名+实体

代码:

int a =10;
int    &    a2   =  a;//a2是a的别名
类型 + & + 变量名 = 实体

       这里要注意了,&在类型后面代表引用,在变量前则取地址



引用的一些性质:
  • 你可以给一个变量无限次的取别名,只要你不累就和鸣人一样 (查吨拉)

在这里插入图片描述

代码

int a=10;
int &a1=a;
int &a2=a;
int &a3=a;
…………………………

运行结果:
在这里插入图片描述

  • 一旦你已经是变量的别名,你就不能成为别人的别名

不知道大家有没有去超市买过哪种促销的酸奶,因为快要过期了所以他们为了处理掉会俩三个捆扎在一起销售,看了看自己的一块腹肌哎,这里一旦是别人的别名你就会永久和和他捆绑在一起

int a=10;
int b=20;
int &a1=a;
a1=b;
aout<<a;//输出是啥?

       这儿其实是赋值了,引用的概念是共用一块空间的哟,那么改变a1那a也被改了

在这里插入图片描述

上面除了不开空间以外指针似乎也可以完成,那么他真正用处是啥?



真正的用处

  • 做参数

        很多书上都是怎么说的,函数传参的时候建议传值,为什么呢??? 因为行参是实参的一份临时拷贝 (就是你原来数据是多大他会开一块一样大的空间存储数据),为了节省空间提高运行效率建议传指

代码:

int Swap(int a[],int b[],int n)//传值
{
    
    
    for(int i=0;i<n;i++)
    {
    
    
        a[i]=b[n];
    }
}

int Swap(int *a,int *b,int n)//传指
{
    
    
    for(int i=0;i<n;i++)
    {
    
    
        *(a+i)=*(b+i);
    }
}

int Swap(int &a,int &b,int n)//传指
{
    
    
    for(int i=0;i<n;i++)
    {
    
    
        a[i]=b[n];
    }
}

//交换10w的数
int main()
{
    
    
   int a[100000]={
    
    1…………100000}int b [100000]={
    
    -1…………0};
}

        1. 空间复杂度看,第一个 O(N) ,第二个 O (1) ,第三 没有开辟空间

       2. 引用代码理解性来说更好理解,更安全,妈妈再也不用担心我会忘记解引用了



  • 作返回值

       引用也可以做返回值,但是他有一个限制,就是返回参数必须是出了你所调用的函数的作用域还没有销毁,换种说法就是你所返回的变量是不存在栈上的

在这里插入图片描述

俩份差不多一样的代码但是多一段 printf("/"); 为啥就变成随机值了呢?

先看看编译器是如何处理的

  1. 1.如何变量带回到主函数的呢?一般情况下入变量比较小就放在寄存器(复制一份返回变量,具有常性),比较大就会在main函数中临时开一块空间

  2. 2 . 且一个变量在函数中创建(没static修饰),那么他的函数结束他的生命周期也结束(就是销毁)

       简单来说就是A 是Z的引用,Z被销毁了,编译器没有初始化这块空间,那么返回就打印则不会有问题,在这期间做一些事情,这块区域重新使用那打印就是有问题的


了解了上面的性质那那么就好理解了

       上面说过小数据是通过寄存器回带的,上面知道数据出了作用域就会销毁,那么如果是你会怎么办,要是我就考一份,或者malloc,new一个,编译器采用的是第一种

如图:
在这里插入图片描述

       但是有一个性质就是具有常性的,你想他不会修改那么给他搞成常量不过分吧


常引用

       其实常量也是有引用的但是没啥用,应为常量是不可用改变的。那他的别名也是。因为引用是给他取别名,公用一块空间,从适配角度来说你要加一个&前加个const

int const  &a=10;

那么返回值是具有常性的,那么你接收的时候也要是常引用

在这里插入图片描述


总结

  • 缺省参数就是一层防护,你没穿参数会自动调用
  • nullptr 代替NULL,他只表示为空指针(void*)0
  • 引用是指针的plus版本
    1. 他和原数据公用一块空间
    2. 他必须初始化
    3. 且她不能像指针一样改变指向位置
    4. 且各便捷,可读性更高
    5. 做返回值的时候一定要确保这个数据出了当前函数作用域不销毁
    6. 这个在后面的类中会特别体现出来

おすすめ

転載: blog.csdn.net/Legwhite/article/details/120565384