存储类别,链接和内存管理

存储类别,链接和内存管理

1,作用域:

根据作用域可分为块作用域,函数作用域,函数原型作用域,文件作用域。

块作用域:在{}之间都一个属于块作用域。块里面定义的变量,作用范围是从定义处到包含该定义的块的末尾。
函数作用域:
函数原型作用域:函数原型作用域是从形参定义处到原型声明结束,
int mighty(int mouse,double large);//里面的mouse,large都属于函数原型作用域
文件作用域:变量的定义在函数外面,具有文件作用域,作用域为:从它定义处到该定义所在文件的末尾

2,链接:

链接主要分为:外部链接,内部链接,无链接;

  无链接:具有块作用域,函数作用域或函数原型作用域的变量都是无链接变量。这意味着这些变量属于定义它们的块,函数或原型私有。
  内部链接:内部链接变量即在该文件内部使用。使用static进行修饰,一旦变量使用static修饰后,外部文件将无法访问,只有文件内部才能够进行访问。
  外部链接:外部链接就是跨文件访问,使用extern进行修饰,一般出现在多文件程序中。

3,存储期:

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

4,变量:

自动变量:

属于自动存储类别的变量具有自动存储期,块作用且无链接。默认情况下,
声明在函数头中的任何变量都属于自动存储类别。

int loop(int a)
{
	int m;//m的作用域
	scanf("%d",&m);
	{
		int i;//m和i的作用域
		for(i=m;i<n;i++)
			puts("i is local to a sub-block\n") 
	 } 
	 return m;//m作用域,i作用域已消失 
}

寄存器变量:

寄存器变量是储存在CPU的寄存器上,这样的变量访问速度快,因储存在寄存器上,所以无法获取其地址,通常要申请这样的变量要使用关键字register
即:register int n;

块作用域的静态变量:

  静态的意思是变量在内存中原地不动,并不是说它的值不变。具有文件作用域的变量自动具有静态存储期。前面提到过,可以创建具有静态存储期、块作用域的局部变量。这些变量和自动变量一样,具有相同的作用域,但是程序离开它们所在的函数后,这些变量不会消失。也就是说,这种变量具有块作用域、无链接,但是具有静态存储期。计算机在多次函数调用之间会记录它们的值。在块中(提供块作用域和无链接)以存储类别说明符 static(提供静态存储期)声明这种变量。

/** 使用局部静态变量 */
#include <stdio.h>
void trystat(void);
int main()
{
    int count;
    for(count = 1; count <= 3; count++)
    {
        printf("Here comes iteration %d:\n",count);
        trystat();
    }

    return 0;
}

void trystat(void)
{
    int fade = 1;
    static int stay = 1;
    printf("fade = %d and  stay = %d\n",fade++,stay++);
}

该程序的输出如下:
Here comes iteration 1:
fade = 1 and stay = 1
Here comes iteration 2:
fade = 1 and stay = 2
Here comes iteration 3:
fade = 1 and stay = 3

静态变量只在编译时初始化一次;

不能在函数参数中用static

外部链接的静态变量:

外部链接的静态变量具有文件作用域、外部链接和静态存储期。该类别有时称为外部存储类别,属于该类别的变量称为外部变量。把变量的定义性声明放在在所有函数的外面便创建了外部变量。当然,为了指出该函数使用了外部变量,可以在函数中用关键字 extern 再次声明。如果一个源代码文件使用的外部变量定义在另一个源代码文件中,则必须用 extern 在该文件中声明该变量

#include <stdio.h>
int Errupt; /* 外部定义的变量 */
double Up[100]; /* 外部定义的数组 */
extern char Coal; /* 如果 Coal 被定义在另一文件,则必须这样声明 */
void next(void);
int main()
{
    extern int Errupt; /* 可选的声明 */
    extern double Up[]; /* 可选的声明 */

    return 0;
}

void next(void)
{
    ...
}

初始化外部变量时不能用变量初始化:int x=2*n
文件中任意函数均可使用外部变量;其他文件使用时必须用关键字extern
来引用定义

内部链接的静态变量:

该存储类别的变量具有静态存储期、文件作用域和内部链接。在所有函数外部(这点与外部变量相同),用存储类别说明符 static 定义的变量具有这种存储类别。
*它与外部链接的静态变量不同于他只能用于该文件的任意函数

