储存类别

自动储存区

  自动储存区中只储存自动变量,自动变量通常是局部变量,函数的形参也视为局部变量;auto用于修饰自动变量,局部变量在不加任何修饰的情况下默认就是自动变量(形参无法被修饰),所以没有任何修饰的局部变量默认就是自动变量,和函数形参一起储存在自动储存区

  自动存储区中的变量在它的作用域(函数或者代码块)被执行时创建、分配内存,在创建时如果没有初始化,变量的值将是未定义的,自动存储区中的变量只在作用域内可见和可用,作用域结束时销毁

  如下代码中,test函数的形参num和函数中的num2都储存在自动储存区,函数test就是它们的作用域,当作用域结束时,numnum2都被销毁

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main() {

// 这里 num2 已经被销毁,目前 num2_pointer 是空指针
int* num2_pointer = test(10);

// num2_pointer 此时为空指针,将会进入 if
if (num2_pointer == NULL) {
printf("num2已被销毁");
} else {
printf("num2 = %d\n", *num2_pointer);
}

return 0;
}

int* test(int num) {
printf("num = %d\n", num);

// num2 在 test 函数运行结束后会被销毁
int num2 = 10;

// num2 被销毁后它的指针就成了空指针
return (&num2);
}

静态储存区

  静态储存区中存放所有全局变量静态变量(局部静态变量和全局静态变量)const修饰的常量(普通常量和静态常量);静态储存区中的数据在程序启动时就被分配空间,并在程序结束时才被释放,静态存储区的数据是在程序运行期间一直存在的,与函数的调用和返回无关

  静态局部变量的空间分配和赋初始值是在程序第一次进入声明这个变量的函数时,所以后续调用函数时不再为其分配空间和赋初始值。静态局部变量的生命周期贯穿整个程序运行期间,而不是只在函数调用时存在。

  如下代码说明了static修饰的静态局部变量不会在函数执行结束后被销毁,并且说明了只有程序第一次进入声明这个静态局部变量的函数时才会为其分配空间和赋初始值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
int main() {
// 第一次调用 test 函数
int* num_pointer = test();
// 将会输出 11,说明 num_pointer 不是空指针,函数中的 num 变量没有被销毁
printf("num = %d\n", *num_pointer);

// 第二次调用 test 函数
num_pointer = test();
// 将会输出 12,num 不会再被分配空间和赋初始值,只执行了自加
printf("num = %d\n", *num_pointer);

return 0;
}

int* test() {
// 只在第一次进入 test 函数时为 num 分配空间,赋初始值
static int num = 10;

// 自加
num++;

// 将 num 的内存地址 return 出去
// test 执行完毕后如果 num 被销毁,那么内存地址将会为空
return (&num);
}

动态储存区

  在C语言中,动态存储区主要负责存储程序运行时动态分配的内存,这部分内存的生命周期不是由编译器决定的,而是由程序员在运行时显式地管理。动态存储区包括堆(heap)和栈(stack)两个部分

  堆(Heap):堆是用于存储动态分配的内存的区域。在堆上分配的内存需要手动释放,否则可能导致内存泄漏。C语言中,通过malloccallocrealloc等函数来在堆上分配内存,通过free函数来释放堆上的内存
  栈(Stack):栈是用于存储函数参数和局部变量的内存的区域。栈上的内存由系统自动管理,它在函数调用时被分配,函数结束时自动释放。栈上的内存生命周期短暂,通常与函数的执行周期相关

1
2
3
4
5
6
7
8
9
10
int main() {

// 在堆上分配一个包含5个整数的数组
int *arr = (int *)malloc(5 * sizeof(int));

// 释放在堆上分配的内存
free(arr);

return 0;
}

寄存器储存区

  寄存器储存区用于指示编译器将变量存储在寄存器中,而不是存储在内存中。寄存器是CPU内部的高速存储器,访问速度比内存快。需要注意的是虽然C语言提供了register关键字,允许程序员建议编译器将某个变量存储在寄存器中,但实际上编译器并不一定会遵循这个建议。

  寄存器储存区主要用于频繁访问的变量,以提高程序的执行速度。由于寄存器数量有限,不是所有变量都能存储在寄存器中。编译器会根据程序的需求和架构的特性来决定是否将变量存储在寄存器中。寄存器储存区中的变量用于临时存储,程序员不能直接对寄存器进行地址操作,因为寄存器没有地址。

  随着编译器优化的发展,现代编译器能够自动分配寄存器