【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:30

    return 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 在此处被修改为 10
        return 0;
    }
    
  2. 返回引用: 函数可以返回引用,允许对函数返回值进行修改。这在实现链式调用等情况下很有用。

    int array[5] = {1, 2, 3, 4, 5};
    
    int& getElement(int index) {
        return array[index];
    }
    
    int main() {
        getElement(2) = 10;
        // array[2] 在此处被修改为 10
        return 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 明确表示空指针


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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

自然语言处理--基于HMM+维特比算法的词性标注

自然语言处理作业2--基于HMM维特比算法的词性标注 一、理论描述 词性标注是一种自然语言处理技术&#xff0c;用于识别文本中每个词的词性&#xff0c;例如名词、动词、形容词等&#xff1b; 词性标注也被称为语法标注或词类消疑&#xff0c;是语料库语言学中将语料库内单词…

【Java-框架-SpringSecurity】单点登录(认证和授权)- 随笔

项目文件&#xff1b; 【1】 预览 文件 文件01 名称 pom.xml&#xff1b; 内容 &#xff08;01&#xff09;总的 <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http:…

RFID标签是什么?该技术有哪些应用领域?

射频识别&#xff08;RFID&#xff09;技术利用电磁场&#xff0c;自动识别和跟踪附在物体上的标签&#xff0c;其中&#xff0c;近场通信&#xff08;NFC&#xff09;是一种基于短距离RFID高频技术的标准&#xff0c;支持13.56 MHz的频率。 NFC技术在现今的产品中应用广泛&am…

一文掌握全方位构建 ECS 安全体系的最佳方法

云布道师 2024 开年伊始&#xff0c;阿里云弹性计算团队全新推出新一季【ECS 安全季】&#xff0c;通过分享云上安全体系相关产品与最佳实践&#xff0c;让用户快速上手构建业务的安全防护能力。 首节课程《如何全方位构建 ECS 的安全体系》由阿里云弹性计算高级产品专家马小…

Python一些可能用的到的函数系列122 ATimer2

说明 由于时间处理在算网中起到了更重要的作用&#xff1a;不仅是进行时间计算&#xff0c;而是成为架构规范的一部分&#xff0c;因此需要对ATimer进行升级&#xff0c;成为一个基础依赖对象。 内容 1 设计 ATimer的作用更多的是进行即时计算&#xff0c;ATimer2将拓展为基…

关于软件0X00000007B的问题

对于0x0000007B问题相信大家一定都很头疼,编译好的软件在自己电脑上可以正常运行,更换一台电脑或许就无法正常运行.那么我们改怎么处理呢? 情况一:vs版本不一致导致的打不开软件 1方法一Windows日志查看软件运行失败的原因,一般都是dll版本不兼容引起的无法调用,解决方法 “”…

穿越网络边界:深入了解 FRP 内网穿透机制

前言 在当今互联网时代&#xff0c;内网穿透成为了解决内部网络服务对外难以访问的问题的一种重要方式。Fast Reverse Proxy&#xff08;FRP&#xff09;作为一款强大的反向代理工具&#xff0c;为用户提供了一种高效、灵活的内网穿透解决方案。本文将深入介绍 FRP 的原理和使…

java基础学习: 什么是泛型的类型擦除

文章目录 一、什么是泛型2、泛型编译前和编译后对比3、泛型的优点&#xff08;1&#xff09;提高了代码的复用性和可读性&#xff08;2&#xff09;提高了代码的安全性 二、泛型的定义1、泛型类2、泛型接口3、泛型方法 三、泛型通配符1、&#xff1f;和T有什么区别2、通配符的分…

喝汽水问题(c语言)

喝汽水&#xff0c;1瓶汽水1元&#xff0c;2个空瓶可以换一瓶汽水&#xff0c;给20元&#xff0c;可以喝多少汽水&#xff0c;这里用c语言来解释 可以先用列举法来说明&#xff0c;20可以买20个汽水&#xff0c;两个空瓶换一瓶就可以获得10个汽水&#xff0c;同理10个空瓶个可…

IDEA常用插件(本人常用,不全)

文章目录 一、图标提示类插件1、Lombok插件&#xff08;用户配合lombok依赖的工具&#xff09;2、MybatisX插件3、GitToolBox4、VUE.js5、ESLint 二、代码自动生成插件1、EasyCode插件&#xff1a;自动生成代码神器2、GsonFormat 三、常用工具类1、IDE Eval Reset 插件&#xf…

vector函数介绍与实现(迭代器失效)

目录 一、介绍vector 1.vector是什么 2.vector的特点 1.随机访问 2.缓存命中 3.vector的结构 二、vector的函数 1.构造函数&#xff08;创建&#xff09;​编辑 2.Iterator&#xff08;迭代器&#xff09; 3.Capacity&#xff08;容量&#xff09; 三、迭代器失效 …

数据库性能优化的解决方案

目录​​​​​​​ 1、什么是数据库性能优化 1.1 数据库性能优化的概念 1.2 为何需要进行数据库性能优化 1.3 数据库性能优化的好处 2、数据库性能优化的基本原理 2.1 数据库查询优化 2.2 数据库索引优化 2.3 数据库表结构优化 2.4 数据库硬件优化 3、数据库查询优化…

一个好用的服务器控制面板

简介 它是一个免费开源的管理面板工具&#xff0c;可以帮助你集中管理多个服务器和网站。Ajenti 支持 Linux、BSD、Mac OS X和Windows 等多个操作系统&#xff0c;并且可以通过一个直观的 Web 界面来完成各种系统管理任务。 相比于其他管理面板&#xff0c;Ajenti有以下几个优…

go语言数组和切片

1. 数组Array Golang Array和以往认知的数组有很大不同。 1. 数组&#xff1a;是同一种数据类型的固定长度的序列。2. 数组定义&#xff1a;var a [len]int&#xff0c;比如&#xff1a;var a [5]int&#xff0c;数组长度必须是常量&#xff0c;且是类型的组成部分。一旦定义&…

数字主持人有多少种应用方式?

在数字经济时代下&#xff0c;越来越多企业、品牌以数字人进行新闻资讯报道、主持互动、人机交互等多形式&#xff0c;提升企业、品牌的影响力和认知度。 *图片源于网络 如山东广播电视台数字主持人“海蓝”&#xff0c;不仅可以用大会活动现场&#xff0c;用多国语言与主持人、…

从零开始c++精讲:第四篇——模板初阶

文章目录 一、泛型编程二、函数模板2.1函数模板概念2.2函数模板格式2.3函数模板原理2.4函数模板实例化2.5函数模板匹配原则 三、类模板3.1类模板的定义格式3.2类模板的实例化 一、泛型编程 如何实现一个通用的交换函数呢&#xff1f; void Swap(int& left, int& righ…

ios适配虚拟home键

在H5开发过程中遇到一个兼容性问题。iphone手机的虚拟home键会对屏幕底部的内容造成遮挡。要处理此问题&#xff0c;需要清楚安全区域这个概念。 安全区域 根据刘海和虚拟Home键&#xff0c;Apple为其设备提供了屏幕安全区域的视觉规范 竖屏&#xff1a;竖屏的时候&#xff…

基于springboot在线学习平台源码和论文

在Internet高速发展的今天&#xff0c;我们生活的各个领域都涉及到计算机的应用&#xff0c;其中包括学习平台的网络应用&#xff0c;在外国学习平台已经是很普遍的方式&#xff0c;不过国内的管理平台可能还处于起步阶段。学习平台具有学习信息管理功能的选择。学习平台采用ja…

PWN入门Protostar靶场Stack系列

Protostar靶场地址 https://exploit.education/protostar/溢出 源码分析 #include <stdlib.h> #include <unistd.h> #include <stdio.h>int main(int argc, char **argv) {volatile int modified; //定义一个变量char buffer[64]; //给…

C++:优先队列-Priority_queue

目录 1.关于优先队列 2.priority_queue的使用 1.构造方法 2.empty();判空 3.size(); 4.top(); 5.push(val); 6.pop(); 3.优先队列模拟实现 4.用优先队列解决数组中第K个大的元素 1.关于优先队列 在C中&#xff0c;可以使用STL&#xff08;标准模板库&#xff09;中的p…