【C++】初级语法阶段

1、初始化列表方案

        1.1、整型变量初始化可以直接用 { } 赋值

        

        1.2、数组、指针同样可以使用初始化列表方案

        

        1.3、注意:一般不用 int a( ) 来定义、初始化a变量,因为在这里会和定义函数int a( ) 形参冲突;而int b{ } 是可以使用的,会自动初始化b为0

———————————————————————————————————————————

2、C++的输入输出

        2.1、使用cin.gee(str,20)可以给字符串中直接输入空格,换行符“ 回车键 ”作为结束标记                

        2.2、使用” # “作为结束标记

        

———————————————————————————————————————————

3、const和指针(重点)

        3.1、const在C和C++中的区别

        const在c中以变量性为主;在c++中以常量性为主

        在.c文件中,[ ]中的数值必须是常量、或者是宏替换的常量、或者是枚举常量

        

        C++中const修饰的这个n要保持常性

        在内存中,*p变成了100,n变成了100;但是编译的时候n不复存在,遇到n就给替换成了字面常量5,然后再赋值给b

        

        3.2、const 放在 * 号前,修饰的是指向性,也就是修饰*P,不能解引用,但是P自身保存的地址可以改变

        比如:

        int a = 10 ,b = 20;

        const int* P  =  &a;

        这里我们可以让P = &b,但是不能通过*P = 100 来改变a的

        

        

        3.3、const放在* 号后,修饰的是变量名(变量自身具有了常性),那P的指向就可以改变,可以使用解引用,但是P保存的地址是不能改变的

       const放在* 号后,不能更改地址

       

       const放在* 号后,可以通过*p修改a变量的值

        

        3.4、* 号的前后都有const,那P、*P都不能被改变

        3.5、安全性

        

        

         

        3.6、指针之间的相互赋值        

        

         

        

———————————————————————————————————————————

4、补充:

        1、c语言中,scanf()函数的安全性判断解决(scanf_s()):

        将目标的大小由程序员指定

        2、判断是编译器是C++还是C,通过编译器自带的宏 _cplusplus 来判断

        

———————————————————————————————————————————

5、引用

        引用就是“别名”的概念

5.1、特点:

        1、定义“引用”,必须要进行初始化

        2、没有空引用

        3、引用没有二级引用

5.2、引用作为形参代替指针

        在c语言中,一般情况下,我们要交换两个变量的值,需要借助交换函数swpe(),通过“传指针,解引用”达到交换的目的

        但是在c++里面,我们可以通过“引用”来实现交换,在swpe()函数这里,我们将函数的参数设为要交换的变量的别名。例如要交换变量int a,int b的值,swpe()函数的参数,我们分别可以设为int & x,int & y,函数内部直接借助临时变量交换x、y的值即可

5.3、引用和const

        const 必须放在 & 的左边,表示常引用(放在&右边会修饰变量名,而被系统忽略,所以不会修饰&)

        由于是常引用,所以c只能读取a的值,不能修改a的值,但是可以通过改变b的值来修改a的值大小

        

        注意:

        对于下方常变量a,我们不能通过普通引用x去引用a,否则就是说明我们可以通过修改普通引用x来改变常变量a的值,所以要用常引用y去引用a

         

        形参的几种形式:

        

5.4、const引用是万能引用:

       const引用可以引用:变量、常变量、字面常量

        

        const引用在引用字面常量的时候实际上是:在底层定义了临时量tmp,接着让Z调用tmp,而不是直接引用字面常量10。引用字面常量10的时候,实际上引用的是tmp,10没有地址空间

5.5、右值引用概念

        左值:在C11标准的概念中,有取地址的能力,比如变量a可以取地址,和变量类型无关

        右值:不可以取地址,比如字面常量(int &  x  =  10,这个就是错误的,但是const  int &  x  =  10 么问题)

左值引用     

        

