C++入门知识【超详解】
目录
- 1.认识C++
- hello world
- C++关键字
- 2.命名空间
- 3.std标准库
- 4.输入输出
- 5.缺省参数
- 6.函数重载
- 7.引用
- 7.1引用的概念
- 7.2引用的场景
- 1.作参数
- 2.作返回值
- 7.3引用的注意点
- 7.4指针和引用的区别
- 8.auto关键字
- 9.基于范围的for循环
- 10.内联函数
- 10.1概念
- 10.2特征
- 11. C++98中的指针空值
1.认识C++
hello world
#include<iostream>
int main() {std::cout << "hello world" << std::endl;return 0;
}
C++关键字
C语言32个关键字,而C++总计63个关键字
2.命名空间
对于上述问题,即是C语言常见的命名冲突问题,C++中用命名空间来解决
命名空间是域
变量查找规则:先在局部找,再全局找
在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存 在于全局作用域中,可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化, 以避免命名冲突或名字污染 , namespace关键字的出现就是针对这种问题的。
定义命名空间,需要使用到namespace关键字,后面跟命名空间的名字,然后接一对{}即可, {} 中即为命名空间的成员
默认查找规则:先在局部找,再全局找
#include<stdio.h>
#include<stdlib.h>
namespace A {int rand = 10;int x = 1;
}int main() {printf("%p\n", rand);printf("%d\n", A::rand);printf("%d\n", A::x);return 0;
}
namespace域不会影响生命周期,相当于全局变量,放在静态域中;在预处理完后,头文件展开,rand未找到局部变量的定义,因此在头文件声明展开后的全局找到了它;而我们用到的**::即为作用域限定符**,相当于在查找变量时,在指定空间查找
变量定义在全局和定义在命名空间的区别?防止冲突
1.命名空间中可以定义变量/函数/类型,可以嵌套
namespace N1
{int a;int b;int Add(int left, int right){return left + right;}namespace N2{int c;int d;int Sub(int left, int right){return left - right;}}
}
对于嵌套的命名空间,访问时应:
N1::a=1;
N1::N2::c=2;
2.同一个工程中允许存在多个相同名称的命名空间 ,编译器最后会自动合并到同一个命名空间中
3.std标准库
std是C++标准库的命名空间,如何展开std使用更合理呢?
1.在日常练习中,建议直接using namespace std即可,这样就很方便
2.using namespace std展开,标准库就全部暴露出来了,如果我们定义跟库重名的类型/对象/函数,就存在冲突问题,因此我们不展开std,而是使用时加上std作用域限定符
3.指定展开:常用的展开,自己定义的时候避免跟常用重名即可
总结:命名空间std尽量避免全部展开,防止命名冲突
4.输入输出
1.使用cout标准输出对象(控制台:Console)和cin标准输入对象**(键盘)时,必须包含< iostream>头文件 以及按命名空间使用方法使用std**
2.cout和cin是全局的流对象, endl是特殊的C++符号,表示换行输出,他们都包含在包含< iostream >头文件中。
3.**<<**是流插入运算符, **>>**是流提取运算符。
4.使用C++输入输出更方便,不需要像printf/scanf输入输出时那样,需要手动控制格式;C++的输入输出可以自动识别变量类型
#include <iostream>
using namespace std;int main()
{int a;double b;char c;// 可以自动识别变量的类型cin >> a;cin >> b >> c;cout << a << endl;cout << b << " " << c << endl;return 0;
}
C++的输入输出虽然方便了,却不好精确控制输入输出格式(例如保留小数点后几位),但是C++兼容C语言,因此在处理这些问题时可以配合着C语言使用;对于值、字符串、空格等多种混输出时,printf同样的比cout更方便
5.缺省参数
using namespace std;
void Func(int a = 10, int b = 20, int c = 30) {cout << "a= " << a << endl;cout << "b= " << b << endl;cout << "c= " << c << endl;
}
1.全缺省调用
int main() {Func();
}
2.半缺省调用(从左向右依次传)
int main() {Func(1);
}
缺省只能从右往左连续缺省
此时b和c缺省:
void Func(int a, int b = 20, int c = 30) {cout << "a= " << a << endl;cout << "b= " << b << endl;cout << "c= " << c << endl;
}
例如缺省的使用:
namespace S {typedef struct Stack{int* a;int top;int capacity;}ST;void StackInit(ST* ps, int defaultCapacity = 4) {ps->a = (int*)malloc(sizeof(int)*defaultCapacity);assert(ps->a);ps->top = 0;ps->capacity = defaultCapacity;}
}int main() {//不知道要插入多少数据S::ST st1;S::StackInit(&st1);//知道要插入100个数据S::ST st2;S::StackInit(&st2, 100);
}
注意:缺省参数不能在函数声明和定义中同时出现,规定只能在声明时(.h)去定义缺省参数
//a.h
void Func(int a = 10);// a.cpp
void Func(int a = 20){}
// 注意:如果声明与定义位置同时出现,恰巧两个位置提供的值不同,那编译器就无法确定到底该用那个缺省值。
6.函数重载
函数重载是函数的一种特殊情况, C++允许在同一作用域中声明几个功能类似的同名函数,这些同名函数的形参列表(①参数个数或②类型或③类型顺序)不同,常用来处理实现功能类似数据类型不同的问题。
int add(int x, int y) {return x + y;
}double add(double x, double y) {return x + y;
}int main() {cout << add(1, 2) << endl;cout << add(1.2, 1.5) << endl;return 0;
}
①C++能自动识别参数类型,本质也是函数重载支持的
②函数重载调用时应该明确调用哪个函数,重载+缺省调用会报错:二义性
③为什么C语言不支持重载,C++是怎么支持重载呢?——函数名修饰(name Mangling)
④返回值不同不能构成重载!原因是调用时的二义性,无法区分调用时不指定返回值类型
7.引用
7.1引用的概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空 间,它和它引用的变量共用同一块内存空间
类型& 引用变量名(对象名) = 引用实体;
引用的存在,就能间接替代C语言当中的指针的部分功能了(无法完全替代指针)
例如我们常用的交换函数:
void Swap(int& m, int& n) {int tmp = m;m = n;n = tmp;
}int main() {int a = 10;int b = 20;Swap(a, b);std::cout << "a=" << a << " " << "b=" << " " << b << std::endl;
}
同理的,我们不仅能给一般变量取别名,也可以给指针变量取别名,因此可以代替二级指针
*&pa=**p; //相当于我们用pa来代替*p,那么对于**p来说即为*pa
注意:
①引用在定义时必须初始化
② 一个变量可以有多个引用
③引用一旦引用一个实体,再不能引用其他实体(引用的指向不可改变)
7.2引用的场景
1.作参数
一般用作输出型参数,C++中可用引用来替代指针;减少拷贝提高效率
void Swap1(int& left, int& right)
{int temp = left;left = right;right = temp;
}
2.作返回值
①引用返回
int& Count()
{ //只有静态才行:减少了一次拷贝static int n = 0;n++;// ...return n;
}
②传值返回
int Count()
{static int n = 0;n++;// ...return n;
}
那么引用返回和传值返回有什么区别呢?
在传值返回时,会将返回值拷贝到一个临时变量(寄存器或上一层栈帧中);而利用引用返回时,也可以理解为存在一个临时变量,它的类型仍是引用类型,相当于返回了一个返回值n的别名,但是由于返回时原返回值n的栈已经销毁了,而返回的它的别名仍然指向的这一片空间;
内存空间销毁意味着什么?
①空间还在吗?在,只是使用权不是我们的,我们存的数据不被保护
②我们还能访问吗?能,只是我们读写的数据都是不确定的
为什么会出现100?main函数调用了Func函数,恰好和调用Count位于同一块空间,ret是这块空间的别名,因此它的值变成了100;本质即是非法空间的访问!这也说明了空间是可以重复使用的
【结论】:出了函数作用域,返回变量不存在了,不能用引用返回,因为引用返回的结果是未定义的;正确使用引用返回值是对于静态声明的变量,返回变量还存在,这种情况就可以使用,使用它的意义即是在返回值传递时不用再开辟临时拷贝变量,提高效率
通过设计一个简单的程序,可以发现确实能提高效率:
7.3引用的注意点
1.指针和引用赋值中,权限可以缩小,但是不能放大
这里b是只读的,a是可读可写的
对于权限缩小是允许的:
需要注意的是,权限的放大缩小只对于指针或引用来说的,正常的赋值是无影响的
int a=1;
const int b=0;
a=b; //right
这里是将b的值传递给a,a值的改变并不会影响b,其本质即是它们不是指针/引用变量,值的改变对互相无影响,这也是指针/引用赋值中有权限放大缩小的概念;
那么对于以后,一般用引用参数都是用const引用,但是如果你要修改这个参数,不用const就行了
2.引用不能使用缺省参数,因为缺省参数一般是常量,但是加上const即可使用
void func(const int& N=10){ //right}
3.引用时涉及强制类型转换需要用到常引用
强制类型转换会产生临时变量:例如我们将double类型的a转换为int类型,我们输出10,但是我们修改的不是并不是a,输出的是产生的临时变量
临时变量具有常性,无法被修改,因此在引用时也要定义常引用
int& ra1 = a; //wrong
const int& ra2 = a; //right
这里的ra2不是a的别名了,而是这个临时变量的别名,打印ra2的值即可验证:
4.传值返回不能用引用变量接收
同理,传值返回涉及到临时变量的拷贝,临时变量具有常性,因此只能用const引用接收
5.语法层面上,ra是a的别名,不开空间;底层实现上,引用是使用指针实现的
7.4指针和引用的区别
①引用概念上定义一个变量的别名,指针存储一个变量地址。
②引用在定义时必须初始化,指针没有要求
③引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何 一个同类型实体
④没有NULL引用,但有NULL指针
⑤在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32 位平台下占4个字节,64位平台下占8个字节)
⑥引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小
⑦有多级指针,没有多级引用
⑧访问实体方式不同, 指针需要显式解引用,引用编译器自己处理
⑨引用比指针使用起来相对更安全
8.auto关键字
引入:随着程序越来越复杂,程序中用到的类型也越来越复杂,经常体现在
①类型难于拼写
②含义不明确导致容易出错
因此有了auto:一个类型指示符来指示编译器, auto声明的变量类型由编译器在编译时期推导而得
int a=10;
auto b=a;
定义变量时,auto声明的变量b,根据a的类型推导b的类型
9.基于范围的for循环
范围for循环的作用是方便遍历数组
int arr[]={1,2,3,4,5};
//依次取arr中数据赋值给e,自动判断结束,自动迭代
for(auto e:arr)
{cout<<e<<" ";
}
cout<<endl;
遍历结果为:
10.内联函数
10.1概念
以inline修饰的函数叫做内联函数, 编译时C++编译器会在调用内联函数的地方展开,没有函数调用建立栈帧的开销,内联函数提升程序运行的效率
例如对于冒泡排序、交换排序等,我们涉及到Swap交换函数,当数据量很大的时候就要多次调用Swap(频繁调用的小函数),即多次调用栈帧;C语言中通过宏函数可以避免栈帧消耗(预处理替换,优化)
而对于C++来说,可以通过inline函数(内联函数)来解决
>为什么不继续使用C语言的宏?①不能调试②没有类型安全检查③容易出错
>例如ADD的宏函数
#define ADD(int x,int y) ((x)+(y))
10.2特征
1.inline是一种以空间换时间的做法,如果编译器将函数当成内联函数处理,在编译阶段,会用函数体替换函数调用,缺陷:可能会使目标文件变大,优势:少了调用开销,提高程序运行效率。
2.inline对于编译器而言只是一个建议,不同编译器关于inline实现机制可能不同,一般建议:将函数规模较小(即函数不是很长,具体没有准确的说法,取决于编译器内部实现),不是递归、且频繁调用的函数采用inline修饰,否则编译器会忽略inline特性
是否展开取决于编译器,函数过长强行展开会引起代码膨胀
代码量决定了可执行程序的大小,在开发中,编译出的程序即可以被理解为安装包
3.在debug模式下,内联不会默认展开,通过修改设置可以展开
>使用时直接在函数前加关键字inline即可
inline ADD(int a,int b){return a+b;
}
4.inline不在声明和定义分离,在.h文件中声明后,预处理后会在.cpp文件展开;inline被展开,没有函数地址,链接(地址)就会找不到
11. C++98中的指针空值
在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针;如果指针没有合法的指向,我们基本都是按照如下 方式对其进行初始化:
int* p1 = NULL;
int* p2 = 0;
NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL
#else
#define NULL
#endif
#endif
可以看到, NULL可能被定义为字面常量0,或者被定义为无类型指针(void)的常量
由于语言具有向前兼容的特点,因此在C++98中的指针空值问题延续到了现在
解决方案为:关键字nullptr,表示指针空值;因此在以后,我们均使用nullptr来表示空指针
return a+b;
}
4.inline不在声明和定义分离,在.h文件中声明后,预处理后会在.cpp文件展开;inline被展开,没有函数地址,链接(地址)就会找不到## 11. C++98中的指针空值> 在良好的C/C++编程习惯中,声明一个变量时最好给该变量一个合适的初始值,否则可能会出现不可预料的错误,比如未初始化的指针;如果指针没有合法的指向,我们基本都是按照如下 方式对其进行初始化:```cpp
int* p1 = NULL;
int* p2 = 0;
NULL实际是一个宏,在传统的C头文件(stddef.h)中,可以看到如下代码:
#ifndef NULL
#ifdef __cplusplus
#define NULL
#else
#define NULL
#endif
#endif
可以看到, NULL可能被定义为字面常量0,或者被定义为无类型指针(void)的常量
由于语言具有向前兼容的特点,因此在C++98中的指针空值问题延续到了现在
解决方案为:关键字nullptr,表示指针空值;因此在以后,我们均使用nullptr来表示空指针
相关文章:

