【C++】入门(二)

在这里插入图片描述

前言:
c++基础语法(下)


文章目录

  • 五、引用
    • 5.1 引用概念
    • 5.2 引用使用规则
    • 5.3 常引用
    • 5.4 引用的使用场景
    • 5.5 引用和指针的区别
  • 六、内联函数
    • 6.1 概念
    • 6.2 内联函数的特性
  • 七、auto关键字(C++11)
    • 7.1 概念
    • 7.2 使用规则
    • 7.3 用于for循环(C++11)
  • 八、指针空值nullptr(C++11)

五、引用

5.1 引用概念

引用是C++语言中的一种机制,用于创建变量的别名。它使用一个已存在的变量来创建另一个名称,从而通过不同的名字访问相同的内存位置。

类型& 引用变量名(对象名) = 引用实体;int a = 10;
//创建引用
int& ra = a;

5.2 引用使用规则

规则如下:

  1. 引用必须在声明时进行初始化: 引用在定义的同时必须进行初始化。

    int a = 42;
    int& a1 = a; // 正确,引用被初始化
    
  2. 创建包含引用的数组: 创建一个包含引用的数组。

     int array[5] = {1, 2, 3, 4, 5};int& referencesArray[5] = {array[0], array[1], array[2], array[3], array[4]};//referencesArray 中的每个元素都是一个对应于 array 中相应索引位置的引用。上述代码创建了一个引用数组,并将每个引用与数组 array 中的元素相绑定。
    
  3. 引用不能重新赋值: 一旦引用被初始化,就不能改变其引用的对象。

    int a = 10;
    int b = 20;
    int& ref = a;
    ref = b; // 此时 a 的值变成 20,而不是修改引用的目标
    
  4. 一个变量可以有多个引用: 多个引用可以同时指向相同的变量,这样它们就共享相同的内存地址,对该变量的修改将会被所有引用所影响。

    int a = 10;
    int& b = a;//b,c都是a的别名
    int& c = a;int d = 5;
    b = d;//变量a被修改为5,同样的b = 5,c = 5
    

5.3 常引用

常引用(const reference)是指在声明引用时使用 const 关键字,以表明引用的目标对象在引用生命周期内不可通过别名修改。

#include <iostream>int main() {int a = 10;const int& b = a; // 常引用std::cout << "a: " << a << std::endl;std::cout << "b: " << b << std::endl;//a:10//b:10// 尝试修改 b 的值(这会导致编译错误)// b = 20;// 修改原始变量 a 的值a = 30;std::cout << "a: " << a << std::endl;std::cout << "b: " << b << std::endl;//a:30//b:30return 0;
}

另外,对常量的常引用时合法的,但对常量的引用不合法

//可以访问常量的值,但不能通过 a 来修改这个值
const int& b = 10;
//int& b = 10; 不合法

5.4 引用的使用场景

  1. 传递函数参数: 通过引用传递参数,可以避免传递大型对象时的复制开销,同时允许在函数内部修改传入的变量。常引用用于确保在函数内部不能修改传入的值。

    void modifyValue(int& value) {value *= 2;
    }int main() {int num = 5;modifyValue(num);// num 在此处被修改为 10return 0;
    }
    
  2. 返回引用: 函数可以返回引用,允许对函数返回值进行修改。这在实现链式调用等情况下很有用。

    int array[5] = {1, 2, 3, 4, 5};int& getElement(int index) {return array[index];
    }int main() {getElement(2) = 10;// array[2] 在此处被修改为 10return 0;
    }
    

    这里数组是全局的,因此在getElement返回值时,数组元素并没有被销毁,因此 array[2] 能被成功修改

    如果是以下的这种情况,变量c 随函数栈帧的销毁也被收回空间,那么这个时候返回c的引用就是无效的,其返回的值是随机值

    int& Add(int a, int b){int c = a + b;return c;
    }int main(){int& ret = Add(1, 2);Add(3, 4);cout << "Add(1, 2) is :"<< ret <<endl;return 0;
    }
    

    在这里插入图片描述


