当前位置: 首页 > news >正文

山东网站建设哪家便宜网站改版如何做301

山东网站建设哪家便宜,网站改版如何做301,企业网站用户群,成都房产网最新楼盘二手房信息#x1f4dd;个人主页#xff1a;夏目浅石. #x1f4cc;博客专栏#xff1a;C的故事 #x1f3e0;学习社区#xff1a;夏目友人帐. 文章目录 前言Ⅰ. 函数重载0x00 重载规则0x01 函数重载的原理名字修饰 Ⅱ. 引用0x00 引用的概念0x01 引用和指针区分0x03 引用的本质0x04… 个人主页夏目浅石. 博客专栏C的故事 学习社区夏目友人帐. 文章目录 前言Ⅰ. 函数重载0x00 重载规则0x01 函数重载的原理名字修饰 Ⅱ. 引用0x00 引用的概念0x01 引用和指针区分0x03 引用的本质0x04 引用的特性0x05 引用的使用场景0x06 常引用0x07 指针和引用区别 Ⅲ. 结语 前言 亲爱的夏目友人帐的小伙伴们今天我们继续讲解 C 入门的知识 函数重载 和 引用 这里的知识虽然入门但是却是你后面更加深入学习 C 知识的钥匙所以请跟着夏目学长一起进入 C 的世界吧 Ⅰ. 函数重载 函数重载的定义 函数重载是函数的一种特殊情况C允许在同一作用域中声明几个功能类似的同名函数这些同名函数的形参列表(参数个数 或 类型 或 类型顺序)不同常用来处理实现功能类似数据类型不同的问题。 我们都知道 C 是对 C语言的 “升级版” 所以不难想到函数重载就是对 C语言 的扩展知识C语言当中是不允许函数名字是相同的如果出现则 就会报错而在 C 却是可以的。 0x00 重载规则 如果一个函数想要满足函数重载则需要满足重载规则(其中一个) 参数类型不同参数个数不同参数类型顺序不同 而对于 C 函数重载 即 函数名字 相同 是可以存在的。 下面根据上面的三个规则给出具体的例子。 // 参数类型不同 int add(int left , int right) {return left right; }int add(double left , double right) {return left right; }// 参数个数不同 int add(double left , double right , int mid) {return left right; }// 参数类型顺序不同 int add(int left , int right) {return left right; }char add(char right , char left) {return left right; } 值得注意的是 函数重载需要在同一块命名空间 因为函数重载是根据类型识别的所以对于相同类型的数据顺序不同不构成函数重载而且编译器无法识别 // 错误样例 不构成重载 int add(int left , int right) {return left right; }int add(int right , int left) {return left right; }0x01 函数重载的原理名字修饰 为什么C支持函数重载而C语言不支持函数重载呢 在C/C中一个程序要运行起来需要经历以下几个阶段预处理、编译、汇编、链接。 从汇编角度来讲调用函数处会变成 call add(地址) 的形式然后通过汇编指令完成调用。 所以对于C语言来说就是依靠函数名去找函数的如果函数名相同则会冲突因为不知道找哪个函数. 对于C来说不同平台就有不同的修饰规则对于 vs 上比较复杂 所以退而求其次这里我们讲 Linux 上的 int add(int left, int right) {return left right; }对于这个函数就会被修饰为 _Z3addii 我想这里你肯定看不懂所以我先给你讲解一下Linux系统下修饰的规则 Linux 下修饰规则—格式 _ Z 函数名称长度 函数名 类型首字母 下面是验证的例子 对于相同名字的函数函数重载就根据参数的类型顺序个数以这些为基准来区别不同的函数。 而根据上面的验证我们也知道为什么 返回值不同 和 参数类型相同但顺序不同 为什么不能构成函数重载的原因 因为对于 参数类型相同但顺序不同形成的后缀还是一样的 并不能区分该调用哪个函数而对于返回值不同的其他都相同的函数来说则是因为分不清调用哪个函数不仅仅是因为函数返回值不在修饰规则内。 Windows 下修饰规则简单了解 Ⅱ. 引用 0x00 引用的概念 引用不是新定义一个变量而是给已存在变量取了一个别名编译器不会为引用变量开辟内存空间它和它引用的变量共用同一块内存空间。 通俗来讲别名又可以说是外号代称比如水浒传里几乎是别名最多的地方。李逵在家称为铁牛江湖上人称黑旋风。铁牛和黑旋风就是李逵的别名。 #includeiostreamusing namespace std;int main() {int a 10;int b a;// b是a的引用cout a endl;cout b endl;return 0; }0x01 引用和指针区分 我们在学习 C语言 的时候知道 是 取地址的意思所以在这里要给大家讲讲 的含义。 就是引用但是 这个操作符和取地址 操作符是重叠的。 所以它们需要不同的场景规范 当 b 单独存在时这时就代表取地址为取出变量的地址。 但是如果这样 #includeiostreamusing namespace std;int main() {int a 10;int b a; //引用int* ptr a; // 取地址return 0; }0x03 引用的本质 我们可以打开调试窗口进行查看a和b的地址和值: 我们发现a和b不仅值相等连地址也是相同的。而这就说明b 就是 a 在语法层面上这里 b 并不是开辟的新空间而是对原来的 a 取了一个新名称叫做 b 。 就好比李逵被叫做黑旋风一样李逵还是李逵黑旋风也是它而 a 就是 a 但是 b 也是 a 。 而如果这时候对 a 或 b 任意一个修改那么 a 和 b 都会发生修改。 #includeiostreamusing namespace std;int main() {int a 10;int b a; //引用b 20;cout b endl;cout a endl;return 0; }0x04 引用的特性 1. 引用在定义时必须初始化 // 错误样例 int main() {int a 10;int b;return 0; }引用是取别名所以在定义的时候必须明确是谁的别名。 2. 一个变量可以有多个引用 一个变量也可以有多个别名。 int main() {int a 10;int b a;int c a;int d a;return 0; }而对于一个起过别名的变量对它的别名取别名也是可以的。 就好比说有人可能知道李逵也叫铁牛并不知道他真实姓名但是他觉得李逵很黑于是叫他黑旋风这也没问题因为这里描述的都是一个人同理描述的也是同一个变量。 int main() {int a 10;int b a;int c b;int d c;return 0; }3. 引用一旦引用一个实体就不能引用其他实体 int main() {int a 10;int b a; // 引用int c 20;b c;// 赋值操作return 0; }引用一旦引用一个实体就不能引用其他实体引用是不会发生改变的。 但是对于指针则是截然不同的 int main() {int a 10;int c 20;int* p a;p c;return 0; }对于指针来说指针可以时刻修改 p原本指向 a , 现在指向 c 但是引用也有局限性因为引用之后的变量是不可修改引用的比如链表节点是要不断更替迭代的所以还需要指针配合C才可以写出一个链表。 0x05 引用的使用场景 1. 做参数 我们知道实参的改变不影响实参所以这种写法并不能改变值因为此刻是 传值调用 #includeiostreamusing namespace std;void Swap(int x,int y) {int tmp x;x y;y tmp; }int main() {int a 10;int b 20;cout a a b b endl;Swap(a,b);cout a a b b endl;return 0; }使用引用修改后 #includeiostreamusing namespace std;void Swap(int x,int y) {int tmp x;x y;y tmp; }int main() {int a 10;int b 20;cout a a b b endl;Swap(a,b);cout a a b b endl;return 0; }x 和 y 分别是 a 和 b 的引用对 x 和 y 进行修改就是对 a 和 b 进行修改所以值也被修改成功了。 它们的地址是完全相同的。而这里这里既不是传值调用也不是传址调用而是 传引用调用 。 思考上面三个函数是否构成函数重载 构成但无法调用。 根据函数名修饰规则传值和传引用的是不一样的比如会加上 R 做区分。 但是不能同时调用传值和传引用因为有歧义因为 调用不明确 编译器并不知道调用哪个: #includeiostreamusing namespace std;void Swap(int x,int y) {int tmp x;x y;y tmp; }void Swap(int x,int y) {int tmp x;x y;y tmp; }int main() {int a 10;int b 20;cout a a b b endl;Swap(a,b);cout a a b b endl;return 0; }2. 引用解决二级指针生涩难懂的问题 讲单链表时我们写的由于是没有头结点的链表所以修改时需要二级指针对于指针概念不清晰的小伙伴们可能比较难理解。 但是学了引用就可以解决这个问题 结构定义 typedef struct SListNode {int data;struct SListNode* next; }SLTNode; 原代码 void SListPushFront(SLTNode** pphead, SLTDateType x) {SLTNode* newnode BuyListNode(x);newnode-next *pphead; *pphead newnode; }// 调用 SLTNode* pilst NULL; SListPushFront(plist);修改后 void SListPushFront(SLTNode* pphead, SLTDateType x) // 改 {SLTNode* newnode BuyListNode(x);newnode-next *pphead; *pphead newnode; }// 调用 SLTNode* pilst NULL; SListPushFront(plist); // 改 修改之后的代码里的二级指针被替换成了引用。 而这里的意思就是给一级指针取了一个别名传过来的是plist而plist 是一个一级指针所以会出现 * 而这里就相当于 pphead 是 plist 的别名。而这里修改 pphead 也就可以对 plist 完成修改。 但是有时候也会这么写 结构定义 typedef struct SListNode {int data;struct SListNode* next; }SLTNode, *PSLTNode; 这里的意思就是将 struct SListNode* 类型重命名为 PSLTNode 。 void SListPushFront(PSLTNode pphead, SLTDateType x) // 改 {PSLTNode newnode BuyListNode(x);newnode-next pphead; pphead newnode; }// 调用 PSLTNode plist NULL; SListPushFront(plist); 在 typedef 之后PSLTNode 就是结构体指针所以传参过去只需要在形参那边用引用接收随后进行操作就可以达成目的。 而形参的改变影响实参的参数叫做输出型参数对于输出型参数使用引用十分方便 3.做返回值 //用引用来接收n的引用 #includeiostream using namespace std; int Count(int x) {int n x;n;// ...return n; }int main() {int ret Count(10);//随机值cout ret endl;Count(20);cout ret endl;//随机值return 0; }这里打印ret的值是不确定的 如果Count函数结束栈帧销毁栈帧没有清理那么ret的值是侥幸正确的 如果Count函数结束栈帧销毁栈帧被清理那么ret的值是随机值 这里可能是编译器的问题结果和我们预想的是一样的但是别的编译器来运行可能就会是随机值 当第一次调用Count函数时返回n的引用。 第二次调用相同的函数栈帧用的是同一块空间并且 ret 是 n 的引用的别名所以出现与传参预期的结果一样那么当调用其他不同的函数后那么该栈帧就会被覆盖则第二次打印ret就会出现随机值了所以这样使用ret是错误的。 // 正确的做法 #includeiostream using namespace std; int Count(int x) {static int n x;n;// ...return n; }int main() {int ret Count(10);cout ret endl;Count(20);cout ret endl;return 0; } 而这时 static 修饰的静态变量不委屈了n不会被销毁所以就不会产生随机值这一错误了 0x06 常引用 以前学习C语言的时候我们知道const 修饰的是常变量不可修改。 #includeiostream using namespace std; int main() {const int a 10;int b a;return 0; }a 本身都不能修改b 为 a 的引用那么 b 也不可以修改这样就没意义了。a 是只读但是引用 b 具有 可读可写 的权利该情况为 权限放大 所以错误了。 这时只要加 const 修饰 b 让 b 的权限也只有只读使得 权限不变 就没问题了 int main() {const int a 10;const int b a;return 0; }而如果原先变量可读可写但是别名用 const 修饰也是可以的这种情况为 权限缩小 对于函数的返回值来说也不能权限放大例如 int func() {static int n 0;n;return n; }int main() {int ret func();// 错误的return 0; }这样也是不行的因为返回方式为 传值返回 返回的是临时变量具有 常性 是不可改的而引用放大了权限所以是错误的这时加 const 修饰就没问题const int ret func() 0x07 指针和引用区别 从语法概念上来说引用是没有开辟空间的而指针是开辟了空间的但是从底层实现上来说则又不一样 int main() {int a 10;int r a;r 20;int* p a;*p 20;return 0; } 其实从汇编上引用其实是开空间的并且实现方式和指针一样引用其实也是用指针实现的。 区别汇总 引用概念上定义一个变量的 别名 指针存储一个变量 地址引用 在定义时 必须初始化 指针最好初始化 但是不初始化也不会报错引用在初始化时引用一个实体后 就不能再引用其他实体 而指针可以在任何时候指向任何一个同类型没有NULL引用但有NULL指针在sizeof中含义不同引用结果为 引用类型的大小但指针始终是 地址空间所占字节个数 (32位平台下占4个字节)引用自加即引用的实体增加1指针自加即指针向后偏移一个类型的大小有多级指针但是没有多级引用访问实体方式不同指针需要显式解引用引用编译器自己处理引用比指针使用起来相对更安全 Ⅲ. 结语 [ 笔者 ] 夏目浅石.[ 更新 ] 2023.9.21 ❌ [ 勘误 ] /* 暂无 */[ 声明 ] 由于作者水平有限本文有错误和不准确之处在所难免本人也很想知道这些错误恳望读者批评指正参考文献 B. 比特科技. C/C[EB/OL]. 2021[2021.8.31] 如果侵权请联系作者夏目浅石立刻删除
http://icebutterfly214.com/news/47644/