C++入门知识【超详解】
目录1.认识Chello worldC关键字2.命名空间3.std标准库4.输入输出5.缺省参数6.函数重载7.引用7.1引用的概念7.2引用的场景1.作参数2.作返回值7.3引用的注意点7.4指针和引用的区别8.auto关键字9.基于范围的for循环10.内联函数10.1概念10.2特征11. C98中的指针空值1.认识C hello …...

零基础、非计算机系学Python该如何上手?
首先我觉得要放平心态,不用过多去纠结是不是专业出身这回事。 想学那就认真去学,我们最终目标是掌握Python这门技能。 非计算机专业同时零基础,想自学Python该如何上手?分享我自学Python的几点建议吧。 1、重视基础 Python是一…...
关于 vue3 模板引用
文章目录前言1.访问模板引用2.v-for中的模板引用3.组件上的ref前言 如果我们需要直接访问组件中的底层DOM元素,可使用vue提供特殊的ref属性来访问 1.访问模板引用 在视图元素中采用ref属性来设置需要访问的DOM元素 a. 该ref属性可采用字符值的执行设置 b. 该ref属…...

Redis | 安装Redis和启动Redis服务
目录 一、Redis简介 1.1 简介 二、Redis安装 2.1 Windows安装Redis 2.2 Linux安装Redis 三、Redis服务启动和停止 3.1 Windows启动Redis服务 3.2 Linux启动Redis服务 四、Redis设置密码远程连接 4.1 为Redis登陆设置密码 4.2 设置Redis允许远程连接 五、Redis常…...