5,存储类别和函数:

函数也有存储类别,可以是外部函数(默认)或静态函数。C99 新增了第 3 种类别——内联函数。外部函数可以被其他文件的函数访问,但是静态函数只能用于其定义所在的文件。假设一个文件中包含了以下函数原型:

double gamma(double); /* 该函数默认为外部函数 */
static double beta(int, int);
extern double delta(double, int);

在同一个程序中,其他文件中的函数可以调用 gamma() 和 delta(),但是不能调用 beta(),因为 static 存储类别说明符创建的函数属于特定模块私有。这样做避免了名称冲突的问题,由于 beta() 受限于它所在的文件,所以在其他文件中可以使用与之同名的函数。

通常的做法是:用 extern 关键字声明定义在其他文件中的函数。这样做是为了表明当前文件中使用的函数被定义在别处。除非使用 static 关键字,否则一般函数声明都默认为 extern。

6,分配内存:malloc()和free()

malloc可以申请内存,它会找到合适的空闲内存块,这样的内存是匿名的,它不同于普通的内存分配,它可以动态分配内存,通常申请内存形式如下:
double pta;
pta=(double
) malloc(30*sizeof(double))
也可以将30改为变量来分配内存;

/** 动态分配数组 */
#include <stdio.h>
#include <stdlib.h> /* 为 malloc()、free() 提供原型 */

int main()
{
    double * ptd;
    int max;
    int number;
    int i = 0;
    puts("What is the maximum number of type double entries?");
    if(scanf("%d", &max) != 1)
    {
        puts("Number not correctly entered -- bye.");
        exit(EXIT_FAILURE);
    }
    ptd = (double *) malloc(max * sizeof(double));
    if(ptd == NULL)
    {
        puts("Memory allocation failed. Goodbye.");
        exit(EXIT_SUCCESS);
    }
    /* ptd 现在指向有 max 个元素的数组 */
    puts("Enter the values (q to quit):");
    while(i < max && scanf("%lf", &ptd[i]) == 1)
        ++i;
    printf("Here are your %d enteries:\n", number = i);
    for(i = 0; i < number; i++)
    {
        printf("%7.2f", ptd[i]);
        if(i % 7 == 6)
            putchar('\h');
    }
    if(i % 7 != 0)
        putchar('\n');
    puts("Done.");
    free(ptd);

    return 0;
}

下面是该程序的运行示例。程序通过交互的方式让用户先确定数组的大小,我们设置数组大小为 5。虽然我们后来输入了 6 个数,但程序也只处理前 5 个数。
What is the maximum number of type double entries?
5
Enter the values (q to quit):
20 30 35 25 40 80
Here are your 5 enteries:
20.00 30.00 35.00 25.00 40.00
Done.

在使用了malloc函数后一定要记得free()
静态内存的数量在编译时是固定的,在程序运行期间也不会改变。自动变量使用的内存数量在程序执行期间自动增加或减少。但是动态分配的内存数量只会增加,除非用 free() 进行释放。

假设有个循环要执行 1000 次,每次分配 16000字节的内存,所以在循环结束时,内存池中有 1600 万字节被占用。实际上,也许在循环结束之前就已耗尽所有内存。这类问题被称为内存泄漏(memory leak)。在函数末尾处调用 free() 函数可避免这类问题发生。

7,const限定符:

const限定符修饰的变量不能改变其值:

const float * p;			//p可以指向别处,p指向的值不能变
float * const p;			//p不可以指向别处,p指向的值可以改变
const float * const p;	//p不可以指向别处,p指向的值不可以改变
const int arr[];			//不能改变arr中的数据
const int * arr;			//同上

2、对全局数据使用 const

使用全局变量是一种冒险的方法,因为这样做暴露了数据,程序的任何部分都能更改数据。如果把数据设置为 const,就可避免这样的危险,因此用 const 限定符声明全局数据很合理。可以创建 const 变量、const 数组和 const 结构。

然而,在文件间共享 const 数据要小心。可以采用两个策略。

第一,遵循外部变量的常用规则,即在一个文件中使用定义式声明,在其他文件中使用引用式声明(用 extern 关键字)
第二,把const变量放在一个头文件中;

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值