5.5 引用和指针的区别

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址。

    • 引用提供了一种直观的别名机制,不需要显式解引用。
    • 指针存储变量地址,需要通过解引用操作符 * 才能访问目标对象。
  2. 引用在定义时必须初始化,指针没有要求。

    • 引用在创建时必须初始化,并且一旦与某个对象关联,就不能再引用其他对象。
    • 指针可以在声明后进行初始化,也可以在后续重新指向其他对象。
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。

    • 引用在创建后与某个实体绑定,无法再引用其他实体。
    • 指针可以在运行时指向不同的对象。
  4. 没有NULL引用,但有NULL指针。

    • 引用不能为NULL,必须在初始化时指向一个有效的对象。
    • 指针可以为空,即指向 nullptrNULL
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)。

    • sizeof 运算符对引用返回引用类型的大小。
    • sizeof 运算符对指针返回指针所占的字节大小,通常与地址空间的大小相关。
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。

    • 引用自增是对引用的实体进行加法操作。
    • 指针自增是将指针指向的地址向后移动一个类型的大小。
  7. 有多级指针,但是没有多级引用。

    • C++ 支持多级指针,可以有 int**int*** 等形式。
    • 没有多级引用的概念,引用通常是单层的。
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理。

    • 引用在使用时无需显式解引用,直接使用引用即可。
    • 指针需要通过解引用操作符 * 显式访问目标对象。
  9. 引用比指针使用起来相对更安全。

    • 引用在使用时更为直观,编译器会在一定程度上确保引用的合法性。
    • 指针可能引发空指针、野指针等问题,需要小心管理。

六、内联函数

6.1 概念

内联函数是C++中的一种编译器优化手段,它通过将函数的定义嵌入到调用该函数的地方,而不是通过传统的函数调用机制,以提高程序的执行效率。

使用关键字 inline 来告诉编译器希望将函数内联展开。在函数定义或声明前加上 inline 关键字即可。

inline int add(int a, int b) {return a + b;
}int main() {int a = 0;int b = 1;cout << "a+b=" << add(a, b) << endl;return 0;
}

6.2 内联函数的特性

  1. 适用于短小的函数: 内联函数适用于函数体较短小的情况,因为内联的目的是减少函数调用的开销,而将大型函数内联可能会导致代码膨胀(函数被内联展开,那么在每个调用点都会生成一份该函数的代码,增加代码的体积,可能导致更大的可执行文件)。

  2. 编译器决定内联: 使用 inline 关键字只是向编译器发出一个建议,最终是否内联取决于编译器的决策。通常,编译器会根据函数的复杂性和调用频率等因素来判断是否进行内联。
    一般来说,将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现)、不是递归、且频繁调用的函数采用inline修饰

  3. 头文件中定义内联函数: 通常,内联函数的定义会放在头文件中,以便在多个源文件中进行内联展开。

    // header.h
    inline int add(int a, int b) {return a + b;
    }
    
    // main.cpp
    #include "header.h"int main() {int result = add(3, 4);  // 内联展开return 0;
    }
    

七、auto关键字(C++11)

7.1 概念

auto 是C++11引入的关键字,用于在声明变量时由编译器自动推导变量的类型。使用 auto 可以简化代码,特别是在涉及复杂的类型或使用模板时。以下是关于 auto 的一些关键点:

  1. 自动类型推导: auto 关键字可以用于声明变量,让编译器自动推导变量的类型。编译器在编译时会根据变量的初始化表达式推断其类型。

    auto x = 10;         // x 的类型将被推断为 int
    auto y = 3.14;       // y 的类型将被推断为 double
    auto z = "Hello";    // z 的类型将被推断为 const char[6]
    
  2. 适用于各种类型: auto 可以用于推导各种类型,包括基本数据类型、复合类型、指针、引用等。

    auto i = 42;               // int
    auto f = 3.14f;            // float
    auto ptr = new int(5);     // int*
    auto& ref = i;             // int&
    

7.2 使用规则

  1. auto与指针和引用结合起来使用: 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。

    int main(){int x = 10;auto a = &x;auto* b = &x;auto& c = x;//用于获取表达式的类型信息cout << typeid(a).name() << endl;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;*a = 20;*b = 30;c = 40;return 0;
    }
    
  2. 在同一行定义多个变量: 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

    auto a = 1, b = 2; 
    auto c = 3, d = 4.0;  // 该行代码会编译失败,因为c和d的初始化表达式类型不同
    
  3. 不能作为函数的参数类型: 函数参数的类型必须在编译时确定,而 auto 是用来进行类型推导的,无法在函数参数中使用。在函数参数中,必须显式指定参数的类型。

    void myFunction(auto x) {  // 错误,auto 不能用作函数参数类型// 函数体
    }
    
  4. 不能直接用来声明数组: 在数组声明中,编译器需要知道数组的元素类型和大小,而 auto 无法提供这些信息。因此,直接使用 auto 来声明数组是不允许的。

    auto myArray[] = {1, 2, 3};  // 错误,auto 不能直接用于数组声明
    

7.3 用于for循环(C++11)

auto 用于范围-based for 循环时,它会自动推导迭代变量的类型,并且可以遍历容器中的元素,使代码更加简洁。以下是使用 auto 的范围-based for 循环的示例:

auto 自动推导出 num 的类型,而 for 循环会遍历 numbers 容器中的每个元素,并将元素的值赋给 num