右值引用

        int && r = 10;这个是所谓的右值引用

        和常引用的相同点:都是在底层定义一个tmp变量保存右值10

        不同点:我们的常引用不能 +=10来改变字面常量10,但是右值引用可以让r+=10,是对临时量tmp += 10

        

5.6、其他引用形式        

        5.6.1、引用和数组

                1、别名影响数组元素的值

                2、引用整个数组。格式:int(&cr)[5] = ar;

        

        5.6.2、数组我们称为组合类型:由类型和大小组成

                int &ar [5]

                不能编译通过,数组元素给到下标,就得开辟空间,但是这里&取别名是不需要开辟空间的

                int (&br)[5]

                给整个数取别名,例如:int (&br)[5] = ar;这里br是数组ar的别名,这个数组是int类型,有5个元素

                int *P [5]

                指针数组:从右向左,有5个元素,p的每一个元素是整型类型的指针

                int (*s)[5]

                数组指针:指针s要指向元素个数为5的整型数组

        5.6.3、引用和指针

                我们可以对一个指针变量ip进行引用,即int *& s = ip;

                理解:对指针ip先取别名 &s,然后这个别名是int * 类型

                

        

        代码分析:

        1、s是对指针ip的引用,即别名。s = &b 改变s的指向,也就是改变ip的指向;

        2、const  int *& s1 = ip,是对指针ip进行取别名,并且s1设置为常性指针,那就是说不能通过 *s1 来改变a的地址,但是 *ip是可以的

        3、int*  const&  s2 = ip,是对指针ip取别名,const修饰变量名ip,可以解引用,不能修改地址

        

5.7指针和引用的区别:

       5.7.1、指针和引用的区别

         1-9从语法角度上看区别,10是汇编层面上的区别

        1、从语法规则上讲,指针变量存储某个实例(变量或对象)的地址,而引用是某个实例的别名。

        2、程序为指针变量分配内存区域(指针分配4字节);而不为引用分配内存区域(仅仅取外号)

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

        4***、指针变量的值(指针的指向)可以发生改变,存储不同实例(比如变量a、b)的地址;引用在定义时就被初始化(也就是它就指定是某个变量的外号,这个变量的地址是确定的),之后无法改变(不能是其他实例的引用)。

        5、指针变量的值可以为空(NULL,nullptr);但是没有空引用(引用前必须定义好某个变量)。

        6、指针变量作为形参时需要测试它的合法性(判空NULL);引用不需要判空;

        7、对指针变量使用“ sizeof ”得到的是指针变量的大小(4字节),对引用变量使用“ sizeo f”得到的是变量的大小(由变量类型决定)。

        8、理论上指针的级数没有限制;但引用只有一级。即不存在引用的引用,但可以有指针的指针(二级指针、三级指针)

        9、++引用(直接反应到实体) 和 ++指针的效果不一样。对引用的操作直接反应到所引用的实体(变量或对象);

        

       知识引申: 数组中,(*p)++是:先取p对应的值,然后对p的值再加1;*p++是:先取i、p对应的值,然后p地址加1个单元格

        10、从汇编层次理解引用与指针变量的区别:(从汇编层面看,引用就是指针,是一个自身为常性的指针,不能指向其他实例,可以改变其值)

        

         

        从汇编代码上看一下引用和指针区别

        int* ip = &a;

        int& x = a;

        都是通过lea取a的地址,然后给到eax,然后通过eax给到对应的变量

        

        5.7.2、指针和引用的相同点:

        绝不可以对函数中的局部变量以引用或指针方式返回,因为函数调用(会先开辟空间)结束之后,栈帧回收,那局部变量就会失效,但是值还存在,有可能打印的时候,这个值是可以正常打印的,但是如果我们再次调用某个函数,对这个栈帧进行操作,那原先这个位置的值就会被清理掉

        

        要返回地址的时候,此标识符名字对应的实体生存期不受函数生存期影响,就可以返回地址。比如:定义的全局变量、或者static int a静态变量(在 .data区)、或者是由指针进入形参,指针返回、或者以引用进、以引用出的方

        

 5.8、如何使用引用

        对于自定义类型,传参数时候,优先使用传引用方式(分析结构体占用内存);

        对于内置类型,函数调用传参数的时候,优先使用传值型(从底层汇编代码分析)

