doc/docs/Cpp-Primer/2.变量和基本类型.md
sairate c34823a3bd docs(book): 添加现代 C++教程及相关代码
- 新增现代 C++ 教程的 Preface 章节,包括英文和中文版本
- 添加 C++ Primer 练习代码
- 新增 Learn C++ 教程的 C++ 开发简介章节
- 添加头文件解析文档
- 更新 mkdocs.yml,包含新教程的目录结构
- 修改项目设置,使用 Python 3.10环境
2025-07-06 14:46:58 +08:00

249 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
sort: 2
---
# 变量和基本类型
### 基本内置类型
**基本算数类型**
| 类型 | 含义 | 最小尺寸 |
| ------------- | -------------- | ------------------------------ |
| `bool` | 布尔类型 | 8bits |
| `char` | 字符 | 8bits |
| `wchar_t` | 宽字符 | 16bits |
| `char16_t` | Unicode字符 | 16bits |
| `char32_t` | Unicode字符 | 32bits |
| `short` | 短整型 | 16bits |
| `int` | 整型 | 16bits (在32位机器中是32bits) |
| `long` | 长整型 | 32bits |
| `long long` | 长整型 | 64bits 是在C++11中新定义的 |
| `float` | 单精度浮点数 | 6位有效数字 |
| `double` | 双精度浮点数 | 10位有效数字 |
| `long double` | 扩展精度浮点数 | 10位有效数字 |
### 如何选择类型
- 1.当明确知晓数值不可能是负数时,选用无符号类型;
- 2.使用`int`执行整数运算。一般`long`的大小和`int`一样,而`short`常常显得太小。除非超过了`int`的范围,选择`long long`
- 3.算术表达式中不要使用`char``bool`
- 4.浮点运算选用`double`
### 类型转换
- 非布尔型赋给布尔型初始值为0则结果为false否则为true。
- 布尔型赋给非布尔型初始值为false结果为0初始值为true结果为1。
### 字面值常量
- 一个形如`42`的值被称作**字面值常量**literal
- 整型和浮点型字面值。
- 字符和字符串字面值。
- 使用空格连接继承自C。
- 字符字面值:单引号, `'a'`
- 字符串字面值:双引号, `"Hello World""`
- 分多行书写字符串。
```
std:cout<<"wow, a really, really long string"
"literal that spans two lines" <<std::endl;
```
- 转义序列。`\n`、`\t`等。
- 布尔字面值。`true``false`。
- 指针字面值。`nullptr`
> 字符串型实际上时常量字符构成的数组,结尾处以`'\0'`结束所以字符串类型实际上长度比内容多1。
## 变量
**变量**提供一个**具名**的、可供程序操作的存储空间。 `C++`中**变量**和**对象**一般可以互换使用。
### 变量定义define
- **定义形式**类型说明符type specifier + 一个或多个变量名组成的列表。如`int sum = 0, value, units_sold = 0;`
- **初始化**initialize对象在创建时获得了一个特定的值。
- **初始化不是赋值!**
- 初始化 = 创建变量 + 赋予初始值
- 赋值 = 擦除对象的当前值 + 用新值代替
- **列表初始化**:使用花括号`{}`,如`int units_sold{0};`
- 默认初始化:定义时没有指定初始值会被默认初始化;**在函数体内部的内置类型变量将不会被初始化**。
- 建议初始化每一个内置类型的变量。
### 变量的**声明**declaration vs **定义**define
- 为了支持分离式编译,`C++`将声明和定义区分开。**声明**使得名字为程序所知。**定义**负责创建与名字关联的实体。
- **extern**:只是说明变量定义在其他地方。
- 只声明而不定义: 在变量名前添加关键字 `extern`,如`extern int i;`。但如果包含了初始值,就变成了定义:`extern double pi = 3.14;`
- 变量只能被定义一次,但是可以多次声明。定义只出现在一个文件中,其他文件使用该变量时需要对其声明。
- 名字的**作用域**namescope`{}`
- **第一次使用变量时再定义它**。
- 嵌套的作用域
- 同时存在全局和局部变量时,已定义局部变量的作用域中可用`::reused`显式访问全局变量reused。
- **但是用到全局变量时,尽量不适用重名的局部变量。**
#### 变量命名规范
1. 需体现实际意义
2. 变量名用小写字母
3. 自定义类名用大写字母开头Sales_item
4. 标识符由多个单词组成中间须有明确区分student_loan或studentLoan不要用studentloan。
## 左值和右值
- **左值**l-value**可以**出现在赋值语句的左边或者右边,比如变量;
- **右值**r-value**只能**出现在赋值语句的右边,比如常量。
## 复合类型
### 引用
> 一般说的引用是指的左值引用
- **引用**引用是一个对象的别名引用类型引用refer to另外一种类型。如`int &refVal = val;`。
- 引用必须初始化。
- 引用和它的初始值是**绑定bind**在一起的,而**不是拷贝**。一旦定义就不能更改绑定为其他的对象
### 指针
> int *p; //**指向int型对象**的指针
- 是一种 `"指向point to"`另外一种类型的复合类型。
- **定义**指针类型: `int *ip1;`**从右向左读有助于阅读**`ip1`是指向`int`类型的指针。
- 指针存放某个对象的**地址**。
- 获取对象的地址: `int i=42; int *p = &i;``&`是**取地址符**。
- 指针的类型与所指向的对象类型必须一致均为同一类型int、double等
- 指针的值的四种状态:
- 1.指向一个对象;
- 2.指向紧邻对象的下一个位置;
- 3.空指针;
- 4.无效指针。
- >**对无效指针的操作均会引发错误,第二种和第三种虽为有效的,但理论上是不被允许的**
- 指针访问对象: `cout << *p;`输出p指针所指对象的数据 `*`是**解引用符**。
-`&``*`这样的符号,既能用作表达式里的运算符,也能作为声明的一部分出现,符号的上下文决定了符号的意义。
```cpp
int i = 42;
int &r = i; // & 紧随类型名出现因此是声明的一部分r是一个引用
int *p; // * 紧随类型名出现因此是声明的一部分p是一个指针
p = &i; // & 出现在表达式中,是一个取地址符
*p = i; // * 出现在表达式中,是一个解引用符
int &r2 = *p; // &是声明的一部分,*是一个解引用符
```
- 空指针不指向任何对象。使用`int *p=nullptr;`来使用空指针。
- > 指针和引用的区别:引用本身并非一个对象,引用定义后就不能绑定到其他的对象了;指针并没有此限制,相当于变量一样使用。
- > 赋值语句永远改变的是**左侧**的对象。
- `void*`指针可以存放**任意**对象的地址。因无类型,仅操作内存空间,对所存对象无法访问。
- 其他指针类型必须要与所指对象**严格匹配**。
- 两个指针相减的类型是`ptrdiff_t`
- 建议:初始化所有指针。
- `int* p1, p2;//*是对p1的修饰所以p2还是int型`
## const限定符
- 动机:希望定义一些不能被改变值的变量。
### 初始化和const
- `const` 对象**必须初始化**,且**不能被改变**。
- `const` 变量默认不能被其他文件访问,非要访问,必须在指定 `const` 定义之前加 `extern` 。要想在多个文件中使用const变量共享定义和声明都加 `extern` 关键字即可。
### const的引用
- **reference to const**对常量的引用指向const对象的引用`const int ival=1; const int &refVal = ival;`,可以读取但不能修改`refVal`
- **临时量**temporary对象当编译器需要一个空间来暂存表达式的求值结果时临时创建的一个未命名的对象。
- 对临时量的引用是非法行为。
### 指针和const
- **pointer to const**(指向常量的指针):不能用于改变其所指对象的值, 如 `const double pi = 3.14; const double *cptr = &pi;`
- **const pointer**:指针本身是常量,也就是说指针固定指向该对象,(存放在指针中的地址不变,地址所对应的那个对象值可以修改)如 `int i = 0; int *const ptr = &i;`
### 顶层const
- `顶层const`:指针本身是个常量。
- `底层const`指针指向的对象是个常量。拷贝时严格要求相同的底层const资格。
### `constexpr`和常量表达式(▲可选)
- 常量表达式:指值不会改变,且在编译过程中就能得到计算结果的表达式。
- `C++11`新标准规定,允许将变量声明为`constexpr`类型以便由编译器来验证变量的值是否是一个常量的表达式。
## 处理类型
### 类型别名
- 传统别名:使用**typedef**来定义类型的同义词。 `typedef double wages;`
- 新标准别名别名声明alias declaration `using SI = Sales_item;`C++11
```cpp
// 对于复合类型(指针等)不能代回原式来进行理解
typedef char *pstring; // pstring是char*的别名
const pstring cstr = 0; // 指向char的常量指针
// 如改写为const char *cstr = 0;不正确为指向const char的指针
// 辅助理解(可代回后加括号)
// const pstring cstr = 0;代回后const (char *) cstr = 0;
// const char *cstr = 0;即为(const char *) cstr = 0;
```
### auto类型说明符 c++11
- **auto**类型说明符:让编译器**自动推断类型**。
- 一条声明语句只能有一个数据类型所以一个auto声明多个变量时只能相同的变量类型(包括复杂类型&和*)。`auto sz = 0, pi =3.14//错误`
- `int i = 0, &r = i; auto a = r;` 推断`a`的类型是`int`
- 会忽略`顶层const`
- `const int ci = 1; const auto f = ci;`推断类型是`int`如果希望是顶层const需要自己加`const`
### decltype类型指示符
- 从表达式的类型推断出要定义的变量的类型。
- **decltype**:选择并返回操作数的**数据类型**。
- `decltype(f()) sum = x;` 推断`sum`的类型是函数`f`的返回类型。
- 不会忽略`顶层const`
- 如果对变量加括号编译器会将其认为是一个表达式如int i-->(i),则decltype((i))得到结果为int&引用。
- 赋值是会产生引用的一类典型表达式,引用的类型就是左值的类型。也就是说,如果 i 是 int则表达式 i=x 的类型是 int&
- decltype((variable))(双层括号)的结果永远是引用而decltype(variable)的结果只有当 **variable** 本身是一个引用时才是引用
## 自定义数据结构
### struct
> 尽量不要把类定义和对象定义放在一起。如`struct Student{} xiaoming,xiaofang;`
- 类可以以关键字`struct`开始,紧跟类名和类体。
- 类数据成员:类体定义类的成员。
- `C++11`:可以为类数据成员提供一个**类内初始值**in-class initializer
### 编写自己的头文件
- 头文件通常包含哪些只能被定义一次的实体:类、`const``constexpr`变量。
预处理器概述:
- **预处理器**preprocessor确保头文件多次包含仍能安全工作。
- 当预处理器看到`#include`标记时,会用指定的头文件内容代替`#include`
- **头文件保护符**header guard头文件保护符依赖于预处理变量的状态已定义和未定义。
- `#indef`已定义时为真
- `#inndef`未定义时为真
- 头文件保护符的名称需要唯一,且保持全部大写。养成良好习惯,不论是否该头文件被包含,要加保护符。
```cpp
#ifndef SALES_DATA_H //SALES_DATA_H未定义时为真
#define SALES_DATA_H
strct Sale_data{
...
}
#endif
```