This commit is contained in:
许大仙 2024-08-28 09:38:54 +08:00
parent 1b72a9d176
commit 236cb5557e
5 changed files with 12 additions and 162 deletions

View File

@ -66,7 +66,7 @@
| unsigned long long无符号长整型 | 8 字节(通常) | 0 ~2^64 -1 |
| [signed] long long有符号长整型默认 | 8 字节(通常) | - 2^63 ~ 2^63-1 |
> [!IMPORTANT]
> [!NOTE]
>
> * ① 数据类型在内存中占用的存储单元字节数就称为该数据类型的长度步长short 占用 2 个字节的内存,就称 short 的长度(步长)是 2。
>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -13,7 +13,7 @@
> [!NOTE]
>
> 之所以指针在 C 语言中颇具争议,是因为一方面其功能强大,直接操作内存地址;另一方面,又很危险,不正确的使用指针的方式,非常容易导致程序崩溃。
> 之所以指针在 C 语言中颇具争议,是因为一方面其功能强大,直接操作内存地址;另一方面,又很危险,不正确的使用指针,非常容易导致程序崩溃。
* 如果没有能很好的使用指针,就会带来一系列的问题,如:
* ① `空指针引用`Null Pointer Dereference当一个指针没有正确初始化或者被赋予了空NULL值时如果程序尝试访问该指针所指向的内存会导致运行时错误甚至导致程序崩溃。
@ -53,164 +53,14 @@
> [!IMPORTANT]
>
> 总而言之,各种编程语言通过引入不同的策略和机制,如:智能指针、垃圾回收器、所有权和借用,以及强类型系统,有效地减少了指针操作所带来的各种安全性和可靠性问题,提升了程序的稳定性和开发效率。
> * ① 总而言之,现代化的高级编程语言通过引入不同的策略和机制,如:智能指针、垃圾回收器、所有权和借用,以及强类型系统,有效地减少了指针操作所带来的各种安全性和可靠性问题,提升了程序的稳定性和开发效率。
> * ② 换言之现代化的高级编程语言就是在某些方面性能运行效率、底层控制隐藏了许多底层实现细节以防止程序员意外地引入安全漏洞和平台特定优化屏蔽底层硬件细节CPU 寄存器、具体的内存布局,以达到跨平台的目的,这也限制了程序员对底层优化的控制),做出一定的牺牲,以换取开发效率以及程序的稳定性。
# 第二章:回顾知识
# 第二章:指针的理解和定义(⭐)
## 2.1 变量
* 变量就是保存程序运行过程中临时产生的值,其语法如下:
```c
数据类型 变量名 = 值 ;
```
> [!IMPORTANT]
>
> 变量名(标识符)需要符合命名规则和命名规范!!!
>
> * 强制规范:
> - ① 只能由`小写`或`大写英文字母``0-9` 或 `_` 组成。
> - ② 不能以`数字`开头。
> - ③ 不可以是`关键字`。
> - ④ 标识符具有`长度`限制,不同编译器和平台会有所不同,一般限制在 63 个字符内。
> - ⑤ 严格`区分大小写字母`Hello、hello 是不同的标识符。
> * 建议规范:
> - ① 为了提高阅读性使用有意义的单词见名知意sumnamemaxyear 等。
> - ② 使用下划线连接多个单词组成的标识符max_classes_per_student 等。
> - ③ 多个单词组成的标识符,除了使用下划线连接,也可以使用小驼峰命名法,除第一个单词外,后续单词的首字母大写,如: studentId、student_name 等。
> - ④ 不要出现仅靠大小写区分不同的标识符name、Name 容易混淆。
> - ⑤ 系统内部使用了一些下划线开头的标识符C99 标准添加的类型 `_Bool`,为防止冲突,建议开发者尽量避免使用下划线开头的标识符。
* `变量名`的`作用`,如下所示:
* ① 当我们`编写`代码的时候,使用`变量名`来`关联`某块内存的`地址`。
* ② 当 CPU `执行`的时候,会将变量名`替换`为具体的地址,再进行具体的操作。
## 2.2 普通变量和指针变量的区别
* 根据`变量`中`存储`的`值`的`不同`,我们可以将`变量`分为两类:
- `普通变量`:变量所对应的内存中存储的是`普通值`。
- `指针变量`:变量所对应的内存中存储的是`另一个变量的地址`。
* 如下图所示:
![img](./assets/1.png)
* 普通变量和指针变量的相同点,如下所示:
* ① 普通变量有内存空间,指针变量也有内存空间。
* ② 普通变量有内存地址,指针变量也有内存地址。
* ③ 普通变量所对应的内存空间中有值,指针变量所对应的内存空间中也有值。
* 普通变量和指针变量的不同点:
- ① `普通变量`所对应的内存空间`存储`的是`普通的值`,如:整数、小数、字符等;`指针变量`所对应的内存空间`存储`的是另外一个变量的`地址`。
- ② `普通变量有普通变量的运算方式`,而`指针变量有指针变量的运算方式`(后续讲解)。
## 2.3 运算符
### 2.3.1 概述
* 运算符是一种特殊的符号,用于数据的运算、赋值和比较等。
* `表达式`指的是一组运算数、运算符的组合,表达式`一定具有值`,一个变量或一个常量可以是表达式,变量、常量和运算符也可以组成表达式,如:
![img](./assets/2.png)
- `操作数`指的是`参与运算`的`值`或者`对象`,如:
![](./assets/3.png)
* 根据`操作数`的`个数`,可以将运算符分为:
* 一元运算符(一目运算符)。
* 二元运算符(二目运算符)。
* 三元运算符(三目运算符)。
* 根据`功能`,可以将运算符分为:
* 算术运算符。
* 关系运算符(比较运算符)。
* 逻辑运算符。
* 赋值运算符。
* 逻辑运算符。
* 位运算符。
* 三元运算符。
> [!NOTE]
>
> 掌握一个运算符,需要关注以下几个方面:
>
> - ① 运算符的含义。
> - ② 运算符操作数的个数。
> - ③ 运算符所组成的表达式。
> - ④ 运算符有无副作用,即:运算后是否会修改操作数的值。
> [!IMPORTANT]
>
> 普通变量支持上述的所有运算符;而指针变量并非支持上述的所有运算符,且支持运算符的含义和普通变量相差较大!!!
### 2.3.2 运算符的优先级
* C 语言中运算符的优先级,如下所示:
| **优先级** | **运算符** | **名称或含义** | **结合方向** |
| ---------- | ---------- | ---------------- | ------------- |
| **1** | `[]` | 数组下标 | ➡️(从左到右) |
| | `()` | 圆括号 | |
| | `.` | 成员选择(对象) | |
| | `->` | 成员选择(指针) | |
| **2** | `-` | 负号运算符 | ⬅️(从右到左) |
| | `(类型)` | 强制类型转换 | |
| | `++` | 自增运算符 | |
| | `--` | 自减运算符 | |
| | `*` | 取值运算符 | |
| | `&` | 取地址运算符 | |
| | `!` | 逻辑非运算符 | |
| | `~` | 按位取反运算符 | |
| | `sizeof` | 长度运算符 | |
| **3** | `/` | 除 | ➡️(从左到右) |
| | `*` | 乘 | |
| | `%` | 余数(取模) | |
| **4** | `+` | 加 | ➡️(从左到右) |
| | `-` | 减 | |
| **5** | `<<` | 左移 | ➡️(从左到右) |
| | `>>` | 右移 | |
| **6** | `>` | 大于 | ➡️(从左到右) |
| | `>=` | 大于等于 | |
| | `<` | 小于 | |
| | `<=` | 小于等于 | |
| **7** | `==` | 等于 | ➡️(从左到右) |
| | `!=` | 不等于 | |
| **8** | `&` | 按位与 | ➡️(从左到右) |
| **9** | `^` | 按位异或 | ➡️(从左到右) |
| **10** | `\|` | 按位或 | ➡️(从左到右) |
| **11** | `&&` | 逻辑与 | ➡️(从左到右) |
| **12** | `\|\|` | 逻辑或 | ➡️(从左到右) |
| **13** | `?:` | 条件运算符 | ⬅️(从右到左) |
| **14** | `=` | 赋值运算符 | ⬅️(从右到左) |
| | `/=` | 除后赋值 | |
| | `*=` | 乘后赋值 | |
| | `%=` | 取模后赋值 | |
| | `+=` | 加后赋值 | |
| | `-=` | 减后赋值 | |
| | `<<=` | 左移后赋值 | |
| | `>>=` | 右移后赋值 | |
| | `&=` | 按位与后赋值 | |
| | `^=` | 按位异或后赋值 | |
| | `\|=` | 按位或后赋值 | |
| **15** | `,` | 逗号运算符 | ➡️(从左到右) |
> [!WARNING]
>
> * ① 不要过多的依赖运算符的优先级来控制表达式的执行顺序,这样可读性太差,尽量`使用小括号来控制`表达式的执行顺序。
> * ② 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它`分成几步`来完成。
> * ③ 运算符优先级不用刻意地去记忆,总体上:一元运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 三元运算符 > 赋值运算符。
> [!IMPORTANT]
>
> * ① 取值运算符 `*` 和取地址运算符 `&` 的优先级相同,并且运算方向都是从右向左!!!
> * ② 逗号运算符 `,` 的优先级最低,并且运算方向是从左向右!!!
# 第三章:指针的理解和定义(⭐)
## 3.1 变量的访问方式
## 2.1 变量的访问方式
* 计算机中程序的运行都是在内存中进行的变量也是内存中分配的空间且不同类型的变量占据的内存空间大小不同char 类型的变量是 1 个字节short 类型的变量是 2 个字节int 类型的变量是 4 个字节...
* 之前我们都是通过`变量名(普通变量)`访问内存中存储的数据,如下所示:
@ -243,7 +93,7 @@ int main() {
> * ① 我们通过`变量名(普通变量)`访问内存中变量存储的数据,之所以称为`直接访问`的方式,是因为对于我们写程序而言,我们无需关心如何根据内存地址去获取内存中对应的数据,也无需关系如何根据内存地址将数据存储到对应的内存空间,这些操作步骤都是`编译器`帮助我们在底层自动完成的(自动化)。
> * ② 但是,我们也可以通过`内存地址`去操作内存中对应的数据(手动化),这种方式就称为`间接访问`的方式了,相对于`直接访问`方式来说,要`理解`的`概念`和`操作`的`步骤`和之前`直接访问`的方式相比,要复杂和麻烦很多,但是效率高。
## 3.2 内存地址和指针
## 2.2 内存地址和指针
* 其实,在之前《数组》中,我们就已经讲解了`内存地址`的概念了,即:操作系统为了更快的去管理内存中的数据,会将`内存条`按照`字节`划分为一个个的`单元格`,并为每个独立的小的`单元格`,分配`唯一的编号`,即:`内存地址`,如下所示:
@ -302,13 +152,13 @@ int main() {
>
> 如果你观察仔细的话,你可能会发现`指针变量`和`普通变量`在内存中占据的存储空间是不一样的,那么到底是什么原因造成这样的结果?
## 3.3 指针变量的定义
## 2.3 指针变量的定义
## 3.4 指针的作用
## 2.4 指针的作用
* 查询数据。
* 存储数据。
@ -404,15 +254,15 @@ int main() {
# 第章:指针的运算(⭐)
# 第章:指针的运算(⭐)
## 4.1 概述
## 3.1 概述
## 4.2 总结
## 3.2 总结
* 在 C 语言中,`普通变量`是直接存储`数据`的`变量`。对于普通变量,支持的操作包括:
* ① **赋值操作**:给变量赋值,如:`int a = 5`。