c 入门(二)
- 1.引用
-
- 1.1引用概念
- 1.2引用特性
- 1.3常应用
- 1.4使用场景
- 1.5传值、传引用效率比较
- 1.6引用和指针的区别
- 2.内联函数
-
- 2.1概念
- 2.2内联函数的特性
- 3.auto关键字(c 11)
-
- 3.1auto使用细则
- 4.基于范围的for循环(c 11)
- 5.指针空值nullptr(c 11)
1.1引用概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,它和它引用的变量共同用一块内存空间。
格式:类型& 引用变量名(对象名)=引用实体
1.2引用特性
1.引用类型必须和引用实体是同种类型的
2.引用在定义时必须初始化
3.一个变量可以有多个引用
4.引用一旦引用一个实体,再不能引用其他实体
1.3常应用
指针和引用,在赋值和初始化时,权限可以缩小,但是不能放大
1.4使用场景
①做参数
上图是以前我们如何交换两个值的
我们不用再像以前一样用指针,过于麻烦,用引用更加好理解,就是给x和y取了个别名而已
这样形参改变,影响实参,我们称之为输出型参数
②做返回值
在函数返回的时候,分为这个变量是否在出了函数作用域就销毁的情况。如果是一般的返回,就是传值返回,无论是否出作用域销毁,他都会创建一个常属性的临时变量,然后回到主函数,赋值给相应的变量。如果是局部变量,也就是出了作用域就销毁的变量,在返回的时候,只能依照上面的办法,因为局部变量在函数栈帧销毁时,也可能一并销毁变成了随机值。但如果是一个全局变量,则可以使用传引用返回,因为全局变量出了作用域不会销毁。
注意:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给操作系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
1.5传值、传引用效率比较
从上图中可以看出传值和传引用的效率相差还是很大的。
以值作为参数或者返回值类型,在传参和返回期间,函数不会直接传递实参或者将变量本身直接返回,而是传递实参或者返回变量的临时拷贝,因为用值作为参数或者返回值类型,效率是非常低下的,尤其是当参数或者返回值类型非常大时,效率就更低。
1.6引用和指针的区别
在汇编代码上可以看见引用和指针的操作是一样的,是不是非常震惊。其实本质上在底层实现上实际是有空间消耗的,因为引用是按照指针来实现的,在语法概念上引用就是一个别名,没有独立空间,和其引用实体共用同一块空间。
引用和指针的不同点:
①引用概念上定义一个变量的别名,指针存储一个变量的地址
②引用在定义时必须初始化,指针没有要求
③引用初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体
④没有null引用,但有null指针
⑤在sizeof中含义不同;引用结果为引用类型的大小,但指针始终是地址空间所占字节个数
⑥引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
⑦有多级指针,但没有多级引用
⑧访问实体方式不同,指针需要显式解引用,引用编译器自己处理
⑨引用比指针使用起来相对更安全
2.1概念
以inline修饰的函数叫做内联函数,编译时c 编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率。
查看方式:
1.在release模式下,查看编译器生成的汇编代码中是否存在call 函数名,但是由于系统会给大量优化,可能看不出,因此我们推荐下面一种方法
2.在debug模式下,需要对编译器进行设置,否则不会展开(因为debug模式下,编译器默认不会对代码进行优化,方便调试)
按照上面的方法调整一下项目的属性就可以查看内联函数的展开了
通过右边的汇编,可以看出,add函数直接在调用的地方展开了,并没有call add来调用函数的指令
2.2内联函数的特性
①inline是一种以空间换时间的做法,这里的空间指的是最后生成的exe文件,因为如果你调用这个函数的次数多了,那么函数每次都展开,他的代码量就上去了。如果编译器将函数当成内联函数处理,那么在编译阶段,会用函数体替换函数调用
②inline对于编译器而言只是一个建议,不同的编译器关于inline实现的及机制可能不同,一般建议将函数规模小、不是递归、且频繁调用的函数采用inline修饰,否则编译器将会忽略illine的特性
当我把代码写的稍微复杂并多一点的时候,编译器直接忽略了inline,并调用了add函数,从右侧的汇编中就能详细看出,编译器call add
③inline不建议声明和定义分离,分离会导致链接错误。因为inline被展开,就没有函数地址了,链接就会找不到
auto作为一个类型指示器来指示编译器,auto声明的变量必须由编译器在编译时期推导而得
3.1auto使用细则
①使用auto定义变量时必须对其进行初始化,在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。因此auto并非是一个类型的声明,而是一个类型声明时的“占位符”,编译器在编译期会将auto替换为变量的实际类型
②auto与指针和引用相结合起来使用:用auto声明指针类型时,用auto*和auto没有任何区别,但用auto声明引用类型时必须加&
③在同一行定义多个变量:当在同一行声明多个变量时,必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量
④auto不能作为函数的参数
⑤auto不能直接用来声明数组
如果想要改变数组的元素,就可以用到前面学习的引用
for循环后的括号由冒号:分为两部分:第一个部分是范围内用于迭代的变量,第二部分则表示被迭代的范围
使用条件:
1.for循环迭代的范围必须是确定的,对于数组而言就是数组的第一个元素和最后一个元素的范围
2.迭代的对象必须要实现 和==的操作
现在只要掌握怎么用就好,现在毕竟是c 入门,后面会详细讲的
对于null的定义就是如果使用了c ,那么null就为0,因此下面的代码就会出现问题,只能把null强制转换为int才能得到想要的结果
因此c 11引入了nullptr
注意:
①在使用nullptr表示指针空值时,不需要包含头文件,因为nullptr是c 11作为新关键字引入的。
② 在c 11中,sizeof(nullptr) 与 sizeof((void)0)所占的字节数相同。
③为了提高代码的健壮性,在后续表示指针空值时建议最好使用nullptr。