博客要考虑的最佳WordPress主题
有太多的选择会瘫痪你做决定的能力。有太多的WordPress主题,但仅仅只需要一个并且它是要合适的。我们建立了数十个 WordPress 博客并安装了数百个主题。根据我们所有的经验,我们发现Newspaper是大多数用户的最佳WordPress博客主题。这个自适应、强大的主…...

C 学习笔记 —— 函数指针
函数指针 上面的第二个char (* f) (int);写法就是函数指针的声明; 首先,什么是函数指针?假设有一个指向 int类型变量的指针,该指针储存着这个int类型变量储存在内存位置的地址。 同样,函数也有地址,因为函…...

FastDDS-3. DDS层
3. DDS层 eProsima Fast DDS公开了两个不同的API,以在不同级别与通信服务交互。主要API是数据分发服务(DDS)数据中心发布订阅(DCPS)平台独立模型(PIM)API,简称DDS DCPS PIM…...

9.2 IGMPv2
实验目的 (1) 熟悉IGMPv2的应用场景 (2) 掌握IGMPv2的配置方法 实验拓扑 实验拓扑如图9-17所示: 图9-17:IGMPv2 实验步骤 配置IP地址(请参考上一个实验)运行IGPÿ…...

巨头混战,抢着“兜底”自动驾驶安全
诚然,中国汽车行业的发展绝对不会拘泥于电动化,必定会在电动化的基础上,迎接下半场的快速智能化。 2021年6月,长城汽车线控底盘全球首次发布。 彼时,长城汽车技术副总裁宋东先宣布,整合了线控转向、线控制…...
RightCapital 第一轮面试题
现在我们就马上开始吧! 答案在文末 JavaScript 是一门单线程的静态类型语言(单选题) 正确 错误 在 JavaScript 中下面哪种类型的值是不可变的(immutable)(单选题) Object Symbol Array Date …...

