2024年10月8日 16:36

This commit is contained in:
许大仙 2024-10-08 08:36:17 +00:00
parent 3067a36245
commit a9762cb7cb

View File

@ -1795,15 +1795,15 @@ int main() {
| 类别 | 作用域 | | 类别 | 作用域 |
| -------- | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ |
| 局部变量 | 局部变量的生存周期仅限于定义它们的函数或代码块的执行时间<br>它们在函数或代码块执行结束后会被销毁。 | | 局部变量 | 局部变量的生存周期仅限于定义它们的函数或代码块。<br>它们在函数或代码块执行结束后会被销毁。 |
| 全局变量 | 全局变量的生命周期从程序开始运行直到程序结束。 <br/>它们在程序整个运行期间都存在。 | | 全局变量 | 全局变量的生命周期从程序开始运行直到程序结束。 <br/>它们在程序整个运行期间都存在。 |
* 初始值对比: * 初始值对比:
| 类别 | 作用域 | | 类别 | 作用域 |
| -------- | ------------------------------------------------------------ | | -------- | ------------------------------------------------------------ |
| 局部变量 | 系统不会对其默认初始化,必须对局部变量初始化后 才能使用。<br>否则,程序运行后可能会异常退出。 | | 局部变量 | 系统不会对其默认初始化,必须对局部变量初始化后才能使用。<br>否则,程序运行后可能会异常退出。 |
| 全局变量 | 如果没有显式初始化,它们会被自动、默认初始化为 零或空值,具体取决于数据类型。<br>int 类型的默认初始化值是 0 。<br>char 类型的默认初始化值是 '\0' 或 0 。<br>float 类型的默认初始化值是 0.0f 。<br/>double 类型的默认初始化值是 0.0 。<br/>指针的默认初始化值是 NULL 或 nullptr 。 | | 全局变量 | 如果没有显式初始化,它们会被自动、默认初始化为零或空值,具体取决于数据类型。<br>int 类型的默认初始化值是 0 。<br>char 类型的默认初始化值是 '\0' 或 0 。<br>float 类型的默认初始化值是 0.0f 。<br/>double 类型的默认初始化值是 0.0 。<br/>指针的默认初始化值是 NULL 或 nullptr 。 |
* 内存中的位置对比: * 内存中的位置对比:
@ -1834,10 +1834,10 @@ int main() {
* 动态存储方式:在程序运行期间根据需要进行`动态的分配存储空间`的方式,数据存放在`动态存储区` ,即:`栈`。 * 动态存储方式:在程序运行期间根据需要进行`动态的分配存储空间`的方式,数据存放在`动态存储区` ,即:`栈`。
* 在动态存储区中存放以下数据: * 在动态存储区中存放以下数据:
* 函数形参:在调用函数时给形参分配存储空间。 * 函数形参:在调用函数时给形参分配存储空间。
* 函数中定义的局部变量且没有用关键字 static 声明的变量,即自动变量。 * 函数中定义的局部变量且没有用关键字 `static` 声明的变量,即自动变量。
* 函数调用时的返回地址等。 * 函数调用时的返回地址等。
* 在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。 自动变量用关键字 auto 作存储类别的声明。 * 在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。因此这类局部变量称为自动变量。 自动变量用关键字 `auto`存储类别的声明。
* 语法: * 语法:
```c ```c
@ -1917,11 +1917,155 @@ int main() {
} }
``` ```
## 3.3 其它变量修饰符(了解) ## 3.3 其它变量修饰符(了解)
### 3.3.1 寄存器变量register 变量)
* 一般情况下,变量(包括静态存储方式和动态存储方式)的值是存放在内存中的。当程序中用到哪一个变量的值时,由控制器发出指令将内存中该变量的值送到运算器中。经过运算器进行运算,如果需要存数,再从运算器将数据送到内存存放。
* 如果有一些变量使用频繁(例如,在一个函数中执行 10 000 次循 环每次循环中都要引用某局部变量则为存取变量的值要花费不少时间。为提高执行效率C 语言允许将局部变量的值放在 CPU 中的寄存器中,需要用时直接从寄存器取出参加运算,不必再到内存中去存取。由于对寄存器的存取速度远高于对内存的存取速度,因此这 样做可以提高执行效率。这种变量叫做寄存器变量,用关键字`register`作声明。
* 语法:
```c
register 数据类型 变量 = 初始化值;
```
> [!NOTE]
>
> * ① 由于现在的计算机的速度愈来愈快,性能愈来愈高, 优化的编译系统能够识别使用频繁的变量,从而自动地将这些变量放在寄存器中,而不需要程序设计者指定。
> * ② 因此,现在实际上用 register 声明变量的必要性不大。
### 3.3.2 const 修饰变量
#### 3.3.2.1 概述
* 在 C 语言中, const 关键字用于创建常量,它指示编译器将标识符 (变量、参数、函数等)视为不可修改的值。
#### 3.3.2.2 常量声明
* 如果一个变量使用 const 修饰,就变为常量,语法如下:
```c
const int MAX_NUM = 100;
```
* 常量一旦被创建后其值就不能再改变,必须在定义的同时赋值(初始化),后面的任何赋值行为都将引发错误。
> [!TIP]
>
> 通常而言,常量名建议使用大驼峰的形式表示,如:`MAX_VALUE`,以便和普通的局部变量区分。
* 示例:
```c {11}
#include <stdio.h>
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, nullptr);
const double PI = 3.14;
// 错误,不能修改常量
PI = 3.1415; // [!code error]
return 0;
}
```
#### 3.3.2.3 指向常量的指针
* const 也可以和指针变量一起使用这样可以限制指针变量本身也可以限制指针指向的数据。const 和指针一起使用会有几种不同的顺序,如下所示:
```c
const int *p1;
```
```c
int const *p2;
```
```c
int * const p3;
```
> [!IMPORTANT]
>
> 技巧:
>
> * ① const 离变量名近,就是用来修饰指针变量的,即:`const` 在 `*` 号之后,表示 **指针本身不能改变,但指向的值可以改变**
> * ② const 离变量名远,就是用来修饰指针指向的数据,即: `const` 在 `*` 号之前,表示 **指向的值不能修改,但是指针本身可以修改**
* 示例:
```c
#include <stdio.h>
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, nullptr);
const int a = 10;
const int b = 20;
const int *p1 = &a;
// 错误,不能通过 p1 修改 a 的值
*p1 = 30; // [!code error]
p1 = &b; // 合法:可以让 p1 指向 b
return 0;
}
```
* 示例:
```c
#include <stdio.h>
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, nullptr);
const int a = 10;
const int b = 20;
int const *p2 = &a;
// 错误,不能通过 p2 修改 a 的值
*p2 = 30; // [!code error]
p2 = &b; // 合法:可以让 p2 指向 b
return 0;
}
```
* 示例:
```c
#include <stdio.h>
int main() {
// 禁用 stdout 缓冲区
setbuf(stdout, nullptr);
const int a = 10;
const int b = 20;
int *const p3 = &a;
// 错误,不能通过 p3 的指向
p3 = &b; // [!code error]
*p3 = 30; // 合法:可以修改 a 的值
return 0;
}
```