———————————————————————————————————————————

6、inline函数

        6.1、小点注意:

        cin输入的时候,以' \n ' 结尾,但是不把' \n ' 保存到变量内部,如果这个cin是在循环里面的话,那就会循环输入,永远不会结束

        get.cin()这个代码以' \n ' 结尾,但是会最终会把最后面' \n ' 保存到变量内部,所以可以作为判断结束的条件

        

6.2、内联函数的理解:

        当程序执行函数调用时,系统要建立栈空间,保护现场,传递参数以及控制程序执行的转移等等,这些工作需要系统时间和空间的开销。

        inline是一种以空间换时间的做法,省去调用函数额开销。但当函数体的代码过长或者是递归函数即便加上inline关键字,也不会在调用点以内联展开该函数。简单来说就是函数代码长度小,就直接在主函数内展开,否则过大就调动函数

        内联函数的定义和声明一定要在同一文件中,不能将声明和定义分别写在两个文件里面

6.3、什么时候建议使用内联函数?

        如果函数的执行开销小于开栈清栈开销(函数体较小),使用inline处理效率高。

        如果函数的执行开销大于开栈清栈开销,使用普通函数方式处理。

6.4、内联函数与宏定义区别:

        (1)内联函数在编译时展开,带参的宏在预编译时展开。

        (2)内联函数直接嵌入到目标代码中,带参的宏是简单的做文本替换。 

        (3)内联函数有类型检测、语法判断等功能,宏只是替换。

———————————————————————————————————————————

7、缺省函数

        C++可以使用缺省函数,但是C语言不可以

        函数在定义的时候,可以指定形参的值为默认值;函数调用的时候,如果给到全部的参数,那就以给到的实参传递给形参,如果没有给实参,那形参就按照默认的值来进行操作

缺省函数特点:

        1、函数的缺省值有可能是常量值、int()、int{ }、也有可能是函数调用,还有可能是类型的调用

        

        

        2、函数缺省值在给定的时候,要从右向左去给到(但是给实参的时候要从左向右给到)

        3、在多文件情况下,一般我们都只给函数的声明中给到缺省参数的默认值就行,而不能在函数定义中给到(多文件:比如有 .h头文件、.cpp函数实现文件、main.cpp测试文件)

        4、缺省参数也可以使用指针形式,但是不能让形参作为另外一个形参的默认值        

        

        5、函数在声明的时候可以省略”形参名“        

        

———————————————————————————————————————————

8、函数重载

8.1、函数重载的概念

        在C++中可以为两个或两个以上的函数提供相同的函数名称,只要参数类型不同,或参数类型相同而参数的个数不同,称为函数重载

        在C语言中函数名称不能一样,如果一样会发生函数名的重定义

        在C++中识别函数,不仅通过函数名识别,还要通过参数表(参数类型,参数个数)进行识别,参数名称不作为识别依据,例如两个类似的函数在定义的时候,其中一个函数的参数有包含默认值,这个时候是不作为识别依据的。

        