Python曲线肘部点检测-膝部点自动检测
文章目录一. 术语解释二. 拐点检测肘部法则是经常使用的法则。很多时候,可以凭人工经验去找最优拐点,但有时需要自动寻找拐点。最近解决了一下这个问题,希望对各位有用。一. 术语解释 **肘形曲线(elbow curve)**类似人胳膊状的曲线ÿ…...

【算法题】最大矩形面积,单调栈解法
力扣:84. 柱状图中最大的矩形 给定 n 个非负整数,用来表示柱状图中各个柱子的高度。每个柱子彼此相邻,且宽度为 1 。 求在该柱状图中,能够勾勒出来的矩形的最大面积。 题意很简单,翻译一下就是:求该图中…...

活动策划|深度分析年货节活动该如何策划!
四月初,不平凡的初春开始恢复往日的平静。对于新零售行业,疫情的缓解也逐渐平稳生态链的运转。2020年新零售的格局在洗礼后,业务的聚焦点也从前端促销转移到后端履约的体验闭环,同时很大程度的推进企业在危机公关下的应对。618大促…...

Idea启动遇到 Web server failed to start. Port 8080 was already in use. 报错
Idea启动遇到问题-记录 报错英文提示: APPLICATION FAILED TO START Description: Web server failed to start. Port 8080 was already in use. Action: Identify and stop the process that’s listening on port 8080 or configure this application to liste…...
Python3中zip()函数知识点总结
1.引言 在本文中,我将带领大家深入了解Python中的zip()函数,使用它可以提升大家的工作效率。 闲话少说,我们直接开始吧! 2. 基础知识 首先,我们来介绍一些基础知识点: Python中的某些数据类型是不可变的…...

