# 狸墨QQ群:134722347
# 程序结构(Lesson1)
**#include**
预处理指令,为方便编译器处理而设置的一种机制,包括一些常用预处理指令和语句,我们统称为预处理系统。
预处理器发现#include 指令后,就会寻找指令后面<>中的文件名,并把这个文件的内容包含到当前文件中。被包含文件中的文本将替换源代码文件中的#include指令,就像你把被包含文件中的全部内容键入到源文件中的这个位置一样。
预处理阶段主要处理的是文本信息。
**main入口函数**
程序运行时最先调用的函数,为了启动编写逻辑,所有的入口函数一般约定为main函数
**std 空间名称**
是C++标准库的空间名称
**::和<<**
:域操作符,用来标注调用内容属于哪一个操作域,可以理为“的”。
<<操作运算符,是被重载后的运算符,属于cout的一个运算符。主要用来表示将后面的内容进行输出调用
# 数据类型(Lesson2)
## 基本的内置类型
Lesson1
C++ 为程序员提供了种类丰富的内置数据类型和用户自定义的数据类型。下表列出了七种基本的 C++ 数据类型:
| 类型 | 关键字 |
| :------- | :------ |
| 布尔型 | bool |
| 字符型 | char |
| 整型 | int |
| 浮点型 | float |
| 双浮点型 | double |
| 无类型 | void |
| 宽字符型 | wchar_t |
一些基本类型可以使用一个或多个类型修饰符进行修饰:
- signed
- unsigned
- short
- long
| 类型 | 位 | 范围 |
| :----------------- | :------------ | :----------------------------------------------------------- |
| char | 1 个字节 | -128 到 127 或者 0 到 255 |
| unsigned char | 1 个字节 | 0 到 255 |
| signed char | 1 个字节 | -128 到 127 |
| int | 4 个字节 | -2147483648 到 2147483647 |
| unsigned int | 4 个字节 | 0 到 4294967295 |
| signed int | 4 个字节 | -2147483648 到 2147483647 |
| short int | 2 个字节 | -32768 到 32767 |
| unsigned short int | 2 个字节 | 0 到 65,535 |
| signed short int | 2 个字节 | -32768 到 32767 |
| long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
| signed long int | 8 个字节 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
| unsigned long int | 8 个字节 | 0 到 18,446,744,073,709,551,615 |
| float | 4 个字节 | 精度型占4个字节(32位)内存空间,+/- 3.4e +/- 38 (~7 个数字) |
| double | 8 个字节 | 双精度型占8 个字节(64位)内存空间,+/- 1.7e +/- 308 (~15 个数字) |
| long double | 16 个字节 | 长双精度型 16 个字节(128位)内存空间,可提供18-19位有效数字。 |
| wchar_t | 2 或 4 个字节 | 1 个宽字符 |
## 常量与变量
### 字面值常量:
直接使用具体数字的值,省去了类型的定义。
这种莫名其妙的字面量也叫幻数。
为了区分不同类型字面值常量,我们使用不同方式:
1.整型字面值常量
2.浮点字面值常量
3.布尔字面值常量
4.字符字面值常量
5.字符串字面值常量
6.转义字符
### 变量:
变量其实只不过是程序可操作的存储区的名称。C++ 中每个变量都有指定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。
1.变量的名称可以由字母、数字和下划线字符组成。
2.它必须以字母或下划线开头。
3.大写字母和小写字母是不同的,因为 C++ 是大小写敏感的。
4.不能使用C++关键字定义
### const常量:
常量在编写时不能改变的数值
### typedef
定义变量类型的别名
作用:
1.使变量类型更清晰
2.用简短名字代替复杂的类型名,使得复杂的类型定义更容易理解
# 运算符(Lesson3)
## 算术运算符
| 运算符 | 描述 | 实例 |
| :----- | :------------------------------- | :--------------- |
| + | 把两个操作数相加 | A + B 将得到 30 |
| - | 从第一个操作数中减去第二个操作数 | A - B 将得到 -10 |
| * | 把两个操作数相乘 | A * B 将得到 200 |
| / | 分子除以分母 | B / A 将得到 2 |
| % | 取模运算符,整除后的余数 | B % A 将得到 0 |
| ++ | 自增运算符,整数值增加 1 | A++ 将得到 11 |
| -- | 自减运算符,整数值减少 1 | |
## 关系运算符
| 运算符 | 描述 | 实例 |
| :----- | :----------------------------------------------------------- | :---------------- |
| == | 检查两个操作数的值是否相等,如果相等则条件为真。 | (A == B) 不为真。 |
| != | 检查两个操作数的值是否相等,如果不相等则条件为真。 | (A != B) 为真。 |
| > | 检查左操作数的值是否大于右操作数的值,如果是则条件为真。 | (A > B) 不为真。 |
| < | 检查左操作数的值是否小于右操作数的值,如果是则条件为真。 | (A < B) 为真。 |
| >= | 检查左操作数的值是否大于或等于右操作数的值,如果是则条件为真。 | (A >= B) 不为真。 |
| <= | 检查左操作数的值是否小于或等于右操作数的值,如果是则条件为真。 | (A <= B) 为真。 |
## 逻辑运算符
| 运算符 | 描述 | 实例 |
| :----- | :----------------------------------------------------------- | :------------------- |
| && | 称为逻辑与运算符。如果两个操作数都 true,则条件为 true。 | (A && B) 为 false。 |
| \|\| | 称为逻辑或运算符。如果两个操作数中有任意一个 true,则条件为 true。 | (A \|\| B) 为 true。 |
| ! | 称为逻辑非运算符。用来逆转操作数的逻辑状态,如果条件为 true 则逻辑非运算符将使其为 false。 | !(A && B) 为 true。 |
## 位运算符
| 运算符 | 描述 | 实例 |
| :----- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| & | 按位与操作,按二进制位进行"与"运算。运算规则:`0&0=0; 0&1=0; 1&0=0; 1&1=1;` | (A & B) 将得到 12,即为 0000 1100 |
| \| | 按位或运算符,按二进制位进行"或"运算。运算规则:`0|0=0; 0|1=1; 1|0=1; 1|1=1;` | (A \| B) 将得到 61,即为 0011 1101 |
| ^ | 异或运算符,按二进制位进行"异或"运算。运算规则:`0^0=0; 0^1=1; 1^0=1; 1^1=0;` | (A ^ B) 将得到 49,即为 0011 0001 |
| ~ | 取反运算符,按二进制位进行"取反"运算。运算规则:`~1=-2; ~0=-1;` | (~A ) 将得到 -61,即为 1100 0011,一个有符号二进制数的补码形式。 |
| << | 二进制左移运算符。将一个运算对象的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。 | A << 2 将 得到 240,即为 1111 0000 |
| >> | 二进制右移运算符。将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。 | A >> 2 将得到 15,即为 0000 1111 |
## 赋值运算符
| 运算符 | 描述 | 实例 |
| :----- | :----------------------------------------------------------- | :------------------------------ |
| = | 简单的赋值运算符,把右边操作数的值赋给左边操作数 | C = A + B 将把 A + B 的值赋给 C |
| += | 加且赋值运算符,把右边操作数加上左边操作数的结果赋值给左边操作数 | C += A 相当于 C = C + A |
| -= | 减且赋值运算符,把左边操作数减去右边操作数的结果赋值给左边操作数 | C -= A 相当于 C = C - A |
| *= | 乘且赋值运算符,把右边操作数乘以左边操作数的结果赋值给左边操作数 | C *= A 相当于 C = C * A |
| /= | 除且赋值运算符,把左边操作数除以右边操作数的结果赋值给左边操作数 | C /= A 相当于 C = C / A |
| %= | 求模且赋值运算符,求两个操作数的模赋值给左边操作数 | C %= A 相当于 C = C % A |
| <<= | 左移且赋值运算符 | C <<= 2 等同于 C = C << 2 |
| >>= | 右移且赋值运算符 | C >>= 2 等同于 C = C >> 2 |
| &= | 按位与且赋值运算符 | C &= 2 等同于 C = C & 2 |
| ^= | 按位异或且赋值运算符 | C ^= 2 等同于 C = C ^ 2 |
| \|= | 按位或且赋值运算符 | C \|= 2 等同于 C = C \| 2 |
## 其他运算符
| 运算符 | 描述 |
| :------------------- | :----------------------------------------------------------- |
| sizeof | [sizeof 运算符](https://www.runoob.com/cplusplus/cpp-sizeof-operator.html)返回变量的大小。例如,sizeof(a) 将返回 4,其中 a 是整数。 |
| Condition ? X : Y | [条件运算符](https://www.runoob.com/cplusplus/cpp-conditional-operator.html)。如果 Condition 为真 ? 则值为 X : 否则值为 Y。 |
| , | [逗号运算符](https://www.runoob.com/cplusplus/cpp-comma-operator.html)会顺序执行一系列运算。整个逗号表达式的值是以逗号分隔的列表中的最后一个表达式的值。 |
| .(点)和 ->(箭头) | [成员运算符](https://www.runoob.com/cplusplus/cpp-member-operators.html)用于引用类、结构和共用体的成员。 |
| Cast | [强制转换运算符](https://www.runoob.com/cplusplus/cpp-casting-operators.html)把一种数据类型转换为另一种数据类型。例如,int(2.2000) 将返回 2。 |
| & | [指针运算符 &](https://www.runoob.com/cplusplus/cpp-pointer-operators.html) 返回变量的地址。例如 &a; 将给出变量的实际地址。 |
| * | [指针运算符 *](https://www.runoob.com/cplusplus/cpp-pointer-operators.html) 指向一个变量。例如,*var; 将指向变量 var。 |
## 运算符优先级
| 优先级 | 操作符 | 描述 | 例子 | 结合性 |
| ------ | ------------------------------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | -------- |
| 1 | ()<br /> []<br /> -> <br />.<br /> ::<br /> ++<br /> -- | 调节优先级的括号操作符<br />数组下标访问操作符 <br />通过指向对象的指针访问成员的操作符<br /> 通过对象本身访问成员的操作符 <br />作用域操作符 <br />后置自增操作符<br />后置自减操作符 | (a + b) / 4;<br /> array[4] = 2; <br />ptr->age = 34; <br />obj.age = 34; <br />Class::age = 2;<br />for( i = 0; i < 10; i++ ) ...<br />for( i = 10; i > 0; i-- ) ... | 从左到右 |
| 2 | !<br /> ~<br /> ++<br /> --<br /> -<br /> +<br /> *<br /> &<br /> (type) <br />sizeof | 逻辑取反操作符 <br />按位取反(按位取补) <br />前置自增操作符 <br />前置自减操作符 <br />一元取负操作符 <br />一元取正操作符 <br />解引用操作符 <br />取地址操作符 <br />类型转换操作符 <br />返回对象占用的字节数操作符 | if( !done ) ... <br />flags = ~flags; <br />for( i = 0; i < 10; ++i ) ... <br />for( i = 10; i > 0; --i ) ... <br />int i = -1; <br />int i = +1; <br />data = *ptr; <br />address = &obj; <br />int i = (int) floatNum; <br />int size = sizeof(floatNum); | 从右到左 |
| 3 | -><br />* .* | 在指针上通过指向成员的指针访问成员的操作符 <br />在对象上通过指向成员的指针访问成员的操作符 | ptr->*var = 24; <br />obj.*var = 24; | 从左到右 |
| 4 | *<br /> /<br /> % | 乘法操作符 <br />除法操作符 <br />取余数操作符 | int i = 2 * 4; <br />float f = 10 / 3; <br />int rem = 4 % 3; | 从左到右 |
| 5 | +<br /> - | 加法操作符 <br />减法操作符 | int i = 2 + 3;<br />int i = 5 - 1; | 从左到右 |
| 6 | <<<br /> >> | 按位左移操作符 <br />按位右移操作符 | int flags = 33 << 1;<br />int flags = 33 >> 1; | 从左到右 |
| 7 | < <br /><= <br />><br />>= | 小于比较操作符<br />小于或等于比较操作符<br />大于比较操作符 <br />大于或等于比较操作符 | if( i < 42 ) ...<br />if( i <= 42 ) ...<br />if( i > 42 ) ...<br />if( i >= 42 ) ... | 从左到右 |
| 8 | ==<br /> != | 等于比较操作符 <br />不等于比较操作符 | if( i == 42 ) ...<br />if( i != 42 ) ... | 从左到右 |
| 9 | & | 按位与操作符 | flags = flags & 42; | 从左到右 |
| 10 | ^ | 按位异或操作符 | flags = flags ^ 42; | 从左到右 |
| 11 | \| | 按位或操作符 | flags = flags \| 42; | 从左到右 |
| 12 | && | 逻辑与操作符 | if( conditionA && conditionB ) ... | 从左到右 |
| 13 | \|\| | 逻辑或操作符 | if( conditionA \|\| conditionB ) ... | 从左到右 |
| 14 | ? : | 三元条件操作符 | int i = (a > b) ? a : b; | 从右到左 |
| 15 | =<br /> +=<br /> -=<br /> *=<br /> /=<br /> %= <br />&=<br />^=<br />\|=<br /><<=<br />>>= | 赋值操作符<br />复合赋值操作符(加法) <br />复合赋值操作符(减法) <br />复合赋值操作符(乘法) <br />复合赋值操作符(除法) <br />复合赋值操作符(取余) <br />复合赋值操作符(按位与) <br />复合赋值操作符(按位异或) <br />复合赋值操作符(按位或) <br />复合赋值操作符(按位左移) <br />复合赋值操作符(按位右移) | int a = b; <br />a += 3; <br />b -= 4;<br /> a *= 5; <br />a /= 2; <br />a %= 3; <br />flags &= new_flags; <br />flags ^= new_flags; <br />flags \|= new_flags; <br />flags <<= 2; <br />flags >>= 2; | 从右到左 |
| 16 | , | 逗号操作符 | for( i = 0, j = 0; i < 10; i++, j++ ) ... | 从左到右 |
## 类型转换
隐式转换
隐式转换会在编译器遇到两个类型不同的操作数的时候自动进行,这一套规则的原则是尽量保持精度,因此精度低的类型会往精度高的类型转换,而存储空间小的类型会往空间大的类型转换。
显式转换
使用强制转换达成自由转换的目的而采用的转换方式
# 流程控制(Lesson4)
## 作用域和块
作用域就是变量的可见范围,在某个作用域中定义了变量之后,我们可以使用、访问这个变量,但是出了这个作用域后,我们就无法使用这个变量了。
程序的作用域是自顶向下定义的,在最上级首先有个全局作用域。全局作用域定义的变量可以在文件中的所有地方被访问,它也叫全局变量,而其他非全局的变量叫做局部变量;而在其下,我们会用花括号{}定义一个个的块,每个块都定义了一层的作用域,而块中又能嵌套,于是就有了顶层作用域的结构。
## 条件控制语句
判断结构要求程序员指定一个或多个要评估或测试的条件,以及条件为真时要执行的语句(必需的)和条件为假时要执行的语句(可选的)。
下面是大多数编程语言中典型的判断结构的一般形式:
![C++ 中的判断语句](C++基础入门.assets/if.png)
| 语句 | 描述 |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| [if 语句](https://www.runoob.com/cplusplus/cpp-if.html) | 一个 **if 语句** 由一个布尔表达式后跟一个或多个语句组成。 |
| [if...else 语句](https://www.runoob.com/cplusplus/cpp-if-else.html) | 一个 **if 语句** 后可跟一个可选的 **else 语句**,else 语句在布尔表达式为假时执行。 |
| [嵌套 if 语句](https://www.runoob.com/cplusplus/cpp-nested-if.html) | 您可以在一个 **if** 或 **else if** 语句内使用另一个 **if** 或 **else if** 语句。 |
| [switch 语句](https://www.runoob.com/cplusplus/cpp-switch.html) | 一个 **switch** 语句允许测试一个变量等于多个值时的情况。 |
| [嵌套 switch 语句](https://www.runoob.com/cplusplus/cpp-nested-switch.html) | 您可以在一个 **switch** 语句内使用另一个 **switch** 语句。 |
**If语句**
If语句是一种基本的条件控制语句,If语句的后面可以选择性的加上else语句
**Switch语句**
switch语句开头的括号中是一个表达式,而其下面的每个case都是这个表达式可能得到的值,每个不同的值都会使程序走进一段不同的代码。表达式的值如果没有出现在所有case后面,就会自动落到default的代码段中
case后面必须是常整型(包括字符型和布尔型),如果不是常量整数,编译器在编译的时候就无法确定分支条件,也就失去了Switch语句优化的好处。
## 循环控制语句
有的时候,可能需要多次执行同一块代码。一般情况下,语句是顺序执行的:函数中的第一个语句先执行,接着是第二个语句,依此类推。
编程语言提供了允许更为复杂的执行路径的多种控制结构。
循环语句允许我们多次执行一个语句或语句组,下面是大多数编程语言中循环语句的一般形式:
![循环结构](C++基础入门.assets/loop.png)
**循环类型**
| 循环类型 | 描述 |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| [while 循环](https://www.runoob.com/cplusplus/cpp-while-loop.html) | 当给定条件为真时,重复语句或语句组。它会在执行循环主体之前测试条件。 |
| [for 循环](https://www.runoob.com/cplusplus/cpp-for-loop.html) | 多次执行一个语句序列,简化管理循环变量的代码。 |
| [do...while 循环](https://www.runoob.com/cplusplus/cpp-do-while-loop.html) | 除了它是在循环主体结尾测试条件外,其他与 while 语句类似。 |
| [嵌套循环](https://www.runoob.com/cplusplus/cpp-nested-loops.html) | 您可以在 while、for 或 do..while 循环内使用一个或多个循环。 |
循环控制语句更改执行的正常序列。当执行离开一个范围时,所有在该范围中创建的自动对象都会被销毁。
| 控制语句 | 描述 |
| :----------------------------------------------------------- | :----------------------------------------------------------- |
| [break 语句](https://www.runoob.com/cplusplus/cpp-break-statement.html) | 终止 **loop** 或 **switch** 语句,程序流将继续执行紧接着 loop 或 switch 的下一条语句。 |
| [continue 语句](https://www.runoob.com/cplusplus/cpp-continue-statement.html) | 引起循环跳过主体的剩余部分,立即重新开始测试条件。 |
| [goto 语句](https://www.runoob.com/cplusplus/cpp-goto-statement.html) | 将控制转移到被标记的语句。但是不建议在程序中使用 goto 语句。 |
# Vector容器与字符串(Lesson5)
## Vector
向量(Vector)是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组。
**容器特性:**
1.顺序序列
顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。
2.动态数组
支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作。提供了在序列末尾相对快速地添加/删除元素的操作。
3.能够感知内存分配器的(Allocator-aware)
容器使用一个内存分配器对象来动态地处理它的存储需求。
函数用法:
1.push_back 在数组的最后添加一个数据
2.pop_back 去掉数组的最后一个数据
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值
12.reserve 改变当前vector所分配空间的大小
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转后的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据
## String字符串
string本质上看作是一种vector<char>也是元素为char的vector
vector的基本操作都适用于string
string的比较规则:
1.字符串比较区分大小写,而大写字母必小写字母小
2.字符串不等长,但是在短的字符串与长的字符串的前一部分完全相等的情况下,短的string小于长的string
3.遇到第一对不匹配的字符就立即返回按字典顺序比较的结果
# 数组与指针(Lesson6)
## 数组的声明与定义
C++ 支持**数组**数据结构,它可以存储一个固定大小的相同类型元素的顺序集合。数组是用来存储一系列数据,但它往往被认为是一系列相同类型的变量。
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 numbers[0]、numbers[1]、...、numbers[99] 来代表一个个单独的变量。数组中的特定元素可以通过索引访问。
所有的数组都是由连续的内存位置组成。最低的地址对应第一个元素,最高的地址对应最后一个元素。
在 C++ 中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:
```
type arrayName [ arraySize ];
```
C++ 支持多维数组,多维数组声明的一般形式如下:
```
type name[size1][size2]...[sizeN];
```
## 二维数组
多维数组最简单的形式是二维数组。一个二维数组,在本质上,是一个一维数组的列表。声明一个 x 行 y 列的二维整型数组,形式如下:
```
type arrayName [ x ][ y ];
```
其中,**type** 可以是任意有效的 C++ 数据类型,**arrayName** 是一个有效的 C++ 标识符。
一个二维数组可以被认为是一个带有 x 行和 y 列的表格。下面是一个二维数组,包含 3 行和 4 列:
![C++ 中的二维数组](C++基础入门.assets/two_dimensional_arrays.jpg)
因此,数组中的每个元素是使用形式为 a[ i , j ] 的元素名称来标识的,其中 a 是数组名称,i 和 j 是唯一标识 a 中每个元素的下标。
## 指针
每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址
**指针**是一个变量,其值为另一个变量的地址,即,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:
```
type *var-name;
```
在这里,**type** 是指针的基类型,它必须是一个有效的 C++ 数据类型,**var-name** 是指针变量的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。但是,在这个语句中,星号是用来指定一个变量是指针。
所有指针的值的实际数据类型,不管是整型、浮点型、字符型,还是其他的数据类型,都是一样的,都是一个代表内存地址的长的十六进制数。不同数据类型的指针之间唯一的不同是,指针所指向的变量或常量的数据类型不同。
使用指针时会频繁进行以下几个操作:定义一个指针变量、把变量地址赋值给指针、访问指针变量中可用地址的值。这些是通过使用一元运算符 ***** 来返回位于操作数所指定地址的变量的值。
**const指针:**
如果原变量是const,值是不能被修改的,指向const对象的指针是一种特殊的指针来保证原变量不会被修改。
**指针的数组和数组的指针:**
指针的数组是一种数组,而数组的指针是一种指针
**指针的指针:**
指针可以指向变量或者对象,也可以指向指针
**const_cast:**
将一个变量转换成const限定的常量
**reinterpret_cast:**
将指向整数的指针转换成指向字符的指针
## 动态数组
动态数组,严格意义上来说并不是数组,程序会使用指针来承载malloc()或者new操作符动态分配的内存空间,然后在需要更新数组大小或者释放空间的时候使用free()或者delete。
**使用malloc()和free()动态分配内存:**
malloc()函数可以在一个叫作堆(Heap)的内存空间中分配制定字节数的内存。与作用域中在栈(Stack)中分配内存的局部变量不同,堆中的内存一旦分配,就不会自动被释放,直到程序调用free()函数
注意:在c++程序中,一定要让free()或delete与malloc()和new匹配,既在程序中一次内存分配一定要有相对应的一次相同大小的内存释放。
## 引用
引用变量是一个别名,也就是说,它是某个已存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
## C++ 引用 vs 指针
引用和指针的区别:
1.不存在空引用,引用必须连接到一块合法的内存。指针可以为空。
2.一旦引用被初始化为一个对象,就不能被指向到另一个对象。指针可以在任何时候指向到另一个对象。
3.引用必须在创建时被初始化,指针可以在任何时间被初始化。
4.修改引用时修改的是引用所代表的原变量的值,而修改指针时则是修改指针所指向的地址。
# 函数(Lesson7)
## 函数定义
函数是一组一起执行一个任务的语句。每个 C++ 程序都至少有一个函数,即主函数 **main()** ,所有简单的程序都可以定义其他额外的函数。
您可以把代码划分到不同的函数中。如何划分代码到不同的函数中是由您来决定的,但在逻辑上,划分通常是根据每个函数执行一个特定的任务来进行的。
函数**声明**告诉编译器函数的名称、返回类型和参数。函数**定义**提供了函数的实际主体。
## 定义函数
C++ 中的函数定义的一般形式如下:
return_type function_name( parameter list ) { body of the function }
在 C++ 中,函数由一个函数头和一个函数主体组成。下面列出一个函数的所有组成部分:
- **返回类型:**一个函数可以返回一个值。**return_type** 是函数返回的值的数据类型。有些函数执行所需的操作而不返回值,在这种情况下,return_type 是关键字 **void**。
- **函数名称:**这是函数的实际名称。函数名和参数列表一起构成了函数签名。
- **参数:**参数就像是占位符。当函数被调用时,您向参数传递一个值,这个值被称为实际参数。参数列表包括函数参数的类型、顺序、数量。参数是可选的,也就是说,函数可能不包含参数。
- **函数主体:**函数主体包含一组定义函数执行任务的语句。
## 调用函数
创建 C++ 函数时,会定义函数做什么,然后通过调用函数来完成已定义的任务。
当程序调用函数时,程序控制权会转移给被调用的函数。被调用的函数执行已定义的任务,当函数的返回语句被执行时,或到达函数的结束括号时,会把程序控制权交还给主程序。
调用函数时,传递所需参数,如果函数返回一个值,则可以存储返回值。
## 函数参数
如果函数要使用参数,则必须声明接受参数值的变量。这些变量称为函数的**形式参数**。
形式参数就像函数内的其他局部变量,在进入函数时被创建,退出函数时被销毁。
当调用函数时,有三种向函数传递参数的方式:
| 调用类型 | 描述 |
| :------- | :----------------------------------------------------------- |
| 传值调用 | 该方法把参数的实际值赋值给函数的形式参数。在这种情况下,修改函数内的形式参数对实际参数没有影响。 |
| 指针调用 | 该方法把参数的地址赋值给形式参数。在函数内,该地址用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。 |
| 引用调用 | 该方法把参数的引用赋值给形式参数。在函数内,该引用用于访问调用中要用到的实际参数。这意味着,修改形式参数会影响实际参数。 |
默认情况下,C++ 使用**传值调用**来传递参数。一般来说,这意味着函数内的代码不能改变用于调用函数的参数。之前提到的实例,调用 max() 函数时,使用了相同的方法。
## 参数传递
参数传递就是要把实参传递,或者说赋值给形参。
形参本质上只是一个函数内部的局部变量,它声明在参数列表中,这只是表面在调用函数的时候,我们将会把第一个实参的值赋值给第一形参。
c++参数传递主要的方式:按值传递、指针传递、引用传递
按值传递:简单把实参的值赋值给形参。
指针传递:和按值传递一样,只是将对象换成了指针。
引用传递:只是声明一个变量的别名,并没有复制值或指针。
## 函数返回值
返回值与按值传参一样都是赋值操作,只是传参是从外赋值到内,而返回值是从内赋值到外。
返回引用
返回指针
## 函数重载
直接声明两个名字一样的函数并使用不同的参数类型,编译器并不会因此而认为这是函数重定义。
**重载解析:**
定义好重载函数后,在函数调用的时候编译器需要负责找到一个与实参列表最匹配的重载版本。编译器寻找这样一个函数的过程叫重载解析。
重载解析的3种结果:
1.找到与实参最匹配的函数
2.没有找到匹配可用的函数,编译器报错。
3.找到几个匹配的但匹配度不分上下的函数,编译器会报出二义性错误。
重载解析过程的步骤:
1.先找到所有当前作用域中可见的重名函数,也叫候选函数
2.然后找到参数个数一致,并且参数类型一致或者可以隐式转换的可行函数。
3.最后找到一个最佳匹配函数,匹配度是由有多少参数需要隐式转换来决定的,如果参数都不用转换,那么该函数肯定是最佳匹配函数。
## 函数指针
如果在程序中定义了一个函数,那么在编译时系统就会为这个函数代码分配一段存储空间,这段存储空间的首地址称为这个函数的地址。而且函数名表示的就是这个地址。既然是地址我们就可以定义一个指针变量来存放,这个指针变量就叫作函数指针变量,简称函数指针。
函数指针指向某种特定类型,函数的类型由其参数及返回类型共同决定,与函数名无关。
函数指针的定义方式为:
```
函数返回值类型 (* 指针变量名) (函数参数列表);
```
网友评论