第 12 章 存储类别、链接和内存管理

一、作用域

1.1 块作用域

定义在块内的变量具有块作用域,块是用一对花括号括起来的代码区域。

1.2 函数作用域

函数作用域仅用于 goto 语句的标签。

1.3 函数原型作用域

函数原型作用域的范围是从形参定义到原型声明结束。这意味着,编译器在处理函数原型中的形参时只关心它的类型,二形参名通常无关紧要。而且,即使有形参名,也不必与函数定义中的形参名匹配。只有在变长数组中,形参名才有用。如:void use_a_VLA (int n, int m, ar[n] [m])

1.4 文件作用域

变量的定义在函数的外面,具有文件作用域。 这样的变量可用于多个函数,所以又称为全局变量。

1.5 翻译单元

​ C 预处理器实际上是用包含的头文件内容替换 #include 指令。所以,编译器源代码和所有的头文件都看成是一个包含信息的单独文件,这个文件被称为翻译单元。

二、链接

2.1 无链接

具有块作用域、函数作用域或函数原型作用域的变量都是无链接变量。

2.2 链接

具有文件作用域的变量可以是外部链接或内部链接。

2.2.1 内部链接

​ 内部链接变量只能在一个翻译单元中使用,内部链接的文件作用域又称为 “文件作用域”。

2.2.2 外部链接

​ 外部链接变量可以在多个文件中使用,外部链接的文件作用域又称为 ”全局作用域“ 或 ”程序作用域“。

三、存储期

3.1 自动存储期

​ **块作用域的变量通常都具有自动存储期。**当程序进入定义这些变量的块时,为这些变量分配内存,当退出这个块时,释放刚才为变量分配的内存。

3.2 静态存储期

文件作用域变量具有静态存储期。

​ 注:static 关键字表明了其链接属性,而非存储期。有 static 关键字的是内部链接。

3.3 线程存储期

具有线程存储期的对象,从被声明到线程结束一直存在。

3.4 动态分配存储期

使用内存分配函数分配的变量。

四、存储类别

4.1 概述

存储类别 存储期 作用域 链接 声明方式
自动 自动 块内
寄存器 自动 块内、使用关键字 register
静态外部链接 静态 文件 外部 所有函数外
静态内部链接 静态 文件 内部 所有函数外,使用关键字 static
静态无链接 静态 快内,使用关键字 static

4.2 特性

4.2.1 寄存器变量

​ 寄存器变量与自动变量相比,它存储在了最快的可用内存中。由于寄存器变量存在了寄存器而非内存中, 所以无法获取寄存器变量的地址。

​ 可声明为 register 的变量类型有限,因为寄存器可能没有足够大的空间来存储 64 位的变量。

4.2.2 静态变量

​ 静态变量是指在内存中原地不动,而不是它的值不变。

​ 静态变量有块静态变量、外部链接的静态变量、内部链接的静态变量。

​ 例:

#include <stdio.h>

int staticdemo(void);

int main(void)
{
        int i;

        for(i = 0; i < 10; i++)
                printf("%d ", staticdemo());	//调用声明静态变量的函数
		
   		 /*运行结果
		1 2 3 4 5 6 7 8 9 10 
		*/
        return 0;
}

int staticdemo(void)
{
        static int demo = 0;	//声明静态变量

        return ++demo;
}

分析结果:

​ 在第一次调用函数 staticdemo() 时声明静态变量并初始化为 0,之后再调用该函数,就不会对 demo 进行初始化,因为可以直接使用那个内存位置的量。

4.2.3 外部链接的静态变量

​ 如果一个源代码文件使用的外部变量定义在另一个源代码文件中,则必须使用 extern 再该文件中声明该变量。

/*file1.c*/
int exVal = 100;
int exVal2 = 200;

/*file2.c*/
#include <stdio.h>
#include "file1.c"
int main(void)
{
        extern int exVal;
    	int exVal2 = 50
        printf("exVal = %d \n", exVal);
        printf("exVal2 = %d \n", exVal2);

        return 0;
}

/*运行结果
exVal = 100
exVal2 = 50
*/

分析结果:

​ exVal 使用了 extern 关键字,所以输出是 file1.c 中定义的值,而 exVal2 并未使用 extern 关键字, 所以是 输出的是 file2.c 中定义的值。

第一次声明称为定义式声明,第二次声明称为引用式声明,只有定义式声明才能初始化变量。

4.2.4 内部连接的静态变量

​ 普通的外部变量可用于统一程序中的任意文件的函数,但内部链接的静态变量只能用于同一个文件中的函数。

例:

#include <stdio.h>

static int a = 100;

int main(void)
{
        printf("static val a = %d \n", a);

        return 0;
}
/*输出结果
static val a = 100
*/

4.2.5 动态存储变量

​ C可以在程序运行时分配更多的内存(如变长数组),我们也可以使用 malloc() 函数分配内存。malloc() 返回动态分配内存块的首字节地址。因此,可以把该地址赋给一个指针,并使用指针访问这块内存。因为 char 表示一字节,malloc() 的返回类型通常被定义为指向 char 的指针,然后使用强制类型转换转成想要的类型。

​ 例:

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
	int i = 0;
	double * ptd = (double *) malloc(5 * sizeof(double));      //声明 5 个空间的double数组
	int * pti = (int *) malloc(3 * sizeof(int));           //声明 10 个长度的int数组

	printf("enter 5 num to assign double arry: \n");
	while (i < 5 && scanf_s("%lf", &ptd[i]) == 1)		//获取 double 输入
		i++;
	printf("here are double arry: \n");
	for (i = 0; i < 5; i++)		//输出
		printf("%7.2f", ptd[i]);
	printf("\n");
    free(ptd);

	i = 0;
	printf("enter 3 num to assign int arry: \n");
	while (i < 3 && scanf_s("%d", &pti[i]) == 1)		//获取 int 输入
		i++;
	printf("here are int arry: \n");
	for (i = 0; i < 3; i++)		//输出
		printf("%d ", pti[i]);
    free(pti);

	return 0;
}

/*运行结果
enter 5 num to assign double arry:
9 10 4.4 8.9 10
here are double arry:
	9.00  10.00   4.40   8.90  10.00
enter 3 num to assign int arry:
4 9 10
here are int arry:
4 9 10
*/

参考书籍

C Primer Plus (第六版)中文版

发布了42 篇原创文章 · 获赞 3 · 访问量 2088

猜你喜欢

转载自blog.csdn.net/stable_zl/article/details/104094609