相关文章:

  • K8S集群怎么强制删除Pod
  • 二十二、定时备份数据库案例1
  • 10、top 命令 动态监控进程
  • 在线调试--天气
  • 2025年评价高的恒功率电伴热带厂家推荐及选购参考榜
  • 2025年评价高的聚脲行业内口碑厂家排行榜
  • 20232308 2025-2026-1 《网络与系统攻防技术》实验七实验报告
  • 2025年口碑好的钱币拍卖潜力黑马榜
  • 2025年知名的黑色退火丝厂家最新推荐权威榜
  • 2025年评价高的桥门式起重机用户好评厂家排行
  • linux $line
  • kali linux输入中文
  • kali linux 网卡
  • Boost Key Programming Speed with CG A10-3+1 HON.D Style 4-Button Remote (5pcs) for CGDI K2
  • java执行linux 命令
  • alpha阶段工作总结11.17
  • java 读取文件linux文件
  • java 读取linux 文件
  • 第三章作业 动态规划
  • 用 Go 进行验证码识别
  • 奶牛快传服务调整公告
  • 从零实现 REINFORCE/GRPO —— 大模型推理强化微调实践
  • 从0到1:揭秘LLM预训练前的海量数据清洗全流程
  • CF2169A题解
  • Sora 2 Cameo多角色上传+Remix二创功能API接入教程,史低0.08/条
  • 基于MIMO系统的SCMA稀疏码多址接入和MPA消息传递算法matlab仿真
  • 一次尝试,3个小时90元的主机游玩和F1电影
  • [GESP202506 二级] 幂和数
  • 2025 年锚具厂家 TOP 企业品牌推荐排行榜,预应力锚具 / 五孔锚具 / 低回缩锚具 / 张拉锚具 / 固定端锚具 / 桥梁预应力锚具 / 边坡锚具公司推荐!
  • 论文速读 | 2025年11月