#include <iostream>
#include <vector>int main() {std::vector<int> numbers = {1, 2, 3, 4, 5};// 使用 auto 和范围-based for 循环遍历容器中的元素for (auto num : numbers) {std::cout << num << " ";}std::cout << std::endl;return 0;
}

在这里插入图片描述


八、指针空值nullptr(C++11)

nullptr 是 C++11 引入的空指针常量,用于代替传统的空指针值 NULL。nullptr 具有更强的类型安全性。

在传统的C头文件(stddef.h)中,可以看到如下代码:
NULL 实际上是一个宏,通常被定义为 0 或 (void*)0。

#ifndef NULL
#ifdef __cplusplus
#define NULL   0
#else
#define NULL   ((void *)0)
#endif
#endif

示例:

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

在这里插入图片描述

程序本意是想通过f(NULL)调用指针版本的f(int* a)函数,但是由于NULL被定义成0,因此与程序的
初衷相悖。
在C++98中,编译器默认情况下将其NULL看成是一个整形常量0。当我们使用NULL调用f(int* a)时必须强转类型 (int*)NULL。而nullptr 明确表示空指针


在这里插入图片描述
如果你喜欢这篇文章,点赞👍+评论+关注⭐️哦!
欢迎大家提出疑问,以及不同的见解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/644352.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

社区分享|百果园选择DataEase搭档蜜蜂微搭实现企业数据应用一体化

百果园&#xff0c;全称为深圳百果园实业&#xff08;集团&#xff09;股份有限公司&#xff0c;2001年12月成立于深圳&#xff0c;2002年开出中国第一家水果专卖店。截至2022年11月&#xff0c;百果园全国门店数量超过5600家&#xff0c;遍布全国140多个城市&#xff0c;消费会…

5118优惠码vip、svip、专业版和旗舰版使用yhm666

5118大数据平台会员优惠码【yhm666】&#xff0c;结算时勾选“使用优惠码”&#xff0c;然后在优惠码窗口中输入yhm666&#xff0c;然后点确定即可享受特价会员价格。阿腾云atengyun.com分享如下图&#xff1a; 5118会员优惠码【yhm666】 5118会员价格和使用优惠码之后的价格对…

ubuntu 20.04 使用 webrtc-streamer自动退出,报错GLIBC 问题解决方法

文章目录 前言Ubuntu 20.4中使用webrtc-streamer报错总结 前言 前端vue2 项目需要播放海康的视频流&#xff0c;本地启动起来了&#xff0c;现在需要的服务器上部署&#xff0c;服务器是Ubuntu 20.04&#xff0c;下面是部署时遇到的问题及解决方法&#xff0c;总耗时2天。 不知…

【GitHub项目推荐--不错的 Java 开源项目】【转载】

1 基于 Java 的沙盒塔防游戏 Mindustry 是一款用 Java 编写的沙盒塔防游戏。玩家需要建造精密的传送带供应链&#xff0c;提供炮塔弹药&#xff0c;生产建筑材料&#xff0c;保护建筑并抵御敌人。也可以在跨平台多人合作游戏中与朋友一起战斗&#xff0c;或组队进行 PVP 比赛。…

多图合并二维码的制作方法,快速在线生成图片二维码

怎么将多张图合并用二维码展示呢&#xff1f;现在经常会通过扫码的方式来查看图片&#xff0c;选择这种方式不仅可以展现更多地内容&#xff0c;还能够减少图片对个人容量的占用&#xff0c;增加用户的交互性和娱乐性。那么如何使用二维码生成器来快速制作图片二维码呢&#xf…

openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)

文章目录 openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具)概述效果笔记编程环境界面控件的设置增加文件拖拽的类RSA证书和key是否匹配的实现在程序中加入环境变量备注备注END openssl3.2 - 检查rsa证书和私钥是否匹配(快速手搓一个工具) 概述 在学习openssl官方的…

Python 变量?对象?引用?赋值?一个例子解释清楚

哈喽大家好&#xff0c;我是咸鱼。 前天有个小伙伴找到我&#xff0c;给了我一段 python 代码&#xff1a; a [1, 2] a[1] a print(a[1])然后问我为什么结果是 [1, [...]]&#xff0c;我一看这个问题有意思&#xff0c;我说三言两语解释不清楚&#xff0c;我写篇文章到时候…

和硕拿下AI Pin代工大单公司 | 百能云芯

和硕公司近日成功中标AI Pin代工大单&#xff0c;AI Pin被认为是继iPhone之后的下一个划时代产品&#xff0c;吸引了全球科技圈的广泛关注。和硕公司对此表示&#xff0c;他们不会只专注于单一客户&#xff0c;而是期望在下半年有更多新品上市&#xff0c;为公司带来丰硕的业绩…

C++ -- 入门(引用)

