learncpp-1 C++基础
1 C++基础
1.1 语句和程序结构
- 语句是一条让计算机执行某个动作的指令,是C++语言中最小的
独立计算单元
在高级语言(例如C++)中,一条语句可能编译成多条机器指令
- 大多数语句以
;结尾
声明语句
跳转
表达式语句
复合语句
选择语句(条件语句)
迭代语句(循环语句)
try代码块
- 函数是顺序执行的语句的集合
- 每个C++程序都
必须有一个main函数。当程序运行时,main函数中的语句按顺序执行 - 在编程中,函数/对象/类型/模板的名字称为
标识符 - 编译器负责检查代码是否符合C++语言的基本语法,如果不符合就会报语法错误
1.2 注释
- 注释会被编译器忽略
- 在库、程序或函数级别,使用注释来描述这些代码要实现的功能(
what) - 在库、程序或函数中,使用注释来描述如何实现(
how) - 在语句级别,使用注释来描述原因(
why)
1.3 对象和变量介绍
程序就是指令的集合,这些指令会操纵数据以产生需要的结果,数据是任何可以由计算机移动、处理或存储的信息。- 数据在计算机中是以二进制形式存储的
- 当运行程序时,操作系统会将程序加载到RAM中。任何硬编码到程序本身的数据(例如"hello,world"等文本)也会在这时候被加载
操作系统还会保留一些额外的RAM,供程序在运行时使用。此内存的常见用途是存储用户的输入/存储文件或网络中读取的数据/存储程序运行时计算得到的值,以便后续使用
可以将RAM看作一系列编号的方格,可用于在程序运行时存储数据
- 一个对象是一块可以存储值的内存区域
可以使用对象来存储和获取值,不用知道这些对象实际存放在内存中的哪个位置
- 可以用一个标识符来命名一个对象,
带有名字的对象称为变量 实例化代表对象将被创建并分配一个内存地址,变量在使用之前必须被实例化- 在C++中,
变量的类型在编译期就确定了,并且不能被改变
1.4 变量赋值和初始化
- 使用=进行变量赋值的方式叫做拷贝赋值:将=右边的值拷贝到=左边的变量中
- 不同形式的初始化
int a; // 默认初始化
int b = 5; // 拷贝初始化
int c(6); // 直接初始化
// 列表初始化方法(c++11,更推荐)
int d{7}; // 直接列表初始化
int e = {8}; // 拷贝列表初始化
int f{}; // 值初始化
- 在大多数情况下,默认初始化不执行任何初始化,因此变量具有不确定的值
- 对于复杂类型来说,拷贝初始化的效率较低(c++17中修复了这些问题)
- 当值被隐式地复制或转换时,也会使用拷贝初始化。例如通过值将参数传递给函数、通过值从函数返回、通过值捕获异常
- 直接初始化最初是为了更有效地初始化复杂对象而引入的;当值被显式地转换为另一种类型时,可以使用直接初始化
- 使用列表初始化时,编译器会检查类型是否匹配
int a = 4.5; // 编译通过
int b(4.5); // 编译通过
int c{4.5}; // 编译报错
- {}会将变量初始化为0或空,因此值初始化也称零初始化
[[maybe_unused]]可以用于修饰一些暂时不使用的变量,从而不会产生编译告警
1.5 iostream介绍
- io库是C++标准库的一部分,用于处理基本输入输出
- io库包含了一些预定义的变量供使用,例如
std::cout和std::cin <<称为插入运算符,>>称为提取运算符std::cout会将输出内容先存入缓冲区std::endl除了会输出一个新行,还会刷新缓冲区,因此效率不如\n- C++的io库未提供一种方法,可以在用户不按回车键的情况下接收键盘输入(有些第三方库提供了这种方法)
- 输入缓冲区中的每行输入数据都以
\n字符结束 - 基本的提取过程:
- 1.前置的空格、制表符、换行符都会被丢弃
- 2.如果输入缓冲区是空的,
>>将等待用户输入 - 3.
>>会提取尽可能多的连续字符,直到遇到换行符或者对于接收变量来说无效的字符
- 提取的结果:
- 如果上面的步骤3中提取了任何字符,则提取成功。提取的字符被转换成一个值并赋给变量
- 如果步骤3没有提取到任何字符,则提取失败。后面的所有提取都会立即失败,直到std::cin被清空
- 任何未提取的字符(包括换行符)仍可用于下一次提取尝试
int x{};
std::cin>>x;
如果用户输入了5a并回车,则5被赋给了x,a和\n则留在了输入缓冲区用于下一次提取
如果用户输入了b并回车,由于b不是有效的整数,因此提取失败,x被设置为0,未来的提取都会失败,直到输入流被清空
1.6 未初始化的变量和未定义的行为
- 一个未初始化的变量的默认值就是那个内存地址中本来就已经存在的值(是不确定的)
- 未定义的行为可能有如下表现:
- 程序每次运行产生不同结果
- 程序总是产生同样的错误结果
- 程序看起来在工作,但在之后又产生错误结果
- 程序崩溃
- 程序在一些编译器上工作,但在另一些编译器不工作
- 程序不工作,除非改变一些看似无关的代码
implementation-defined behavior指的是留给实现(编译器)来定义的语法行为,这些行为必须是一致的且有文档记录,不同的编译器可能会产生不同的结果- 避免使用与编译器的具体实现相关的语法,例如sizeof
1.7 关键字和命名标识符
- 命名规则建议
- 变量名/方法名应该首字母小写,并使用驼峰命名法;结构体名/自定义类名/枚举类型名应该首字母大写
- 避免使用下划线作为标识符的首字母,因为这些名称通常是保留给操作系统或者编译器使用的
- 选择有意义的名称,能够让人一眼看出这个变量的作用
1.8 空白和基本格式
- 双引号中不允许包含换行,但是两个被双引号包含的字符串可以通过空格/换行连接
std::cout << "Hello
world!"; // Not allowed!
std::cout << "Hello "
"world!"; // prints "Hello world!"
- 基本格式建议
- 使用空格或者tab缩进
- 如果一行被分割成了多行,则操作符应该放在新行的行首而不是上一行的行尾
- 当在一个已存在的项目中工作时,要与已被采用的风格保持一致
1.9 字面量和运算符
字面量(字面量常量)是直接插入到源代码中的固定值
// "hello"和5都是字面量
std::cout << "hello";
int x{5};
- 字面量和变量一样,都有值和类型,但是变量的值可以改变,而
字面量的值是固定的
std::cout << 5 << '\n';
int x{5};
std::cout << x << '\n';
编译器在编译第1行时,会生成
cout打印5的代码。5这个值会被编译进可执行文件,并且可以直接使用
编译器在编译第2行时,会生成将5这个值复制到变量x对应的那块内存中的代码
编译器在编译第3行时,会生成cout打印变量x对应的那块内存中的值(也就是5)的代码
因此,在字面量的情况下,可以直接打印出5这个值;而在变量的情况下,需要先从变量对应的内存中获取5这个值,然后再打印
- 字面量是直接插入到源代码中的值,这些值通常直接出现在可执行文件中(除非它们被优化掉),而可执行文件在创建后是不能改变的;而变量的值是存放在内存中,内存中的值是可以在可执行文件运行过程中修改的
- 运算符接收的输入参数的个数叫做元数:一元运算符、二元运算符、三元运算符(只有
条件运算符)、零式运算符(只有throw运算符) - 大部分运算符会接收操作数并计算得到一个结果,少部分运算符不会产生运算结果(例如
delete和throw) - 一些运算符除了产生返回值之外,还有产生一些额外的、可观测的影响(也叫做
副作用) - 运算符
=和<<的返回结果是它们的左操作数。x=5的返回结果是x,std::cout<<5的返回结果是std::cout
这样做的原因是为了使这些运算符可以链接使用
x=y=5:先计算y=5将5赋值给y,然后返回y,然后再计算x=y,将y的值赋值给x
std::cout<<"hello"<<"world":先计算std::cout<<"hello",输出"hello",然后返回std::cout,然后再计算std::cout<<"world",输出"world"
1.10 表达式
表达式是由字面量、变量、运算符、函数调用组成非空序列,用于计算单个值。执行表达式的过程称为求值,产生的单个值称为表达式的结果。
2 // 这个表达式的值就是2
"hello" // 这个表达式的值就是"hello"
x // 这个表达式的值就是x的值
2 + 3 // 这个表达式的值就是5
five() // 这个表达式的值就是five函数的返回值
- 包含带有副作用的运算符的表达式有点不一样
x = 5 // 这个表达式的值是x(副作用是将5赋值给x)
x = 2 + 3 // 这个表达式的值是x(副作用是将5赋值给x)
std::cout << x // 这个表达式的值是std::cout(副作用是输出x的值)
- 表达式不以
;结尾,表达式始终作为语句的一部分:type identifier {expression};
int x{2+3}; // 2+3是表达式,而分号在包含表达式的整个语句的结尾
语句用于程序
执行某个操作,表达式用于程序计算一个值
- 在C++中,在任何可以使用单个值的地方,都可以使用产生单个值的表达式进行替代
表达式语句就是由一个表达式后面加上分号组成的语句
当表达式用在表达式语句中时,任何表达式
计算得到的结果都会被丢弃(例如x=5;,这个表达式的返回结果是x,这个结果被丢弃,而不是x本身被丢弃)
- 无用的表达式语句(例如
2*3;)会导致编译警告 子表达式:可以当做操作数使用的表达式,例如x=4+5的子表达式是x和4+5;4+5的子表达式是4和5完整表达式:不是子表达式的表达式。x=4+5就是完整表达式复合表达式:包含两个或多个运算符的表达式。x=4+5是复合表达式,4+5不是复合表达式
浙公网安备 33010602011771号