过滤器,监听器,拦截器的原理与在Servlet和Spring的应用
在Java Web的开发中,最原始和初期的学习都是从Servlet开始的,Servlet是Java最为耀眼的技术,也是Java EE的技术变革。目前大火主流的框架spring boot也的spring mvc部分也是基于拓展servlet完成的。回到之前的文章spring 实现了对servlet的封装…...
minio spring boot 秒传、分片上传、断点续传文件实现
此处后端使用的是前期封装的自定义starter,具体链接可参考:minio对象存储spring boot starter封装组件 这里主要针对前期封装的组件,做一个简单的应用,前端直传可查看之前的文章 秒传 秒传的逻辑比较简单,在前传上传…...

MTK平台使用Omnipeek分析空口协议讲解
讲解这个之前,我们先来了解下beacon/robe Request/Probe Response 三种帧 beacon帧 信标帧,由AP以一定的时间间隔周期性发出,以此来告诉外界自己无线网络的存在。 Beacon帧作为802.11中一个周期性的帧,Beacon周期调高,对应睡眠周期拉长,故节能(即越来休息100ms再起来…...

string和自动推断类型
欢迎来观看温柔了岁月.c的博客目前设有C学习专栏C语言项目专栏数据结构与算法专栏目前主要更新C学习专栏,C语言项目专栏不定时更新待C专栏完毕,会陆续更新C项目专栏和数据结构与算法专栏一周主要三更,星期三,星期五,星…...

【软件测试】从功能到自动化测试,测试人的进阶之路细节,这些必不可少......
目录:导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜)前言 测试流程࿰…...

Spark 之 入门讲解详细版(1)
1、简介 1.1 Spark简介 Spark是加州大学伯克利分校AMP实验室(Algorithms, Machines, and People Lab)开发通用内存并行计算框架。Spark在2013年6月进入Apache成为孵化项目,8个月后成为Apache顶级项目,速度之快足见过人之处&…...

Debian系统简介
目录 Debian系统介绍 Debian版本介绍 Debian软件源介绍 软件包管理工具dpkg dpkg核心指令详解 安装软件包 卸载软件包 查询软件包状态 验证软件包完整性 手动处理依赖关系 dpkg vs apt Debian系统介绍 Debian 和 Ubuntu 都是基于 Debian内核 的 Linux 发行版ÿ…...

376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
全面解析各类VPN技术:GRE、IPsec、L2TP、SSL与MPLS VPN对比
目录 引言 VPN技术概述 GRE VPN 3.1 GRE封装结构 3.2 GRE的应用场景 GRE over IPsec 4.1 GRE over IPsec封装结构 4.2 为什么使用GRE over IPsec? IPsec VPN 5.1 IPsec传输模式(Transport Mode) 5.2 IPsec隧道模式(Tunne…...
.Net Framework 4/C# 关键字(非常用,持续更新...)
一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
Java毕业设计:WML信息查询与后端信息发布系统开发
JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发,实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构,服务器端使用Java Servlet处理请求,数据库采用MySQL存储信息࿰…...

【Redis】笔记|第8节|大厂高并发缓存架构实战与优化
缓存架构 代码结构 代码详情 功能点: 多级缓存,先查本地缓存,再查Redis,最后才查数据库热点数据重建逻辑使用分布式锁,二次查询更新缓存采用读写锁提升性能采用Redis的发布订阅机制通知所有实例更新本地缓存适用读多…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...