1.引用 1.1引用的概念 引用不是新定义一个变量&#xff0c;而是给已存在变量取了一个别名&#xff0c;编译器不会为引用变量开辟内存空间&#xff0c;它和它引用的变量共用同一块内存空间。 比如&#xff1a;李逵&#xff0c;在家称为"铁牛"&#xff0c;江湖上人称&q…

CC工具箱使用指南:【平差工具】

一、简介 平差是一个摘自英文单词“adiustment”的中文翻译&#xff0c;它最初源于土地测量工程&#xff0c;并在后来广泛应用于各个测量领域在传统的测量中&#xff0c;由于各种误差的存在&#xff0c;例如仪器、人为、大地形态等因素&#xff0c;所得到的测量结果是不完全准…

MySQL基础(一)

学习数据库的目的&#xff1a; 实现数据持久化到本地。使用完整的管理系统统一管理&#xff0c;可以实现结构化查询&#xff0c;方便管理。 一、数据库概述 数据库&#xff08;DataBase&#xff09; 为了方便数据的存储和管理&#xff0c;它将数据按照特定的 规则存储在磁盘…

项目解决方案: 视频融合(实时监控视频和三维建模进行融合)设计方案

目 录 一、需求描述 1、视频接入和控制要求 2、视频播放需求 3、提供其他应用的调用 二、方案设计 &#xff08;一&#xff09;系统设计图 &#xff08;二&#xff09;产品实现方案 三、产品和功能描述 &#xff08;一&#xff09;总体描述 &#xf…

Java 数据结构集合

文章目录 Java 数据结构1. 基本数据结构1.1 数组 (Array)1.2 链表 (Linked List)1.3 栈 (Stack)1.4 队列 (Queue)双向队列优先级队列 2. 树形数据结构2.1 二叉树 (Binary Tree)2.2 堆 (Heap) 3. 散列数据结构3.1 哈希表 (Hash Map)3.2 LinkedHashMap3.3 TreeMapConcurrentHashM…

【C++练级之路】【Lv.7】【STL】vector类的模拟实现

快乐的流畅&#xff1a;个人主页 个人专栏&#xff1a;《C语言》《数据结构世界》《进击的C》 远方有一堆篝火&#xff0c;在为久候之人燃烧&#xff01; 文章目录 引言一、成员变量二、默认成员函数2.1 constructor2.2 destructor2.3 copy constructor2.4 operator 三、迭代器…

Java毕业设计-基于jsp+servlet的学生推荐平台管理系统-第81期

获取源码资料&#xff0c;请移步从戎源码网&#xff1a;从戎源码网_专业的计算机毕业设计网站 项目介绍 基于jspservlet的学生推荐平台管理系统&#xff1a;前端 jsp、jquery&#xff0c;后端 servlet、jdbc&#xff0c;集成用户端和管理后台&#xff0c;用户端浏览书籍课程&…

Web06--JavaScript基础02

1、JS流程控制语句 JS与Java一样&#xff0c;也有三个流程控制语句&#xff1a; 顺序结构 选择结构 循环结构 1.1 选择结构 1.1.1 if结构 <script type"text/javascript">if (条件表达式) {代码块;} else if(条件表达式){代码块;} else {代码块;} </scr…

选择排序 | 冒泡排序 | C语言(详解)

一&#xff0c;选择排序 1&#xff0c;基本知识 对排序的双层 for 循环的理解&#xff1a;外层 控制趟数&#xff0c;里层 不断地对数组进行遍历。 2&#xff0c;逐层深入 经典的选择排序GIF动图&#xff0c;如下&#xff1a; 关键部分&#xff1a; Ⅰ&#xff0c;从数组中…

mathematical-expression 实现 数学表达式解析 Java 篇

mathematical-expression 实现 数学表达式解析 Java 篇 Java技术栏 使用 ME&#xff08; mathematical-expression&#xff09;数学表达式解析库 实现Java中 数学表达式 的解析和计算。 目录 文章目录 mathematical-expression 实现 数学表达式解析 Java 篇目录mathematical-…

面试知识点:notify是随机唤醒线程吗(唤醒线程顺序)?

做 Java 开发的小伙伴&#xff0c;对 wait 方法和 notify 方法应该都比较熟悉&#xff0c;这两个方法在线程通讯中使用的频率非常高&#xff0c;但对于 notify 方法的唤醒顺序&#xff0c;有很多小伙伴的理解都是错误的&#xff0c;有很多人会认为 notify 是随机唤醒的&#xf…

构建中国人自己的私人GPT—与文档对话

先看效果 他可以从上传的文件中提取内容作为答案。上传文件摄取速度 摄取速度取决于您正在摄取的文档数量以及每个文档的大小。为了加快摄取速度&#xff0c;您可以在配置中更改摄取模式。 存在以下摄取模式&#xff1a; simple&#xff1a;历史行为&#xff0c;一次按顺序摄…