8.2函数重载的各类变化

        8.2.1、返回值不能作为识别依据。

        两个参数名、参数相同,但是返回类型不同,会被标记为编译错误:函数的重复声明。

        8.2.2、参数名不能作为识别依据。

        参数表进行比较的时候,和参数名称无关

        8.2.3、如果在两个函数的参数表中,只有缺省实参不同,也不能作为函数重载的依据。

        也就是第二个声明被视为第一个的重复声明。
        

        8.2.4、typedef也不能作为函数重载的依据

        

        8.2.5、C++中const(常性)、volatile(易变关键字)

        当一个形参类型有const或volatile 修饰时,如果形参是按值传递方式定义,那么在识别函数声明是否相同时,并不考虑const和 volatile 修饰符,也就是说const或volatile在值传递的时候并不能作为函数重载的依据

        

        但是如果按照指针方式定义,或者按照引用方式定义的话,那么进行const、volatile参数传递的话是可以作为函数重载依据的

                

        

        8.2.6、函数调用的二义性

        第二个func()函数含有缺省参数,所以主函数中func(12)在调用的时候,上面两个函数都可以进行调用,所以就会产生二义性,所以重载函数的时候,不要轻易使用缺省值,以免函数调用产生二义性

        

        

         8.2.7const和引用&,在函数重载中的匹配规则:

        普通变量会优先调用形参是普通指针的函数,如果没有普通指针(int* p)的函数,那就退而求其次找到形参为常性指针(const int* p)的函数;而常变量只能找形参为常性指针的函数

        普通变量会优先调用形参是普通引用的函数,如果没有普通引用(int& p)的函数,那就退而求其次找到形参为常引用(const int& p)的函数;而常变量只能找形参为常引用的函数 

        还有要注意以下这种方式1、3也是不能函数重载的:        

        

8.3、c语言为什么不能进行函数重载,而C++可以进行函数重载?(待整理)

        答案:关于名字粉碎技术,在编译中会对函数名进行另外的修饰

        名字粉碎(名字修饰)——“C” 或者 “C++” 函数在内部(编译和链接)通过修饰名识别。修饰名是编译器在编译函数定义或者原型时生成的字符串。

        C++在做名字修饰的时候,会把参数作为函数名的一部分。c只是单纯的依据函数名

        C语言的名字修饰规则非常简单,_cdecl是C/C++的缺省调用方式,调用约定函数名字前面添加了下划线前缀。

        

        C++的名字修饰足够复杂

        

        auto的原理就是根据后面的值,来自己推测前面的类型是什么。

        auto的作用就是为了简化变量初始化,如果这个变量有一个很长很长的初始化类型,就可以用auto代替。

如何判断编译器是C还是C++?

        在编译器下有个宏:_cplusplus,检测这个宏存在与否

        

——————————————————————————————————————————————————————————————————————————————————————

9、函数模板

模板类型推演:

        是对类型重命名的规则,不是简单的替换;

        特别是当T表示指针类型,例如 int* ,的时候,T x,y;是正确的;如果是替换的话就是 int* x,y;此时x是指针类型,y是整型,所以此处并非是替换,而是类型重命名 

         

编译时:模板函数是产生代码的代码

         

 



10、名字空间域:namespace

 



11、new / delete

 

 

 

 



12、C11部分特性

12.1、类型推导

1、auto关键字

        C++11引入了auto和decltype关键字实现类型推导,通过这两个关键字不仅能方便地获取复杂的类型,而且还能简化书写,提高编码效率。

        c11中auto称为类型指示符(type-specifier)。

        在c语言中auto是存储类型指示符。

        auto类型推导:auto定义的变量,可以根据初始化的值,在编译时推导出变量名的类型。

        

         

         

         

 

可当作函数模板去使用:

        

 

 

2、decltype关键字

        上一节所讲的auto,用于通过一个表达式在编译时确定待定义的变量类型,auto所修饰的变量必须被初始化,编译器需要通过初始化来确定 auto 所代表的类型,即必须要定义变量。若仅希望得到类型,而不需要(或不能)定义变量的时候应该怎么办呢?

        C++11新增了decltype关键字,用来在编译时推导出一个表达或的类型。

        它的语法格式如下∶

        decltype (exp)

        其中,exp表示一个表达式(expression) 。

        从格式上来看,decltype很像sizeof-—用来推导表达式类型大小的操作符。类似于sizeof,

不计算值,只取类型;函数也是,只取返回值类型,不调动函数

        

         

         

        

 

 12.2、基于范围的for循环

        

 

根据auto,自动推导容器中的元素类型:

        

         

 

12.3、nullptr

        

12.4、using和_tepydef

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值