96SEO 2026-02-23 12:49 16
上一篇博客【C初阶】C入门(一):命名空间C的输入输出缺省参数函数重载

1.引用1.1引用的概念1.2引用的特性1.2.1引用在定义时必须初始化1.2.2一个变量可以有多个引用1.2.3引用一旦引用了一个实体就不能再引用其他实体
1.3引用的使用场景1.3.1引用做参数(输出型参数)1.3.2解决二级指针难懂的问题
auto与指针和引用结合起来使用3.2.2在同一行定义多个变量
auto不能推导的场景3.3.1auto不能作为函数的参数3.3.2auto不能直接用来声明数组
4.基于范围的for循环(C11)4.1范围for的使用条件4.1.1for循环迭代的范围必须是确定的4.1.2迭代的对象要实现和操作
引用不是定义一个变量而是已存在的变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。
a;此时b已经是a的引用了b不能再引用其他实体。
如果写下以下代码想让b引用另一个变量c
c;//错误想法让b转而引用c但该代码的意思是将b引用的实体赋值为c也就是将变量a的内容改成了20。
形参的改变影响实参的参数叫做输出型参数对于输出型参数使用引用十分方便。
C语言中的交换函数学习C语言的时候经常用交换函数来说明传值和传址的区别。
现在我们学习了引用可以不用指针作为形参了
}因为在这里a和b是传入实参的引用我们将a和b的值交换就相当于将传入的两个实参交换了。
在单链表的C语言实现的这篇博客里由于是没有头结点的链表所以修改时需要二级指针刚开始学习的时候可能比较难理解。
但是学了引用就可以解决这个问题
SListPushFront(plist);修改后的二级指针被替换成了引用:
修改这里的意思是给一级指针取了一个别名传过来的是plist而plist
就是结构体指针所以传参过去只需要在形参那边用引用接收随后进行操作就可以达成目的。
}这里看似很简单就是把Count函数计算结束的结果返回但是这里包含了
的函数栈帧已经销毁了这里打印的ret的值是不确定的。
因为空间已经归还给操作系统了这时都是非法访问所以必定是n拷贝后的数据被返回。
不论这个函数结束返回的那个值会不会被销毁都会创建临时变量返回例如
}对于该函数编译器仍然是创建临时变量返回因为编译器不会对其进行特殊处理仍然是放到
但这个临时变量创建的有点多余明明这块空间一直存在却依然创建临时变量返回
的空间此时n的空间已经还给操作系统了由于这是读操作编译器不一定检查出来但是本质是错的类似野指针访问。
eg调用Count函数后再调用其他函数后会再次建立栈帧后面的栈帧会覆盖前面的栈帧恰好出现随机值
引用返回的原则如果函数返回时出了函数作用域返回对象还在(还没还给系统)则可以使用引用返回如果已经还给系统了则必须使用传值返回。
区别就是传值返回生成拷贝引用返回不生成拷贝。
中间并不产生拷贝因为返回的是别名。
这就相当于返回的就是它本身。
总结如果出了作用域返回变量静态static全局变量上一层栈帧动态开辟malloc等不会随着函数调用的结束而被销毁的数据仍然存在则可以使用引用返回不能是函数内部创建的普通局部变量。
上面提到引用类型必须和引用实体是同种类型的。
但是仅仅是同种类型还不能保证能够引用成功我们若用一个普通引用类型去引用其对应的类型但该类型被const所修饰那么引用将不会成功。
}我们可以将被const修饰了的类型理解为安全的类型因为其不能被修改。
我们若将一个安全的类型交给一个不安全的类型可被修改那么将不会成功。
权限可以缩小此时x可以因为x本身有可以修改的权限且y、z的值同时也会变因为本来就是同一个空间x的改变就是y、z的改变。
只是作为z时由于权限限制z不行
同理这里错误的原因发生类型转换(提升、截断)的时候会产生一个临时变量
dd把dd转换后的值放到临时变量中把临时变量给接收的值ii而临时变量具有常性不可修改引用就加了写权限就错了因为
而下图由于返回的是x的别名不是x不会产生临时变量了再传给int
ret为权限平移总结对于引用引用后的变量所具权限可以缩小或不变但是不能放大指针也适用这个说法。
const
可以接收各种类型的对象变量、常量、隐式转换。
对于输出型参数可以用引用反之用
在语法概念上引用就是一个别名没有独立的空间其和引用实体共用同一块空间。
10;//在语法上这里给a这块空间取了一个别名没有新开空间int
20;//在语法上这里定义了一个pa指针开辟了4个字节32位平台的空间用于存储a的地址int*
}但是在底层实现上引用实际是有空间的从汇编角度来看引用的底层实现也是类似指针存地址的方式来处理的。
2、引用在初始化时引用一个实体后就不能再引用其他实体而指针可以在任何时候指向任何一个同类型实体。
4、在sizeof中的含义不同引用的结果为引用类型的大小但指针始终是地址空间所占字节个数32位平台下占4个字节。
5、引用进行自增操作就相当于实体增加1指针进行自增操作是指针向后偏移一个类型的大小。
7、访问实体的方式不同指针需要显示解引用而引用是编译器自己处理。
调用函数需要建立栈帧栈帧中要保存寄存器结束后就要恢复这其中都是有
优化因为宏是在预处理阶段完成替换的并没有执行时的开销并且因为代码量小也不会造成代码堆积。
}但通过上图可以看出写宏时很容易出错下次再错就挨打吧[bushi]要么是替换出错要么是优先级出错所以宏并不友好。
版本下其他版本优化的太多可能就不太好观察所以我们设置一下编译器在
就是函数调用的指令它的消失就说明第二段代码没有进行调用。
内联函数直接在局部展开了在
的做法如果编译器将函数当成内联函数处理在编译阶段会用函数体替换函数调用。
inline对于编译器而言只是一个建议不同编译器关于inline实现机制可能不同一般建议将函数规模较小(即函数不是很长具体没有准确的说法取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰否则编译器会忽略inline特性。
inline不建议声明和定义分离分离会导致链接错误。
因为inline被展开就没有函数地址了链接就会找不到。
1空间换时间是因为反复调用内联函数导致编译出来的可执行程序变大
条指令cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;cout111111endl;
行指令。
若用内联函数则展开若一千次调用每次调用的地方为都会展开为
展开会让编译后的程序变大如果递归函数作内联后果可想而知。
所以长函数和递归函数不适合展开。
2编译器可以忽略内联请求内联函数被忽略的界限没有被规定一般10行以上就被认为是长函数当然不同的编译器不同
中被引用由于内联函数在调用的地方展开所以内联函数无地址这里的地址指的是call
当编译时由于头文件要被包含但是这时只有函数声明但是没有函数的定义所以只能在链接时展开这里只能变为
所以当声明和定义分离调用函数时由于内联函数无地址编译器链接不到就会报错为链接错误。
1、inline是一种以空间换时间的做法省了去调用函数的额外开销。
由于内联函数会在调用的位置展开所以代码很长或者有递归的函数不适宜作为内联函数。
频繁调用的小函数建议定义成内联函数。
2、inline对于编译器而言只是一个建议编译器会自动优化如果定义为inline的函数体内有递归等编译器优化时会忽略掉内联。
3、inline不建议声明和定义分离分离会导致链接错误。
因为inline被展开就没有函数地址了链接就会找不到。
在早期的C/C中auto的含义是使用auto修饰的变量是具有自动存储器的局部变量但遗憾的是一直没有人去使用它。
在C11中标准委员会赋予了auto全新的含义auto不再是一个存储类型指示符而是作为一个新的类型指示符来指示编译器auto声明的变量必须由编译器在编译时期推导而得。
注意使用auto变量时必须对其进行初始化在编译阶段编译器需要根据初始化表达式来推导auto的实际类型。
因此auto并非是一种“类型”的声明而是一个类型声明的“占位符”编译器在编译期会将auto替换为变量实际的类型。
用auto声明指针类型时用auto和auto*没有任何区别但用auto声明引用类型时必须加
//自动推导出d的类型为int//打印变量b,c,d的类型cout
}注意用auto声明引用时必须加否则创建的只是与实体类型相同的普通变量。
当在同一行声明多个变量时这些变量必须是相同的类型否则编译器将会报错因为编译器实际只对第一个类型进行推导然后用推导出来的类型定义其他变量。
以下代码编译失败auto不能作为形参类型因为编译器无法对x的实际类型进行推导。
endl;以上方式也是我们C语言中所用的遍历数组的方式但对于一个有范围的集合而言循环是多余的有时还容易犯错。
因此C11中引入了基于范围的for循环。
for循环后的括号由冒号分为两部分第一部分是范围内用于迭代的变量第二部分则表示被迭代的范围。
endl;注意与普通循环类似可用continue来结束本次循环也可以用break来跳出整个循环。
对于数组而言就是数组中第一个元素和最后一个元素的范围对于类而言应该提供begin和end的方法begin和end就是for循环迭代的范围。
以下代码就有问题因为for的范围不确定因为函数传参数组就会退化为指针
在良好的C/C编程习惯中在声明一个变量的同时最好给该变量一个合适的初始值否则可能会出现不可预料的错误。
比如未初始化的指针如果一个指针没有合法的指向我们基本都是按如下方式对其进行初始化
0;NULL其实是一个宏在传统的C头文件(stddef.h)中可以看到如下代码
*/可以看到NULL可能被定义为字面常量0也可能被定义为无类型指针(void*)的常量。
但是不论采取何种定义在使用空值的指针时都不可避免的会遇到一些麻烦例如
}程序本意本意是想通过Fun(NULL)调用指针版本的Fun(int*
p)函数但是由于NULL被定义为0Fun(NULL)最终调用的是Fun(int
注意在C98中字面常量0既可以是一个整型数字也可以是无类型的指针(void*)常量但编译器默认情况下将其看成是一个整型常量如果要将其按照指针方式来使用必须对其进行强制转换。
1、在使用nullptr表示指针空值时不需要包含头文件因为nullptr是C11作为关键字引入的。
2、在C11中sizeof(nullptr)与sizeof((void*)0)所占的字节数相同。
3、为了提高代码的健壮性在后序表示指针空值时建议最好使用nullptr。
今天我们认识并具体学习了有关引用、内联函数、auto关键字、范围for循环(C11)、指针空值nullptr的知识。
接下来我们将继续学习C中类和对象的相关知识。
希望我的文章和讲解能对大家的学习提供一些帮助。
当然本文仍有许多不足之处欢迎各位小伙伴们随时私信交流、批评指正我们下期见~
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback