【c++篇】:初识c++--编程新手的快速入门之道(二)

文章目录

  • 前言
  • 一.引用
    • 1.引用的概念
    • 2.引用的特性
    • 3.引用的使用场景
    • 4.常引用
    • 5.引用和指针的区别
  • 二.内联函数
    • 1.C语言的宏函数
    • 2.内联函数的概念
    • 3.内联函数的特性
  • 三.auto关键字
    • 1.`auto`的定义
    • 2.`auto`的使用规则
    • 3.`auto`不能推导的场景
  • 四.基于范围的for循环
    • 1.范围for的语法
    • 2.范围for的使用条件
  • 五.指针空值nullptr

前言

在上一篇文章中讲解了部分c++入门知识点,这篇文章将继续讲解剩下的知识点

一.引用

1.引用的概念

**引用(&)**不是新创建一个变量,而是为变量取别名。引用时共用一块空间,编译器不会新开辟空间。如图所示,b是a的别名,c是b的别名,它们的空间地址一样

using namespace std;
int main() {int a = 1;int& b = a;int& c = b;cout << &a << endl;cout << &b << endl;cout << &c << endl;return 0;
}

在这里插入图片描述

C语言中用指针对变量进行修改,而c++可以直接用引用进行修改。

using namespace std;
int main() {int a = 1;int& b = a;int& c = b;cout << a << " ";cout << b << " ";cout << c << " ";cout << endl;b++;cout << a << " ";cout << b << " ";cout << c << " ";cout << endl;c++;cout << a << " ";cout << b << " ";cout << c << " ";cout << endl;return 0;
}

在这里插入图片描述

2.引用的特性

  • 引用时必须初始化

    int a=0;
    int &b;   //错误
    int &b=a; //正确
    
  • 一个变量可以有多个引用

    int a=0;
    int &b=a;
    int &c=a;
    
  • 引用一旦引用一个实体,再不能引用其他实体

    int a=0;
    int c=0;
    int &b=a;
    int &b=c;  //错误
    

3.引用的使用场景

  • 做参数

    我们之前用C语言写交换两个数的函数时需要用到指针传参,而c++中可以直接用引用做参数。比如下面的代码中,形参a,b就是实参x,y的别名(也就是引用),形参a,b交换,实参x,y也会交换。引用做参数可以提高函数调用的效率。

    using namespace std;
    //用指针做参数
    void Swap1(int*a,int*b){int t=*a;*a=*b;*b=t;
    }
    //用引用做参数
    void Swap2(int&a,int&b){int t=a;a=b;b=t;
    }
    int main(){int x=10,y=20;Swap1(&x,&y);cout<<x<<" "<<y<<endl;x=10,y=20;Swap2(x,y);cout<<x<<" "<<y<<endl;return 0;
    }
    

    在这里插入图片描述

  • 做返回值

    函数传值返回时,会生成一个临时变量用来拷贝返回值,而引用做返回值时,不用生成临时变量,减少了拷贝,提高了效率

    int& Count(){static int n=0;n++;return n;
    }
    int main(){int ret=Count();return 0;
    }
    

    上面这段代码,返回的n在静态区,所以函数调用结束时,n依然还在。而下面这段代码则是引用做返回值时的错误用例:

    int& Count(){int n=0;n++;return n;
    }
    int main(){int ret=Count();return 0;
    }
    

    不同的是下面的n是局部变量,当函数调用结束时,栈帧销毁,如果没有清理栈帧,ret可能是正确值,如果清理栈帧,ret就会是一个随机值。而如果接受也是引用时,那么ret就一定是随机值。比如:

    int& Count(){int n=0;n++;return n;
    }
    int main(){//ret是n的别名int& ret=Count();return 0;
    }
    

总结:

  • 基本任何场景都可以用引用传参。
  • 谨慎使用引用做返回值,出了函数作用域,对象不在就不能用引用返回,还在就可以用引用返回。

4.常引用

int main(){const int a=0;int& b=a;     //不可以,权限不能放大const int c=0;int d=c;      //可以,c拷贝给d,权限平移,d的改变不影响cint x=0;const int& y=x;//可以,权限缩小,如果x改变,y也会改变,但不能通过y来修改xdouble dd=1.11;int ii=dd;        //可以,借助int临时变量const int& rii=dd;//不可以,临时变量具有常性
}

5.引用和指针的区别

  1. 引用概念上定义一个变量的别名,指针存储一个变量地址
  2. 引用在定义时必须初始化,指针没有要求
  3. 引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
  4. 没有NULL引用,但有NULL指针
  5. 在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节)
  6. 引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
  7. 有多级指针,但是没有多级引用
  8. 访问实体方式不同,指针需要显式解引用,引用编译器自己处理
  9. 引用比指针使用起来相对更安全

二.内联函数

1.C语言的宏函数

我们首先来看下面这段代码:

int Add(int x,int y){return x+y;
}
int main(){for(int i=0;i<10000;i++){cout<<Add(i,i+1)<<endl;}return 0;
}

在调用函数时,每调用一次函数,就要在栈区创建和销毁一次空间,而我们上面这一段代码,频繁地调用函数,就会频繁地建立栈帧,大大降低了效率,为了解决这一情况,C语言用宏函数来替换:

#define Add(x,y) ((x)+(y))

利用宏函数来替换,不需要建立栈帧,大大提高调用效率。但缺点就是写起来较为复杂,容易出错,可读性差并且不能调试。

而在c++中为优化这一点,增加了新的内联函数inline

2.内联函数的概念

inline修饰的函数叫做内联函数,编译时c++编译器会在调用内联函数的地方展开,没用调用函数建立栈帧,提升程序运行的效率。

还是上面的这一段代码:

//在函数类型前加上inline关键字
inline int Add(int x,int y){return x+y;
}
int main(){for(int i=0;i<10000;i++){cout<<Add(i,i+1)<<endl;}return 0;
}

3.内联函数的特性

  • inline是一种以空间换时间的做法,编译器将函数当成内联函数处理时,在编译阶段,会展开整个函数体来替换函数调用。少了调用开销,大大提高程序运行效率。
  • 内联函数只适合函数规模较小的(也就是函数不是很长),不是递归且频繁调用的函数用inline修饰。比如函数fun()有50行代码,如果fun()不是内联函数时,10000个位置调用函数,合计共10000+50行,如果fun()是内联函数,合计共10000*50行。这就会使目标文件变大。
  • 内联函数不建议声明和定义分离,分离会导致链接错误,因为inline被展开,就没有函数地址,链接找不到。
//fun.h
#include<iostream>
using namespace std;
inline void fun(int i);//fun.cpp
#include"fun.h"void fun(int i) {cout << i << endl;
}//test.cpp
#include"fun.h"
int main() {int x = 10;fun(10);return 0;
}

在这里插入图片描述

最好声明和定义放在一起:

//fun.h
#include<iostream>
using namespace std;
void fun(int i) {cout << i << endl;
}//test.cpp
#include"fun.h"
int main() {int x = 10;fun(10);return 0;
}

三.auto关键字

1.auto的定义

在C语言的时候我们知道typedef关键字可以用来给一些类型取别名,对于一些较长的类型名时使用起来会很方便,比如,std::map<std::string,std::string>::iterator 是一个类型,但是该类型太长了,特别容易写错,于是可以通过typedef给类型取别名

typedef std::map<std::string, std::string> Map;

使用typedef确实可以简便代码,但是也会遇到一些特殊情况:

typedef char*pstring
int main(){const pstring p1;const pstring *p2;return 0;
}

在这里插入图片描述

c++为了解决这一情况将auto赋予了新的含义。

c++11中,auto不再是一个存储类型指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。

int TestAuto()
{return 10;
}
int main()
{int a = 10;auto b = a;auto c = 'a';auto d = TestAuto();cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;return 0;
}

在这里插入图片描述

2.auto的使用规则

  • 使用auto时,一定要初始化,在编译阶段编译器需要根据初始化表达式来推到实际类型,然后将auto替换为变量的实际类型。

  • auto声明指针类型时,autoauto*没有区别,但是auto声明引用类型时必须加上&

    int main() {int a = 10;auto b = &a;auto* c = &a;auto& d = a;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;*b = 20;*c = 30;d = 40;return 0;
    }
    

    在这里插入图片描述

  • 在同一行定义多个变量时,这些变量必须是相同的类型,否则编译器会报错。

    void Testauto(){auto a=1,b=2;auto c=1,d=1.1;
    }
    

    在这里插入图片描述

3.auto不能推导的场景

  • auto不能作为函数的参数

    void TestAuto(auto a){cout<<a<<endl;
    }
    

    在这里插入图片描述

  • **auto不能直接用来声明数组**

    void TestAuto(){int a[]={1,2,3};auto b[]={4,5,6};
    }
    

    在这里插入图片描述

四.基于范围的for循环

1.范围for的语法

在C语言或者c++98中,我们如果要遍历一个数组,通常会按照以下方式进行

using namespace std;
int main() {int array[] = { 1,2,3,4,5,6 };for (int i = 0; i < sizeof(array) / sizeof(int); i++) {array[i] *= 2;}for (int i = 0; i < sizeof(array) / sizeof(int); i++) {cout << array[i] << " ";}cout << endl;return 0;
}

而在之后的c++11更新中,引入了基于范围的for循环,对于一个有范围的集合,在遍历时可以自动识别循环范围。for循环后的括号由:分为两部分,第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。

using namespace std;
int main() {int array[] = { 1,2,3,4,5,6 };for (auto& e : array) {//每一项都乘以2e *= 2;}for (auto& e : array) {cout << e << " ";}cout << endl;return 0;
}

在这里插入图片描述

和普通的for循环一样,范围for循环也可以用continue结束本次循环,也可以用break直接结束整个循环。

2.范围for的使用条件

for循环迭代的范围必须是确定的。

对于一个数组,就是数组第一个元素和最后一个元素的范围;在之后学到类时,还有关于类的范围。

下面这一段代码就是错误的,因为for的范围不确定,数组名作为参数传过来,我们只知道数组第一个元素,而不确定最后一个。

using namespace std;
void TestFor(int array[]){for(auto e:array){cout<<e<<endl;}
}
int main(){int array[]={1,2,3,4,5,6};TestFor(array);return 0;
}

在这里插入图片描述

五.指针空值nullptr

在C语言的时候我们知道NULL表示空指针,但实际上NULL是一个宏,NULL被定义为字面常量0或者无类型指针(void*)的常量。在C语言的头文件(stddef.h)中可以看到以下代码:

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

在使用NULL不可避免的会遇到一些特殊情况,比如:

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

在这里插入图片描述

因为NULL被定义为0,因此程序默认调用了第一个函数void f(int),如果要使NULL按照指针方式使用,必须1强制转换为`((void*)0)。

为了解决这个麻烦,在c++11时,引入了新关键字nullptr表示指针空值,在使用时,不需要包含头文件

在上面的代码中加上这句,就会得到以下结果:

f(nullptr);

在这里插入图片描述

在c++11中,sizeof(nulllptr)sizeof((void*)0)所占的字节数相同
以上就是关于c++入门部分的讲解,如果哪里有错的话,可以在评论区指正,也欢迎大家一起讨论学习,如果对你的学习有帮助的话,点点赞关注支持一下吧!!!
在这里插入图片描述

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

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

相关文章

时间序列预测(七)——梯度消失(Vanishing Gradient)与梯度爆炸(Exploding Gradient)

目录 一、定义 二、产生原因 三、解决方法&#xff1a; 梯度消失与梯度爆炸是深度学习中常见的训练问题&#xff0c;它们主要发生在神经网络的反向传播过程中&#xff0c;使得模型难以有效学习。 一、定义 1、梯度消失&#xff08;Vanishing Gradient&#xff09;&#xf…

PCL 点云配准-改进的RANSAC算法(粗配准)

目录 一、概述 1.1原理 1.2实现步骤 1.3应用场景 二、代码实现 2.1关键函数 2.1.1 计算FPFH特征 2.1.2 RANSAC配准 2.1.3 可视化点云 2.2完整代码 三、实现效果 PCL点云算法汇总及实战案例汇总的目录地址链接&#xff1a; PCL点云算法与项目实战案例汇总&#xff0…

FlinkCDC 实现 MySQL 数据变更实时同步

文章目录 1、基本介绍2、代码实战2.1、数据源准备2.2、代码实战2.3、数据格式 1、基本介绍 Flink CDC 是 Apache Flink 提供的一个功能强大的组件&#xff0c;用于实时捕获和处理数据库中的数据变更。可以实时地从各种数据库&#xff08;如MySQL、PostgreSQL、Oracle、MongoDB…

【图论】(一)图论理论基础与岛屿问题

图论理论基础与岛屿问题 图论理论基础深度搜索&#xff08;dfs&#xff09;广度搜索&#xff08;bfs&#xff09;岛屿问题概述 岛屿数量岛屿数量-深搜版岛屿数量-广搜版 岛屿的最大面积孤岛的总面积沉没孤岛建造最大人工岛水流问题岛屿的周长 图论理论基础 这里仅对图论相关核…

java学习--集合(大写五.5)

5.collection子接口&#xff1a;Set 5.1Set及其实现类特点 java.util.Collection:存储一个一个的数据 子接口&#xff1a;Set:存储无序的、不可重复的数据(高中学习的集合) 1&#xff09;HashsSet主要实现类 底层使用的是HashMap&#xff0c;即使用数组单向链表红黑树结构进行…

netron安装(windows linux)

目录 netron简介 不同操作系统的安装方式 linux windows mac系统 netron简介 netron可视化工具&#xff0c;是一个可以清晰的看到神经网络模型的每一层的输入输出&#xff0c;网络总体的架构&#xff0c;而且支持各种不同网络框架&#xff0c;简单好用。 效果如下所示 不…

【视频笔记】408新增知识点信号——里昂视频

文章目录 **2.信号****3.信号的实现**4.信号的处理**①忽略信号****②执行信号的默认操作****③捕获井处理信号**几个Linux支持的典型信号&#xff1a; **5.信号的产生**① **通过终端按键(键盘)产生信号**例如&#xff0c;CtrlC发送2号信号SIGINT、Ctrl\发送3号信号SIGQUIT② …

爬虫逆向-js进阶

1.作用域和闭包 //作用域 // var a 3 // // function test(a){ // var a 1; // console.log(函数内部,a) // } // test(2) // // console.log(a)//闭包 // function jiami(){ // function encrypt(){ // console.log(在这里进行加密了) // } // p…

五个必备的高清无水印视频素材库推荐

做抖音、短视频创作的朋友都知道&#xff0c;优质的素材往往决定了作品能否获得更多关注。如果你还不知道在哪里下载高清无水印的视频素材&#xff0c;不用担心&#xff01;今天为你推荐5个高品质的视频素材库&#xff0c;助你轻松创作出爆款视频。 蛙学网 是国内领先的视频素材…

Mysql常用sql语句与刷题知识点

目录 1. 常用sql2. 刷题知识点 1. 常用sql #查询MySQL中所有的数据库 SHOW DATABASES; #查询当前正在使用的数据库 SELECT DATABASE();#普通创建&#xff08;创建已经存在的数据库会报错&#xff09; CREATE DATABASE 数据库名称; #创建并判断&#xff08;该数据库不存在才创建…

2.html编辑器介绍

html编辑器介绍 HTML 编辑器推荐 理论上我们可以使用记事本进行html编码和开发&#xff0c;但是在实际开发html页面的时候&#xff0c;使用一些专业的开发工具可以使我们更加快速和高效的进行开发&#xff0c;下面介绍几种开发工具&#xff1a; VS Code&#xff1a;https://…

006_django基于Python的二手房源信息爬取与分析2024_l77153d4

目录 系统展示 开发背景 代码实现 项目案例 获取源码 博主介绍&#xff1a;CodeMentor毕业设计领航者、全网关注者30W群落&#xff0c;InfoQ特邀专栏作家、技术博客领航者、InfoQ新星培育计划导师、Web开发领域杰出贡献者&#xff0c;博客领航之星、开发者头条/腾讯云/AW…

【uniapp】实现触底加载数据

前言&#xff1a;实现界面触底数据加载。后端接口得支持翻页传参&#xff08;本案例使用django&#xff09; 1、后端接口 1.1 封装翻页公共方法standardPagination.py # -*- coding: utf-8 -*- # Time : 2024/10/15 13:15 # Author : super # File : standardPaginat…

全托自闭症教育,关注孩子每个细节

原文文章&#xff1a;http://www.zibizhengwang.com/page37.html 自闭症&#xff0c;这一复杂的神经发育障碍&#xff0c;影响着无数孩子的成长与未来。然而&#xff0c;在广州&#xff0c;有一座特别的灯塔——星贝育园自闭症儿童寄宿制学校&#xff0c;它不仅照亮了自闭症儿…

SpringBoot使用esayExcel根据模板导出excel

1、依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>3.1.3</version></dependency> 2、模板 3、实体类 package com.skybird.iot.addons.productionManagement.qualityTesting…

配置MAC地址安全

概述 MAC地址安全配置是确保网络设备和通信安全的重要措施&#xff0c;通过限制、监控和管理设备的物理地址来防止未授权访问和潜在的网络威胁。以下是对MAC地址安全的概述&#xff1a; 基本概念 定义&#xff1a;MAC地址&#xff08;Media Access Control Address&#xff09…

Jenkins整合Docker实现CICD自动化部署(若依项目)

前期准备 提前准备好jenkins环境 并且jenkins能使用docker命令&#xff0c;并且已经配置好了jdk、node、maven环境&#xff0c;我之前写了安装jenkins的博客&#xff0c;里面讲得比较详细&#xff0c;推荐用我这种方式安装 docker安装jenkins&#xff0c;并配置jdk、node和m…

CEP 复杂事件处理引擎进阶:股票中高频 CTA 策略实现与并行回测

在 CEP 复杂事件处理引擎入门&#xff1a;初级高频量价因子策略的实现 中&#xff0c;我们详细介绍了 CEP 引擎和它的一些关键概念&#xff0c;如复杂事件和事件监听器等。随后又通过两个初级的 CEP 引擎使用案例介绍了创建并运行一个最简单结构的 CEP 引擎所需的步骤和模块&am…

骨传导耳机哪个牌子最好?五大高口碑骨传导耳机揭秘!

骨传导耳机作为一种创新的音频设备&#xff0c;通过振动头骨直接将声音传递到内耳&#xff0c;不仅为用户提供了全新的听音体验&#xff0c;还能在保持环境音的情况下享受音乐&#xff0c;特别适合户外运动和日常通勤。然而&#xff0c;在众多品牌和型号中选择最适合自己的骨传…

人工智能正在扼杀云计算的可持续性

可持续性曾是公共云计算中备受推崇的优势。企业和云提供商大肆宣扬他们的绿色计划&#xff0c;推广采用可再生能源的数据中心&#xff0c;以减少碳足迹。 近几个月来&#xff0c;这个话题已悄然淡出人们的视线。罪魁祸首是什么&#xff1f;对人工智能功能的无限需求正在推动云…