C语言:存储类链接和内存管理

Posted 鸿渐之翼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言:存储类链接和内存管理相关的知识,希望对你有一定的参考价值。

博主:鸿渐之翼
个人介绍:一个搞底层的FW,喜欢发一点没用的东西。
在这里插入图片描述

存储类:

作用域:
作用域描述程序中可以访问的一个标识符或多个区域。我们使用的局部变量,包括函数的形式变量,都是代码块作用域。

double A(double b)
{
double j=1;
int i;
for(i=0;i<10;i++)
double k =j+i;//k的作用域开始
...
       j *=k;//k的作用域结束
}
return j;

函数原型作用域(function prototype scope)
适用于函数原型中使用的变量名称:

int A(int a, double b);

链接:
c语言中变量具有以下链接:
外部链接(external linkage),内部链接(internal linkage)
空链接(no linkage)

存储时期:
c变量中两种存储时期:
静态存储时期(static storage duration)
自动存储时期(automantic storage duration)

自动变量:
默认情况下,在代码块或函数的头部定义的任意变量都属于自动存储类。

寄存器变量:
寄存器变量可以被存储在CPU寄存器中。
在这里插入图片描述

因为寄存器变量多放在一个寄存器而非内存中,所以无法获得寄存器变量的地址。
以下声明寄存器变量:

int main(void)
{
register int quick;
}


具有代码块作用域的静态变量
静态变量(static variable)“静态”指的是位置固定不动。
从函数条用到下一次调用,它们并不会消失。
具有外部链接的静态变量
包含了
1.文件作用域2.外部链接3.静态存储时期。
这一类型被称为external storage class

int out;//外部定义的变量
double a[10];//外部定义的数组
extern char a;
int main(void){
    extern int out; //可选择声明
    extern double a[]; //可选择声明
}

out的两次申明是链接的例子。它们都指向同一个变量,外部变量具有外部链接。
具有内部链接的静态变量

static int a=1int main(void{
int a=1//外部链接
statci int b=2; //内部链接
}

在这里插入图片描述

存储类总结

自动变量具有代码块作用域、空链接和自动存储时期,一般是一个函数私有。
寄存器变量和自动变量具有相同的属性,编译器能使用更快的内存或存储器来存储它们,但无法获取一个寄存器变量的地址。
具有静态存储时期的变量可能具有外部链接、内部链接或空链接。
当程序执行到包含变量声明的代码块时,给具有自动存储时期的变量分配内存,并在代码块结束时释放这部分内存。如果没有没有初始化,这样的变量具有一个无效值。具有代码块作用的变量局部包含变量声明的代码块。
example:

#include<stdio.h>
void report_count();
void accumulate(int a);
int count=0;//文件作用域,外部链接
int main(void){
int value;//自动变量
register int i;//寄存器变量
extern int count; //引用声明,外部链接
static int total = 0; //静态定义,内部链接
void accumulate(int k) //函数原型
printf("Enter a positive interger:");
while(scanf("%d",&value)==1 && value>0)
{
++count;//使用文件作用域变量
for(i==value;i>=0;i--)
accumulate(i);
printf("Enter a positive integer;");
}
report_count();
return 0;
}
void report_count()
{
printf("Loop executed %d times\\n",count);
}
void accumulate(int k)
{
 static int subtotal =o; //静态、空链接
 if (k<=0)
 {
 printf("loop cycle: %d\\n",count);
 printf("subtotal:%d total:%d\\n",subtotal,total);
 subtotal=0;
 }
 else
 {
   subtotal +=k;
   total +=k;
 };
}

int count=0;//文件作用域,外部链接
int value;//自动变量
register int i;//寄存器变量
++count;//使用文件作用域变量
extern int count; //引用声明,外部链接
static int total = 0; //静态定义,内部链接
void accumulate(int k) //函数原型

存储类与函数

double a();
static double b();
extern double c();

double a()默认为外部,函数a()与函数c()可以被程序其他文件中的函数使用,b()不能,因为b被限定在一个文件中。
static存储类就是创建一个特定的模版私有的函数。从而避免可能的名字冲突。

在这里插入图片描述

分配内存 malloc()与free()

除了常规的分配内存方式

float a;
char a[] = "aaaaa";
int a[100];

c语言中还有函数malloc(),malloc()分配了内存,但是没有为它制定名字。然而,malloc可以返回内存第一个字节的地址。

double * a;
a = (double *)malloc(20 *sizeof(double));

这段代码请求20个double类型的空间,并且把a指向该空间所在位置。a是作为一个double类型值的指针声明,而不是指向20个double类型值的数据块指针。
例如程序

//dyn_arr.c
#include<stdio.h>
#include<stdlib.h>//为malloc()和free函数提供原型
int main(int argc, char const *argv[])
{
    double *pointer;
    int max;
    int number;
    int i=0;
    puts("what is maximum number of type double entries?");
    scanf("%d",&max);
    pointer =(double *)malloc(max *sizeof(double));
    if(pointer == NULL)
    {
    	puts("Memory allocation failed.Goodby.");
    	exit(EXIT_FAILURE);
    }
    /*pointer现在指向max个元素的数组*/
    puts(" Enter teh values:");
    while(i < max && scanf("%lf",&pointer[i])==1);
         ++i;
    printf("Here are you %d entries:\\n",number=i);
    for(i = 0; i < number;i++)
    {
         	printf("%7.2f",pointer[i]);
         	if(i % 7 == 6)
         		putchar('\\n');
    }
    if(i % 7 !=0)
         	putchar('\\n');
         puts("done.");
    free(pointer);

	return 0;
}

分配对应存放所请求数目足够大的内存空间,并把该内存的地址赋给指针pointer

pointer =(double*)malloc(max *sizeof(double));

malloc()可能无法获得所需数量的内存,在这种情况下,函数返回空指针,程序终止;

if(pointer ==NULL)
{
 puts("Memory allocation failed.Goodbye.");
 exit(EXIT_FAILURE);
}

如果成功分配内存,程序把pointer当作max个的数组名字
最后使用free()释放内存。

free()的重要性importance of Free()!
example:

int main()
{
double a[2000];
int i
}
for (i=0; i<=1000;i++)
gobble(a,2000);
void gobble(double argv[],int n)
{
double * p =(double *)malloc(n *sizeof(double));
/*free(temp);*/
//忘记使用free();
}

第一次调用gobble(),它创建了指针p,斌使用了maclloc()分配16000字节内存(设double是8字节)。
当函数终止时,指针p作为一个自动变量消失。但它指向的16000个字节内存依然存在,我们无法访问这些内存,因为地址没了。由于没有调用free(),不可以再使用它了。
第二次调用gobble(),它创建了一个p,再次使用malloc()分配的16000个字节内存。第一次的内存不能使用,因此malloc()不得不再找一个16000字节的块。
当程序完成循环1000次,已经有1600万字节的内存从内存池中移走了。程序已经出现了内存溢出。我们称为memory leak。

在这里插入图片描述

本篇完

在这里插入图片描述

以上是关于C语言:存储类链接和内存管理的主要内容,如果未能解决你的问题,请参考以下文章

C 基础 - 存储类链接与内存管理

存储类链接和内存管理(c prime plus)

存储类,作用域,生命周期和链接属性

C存储类链接和内存管理--动态分配内存及类型限定词

存储链接类别内存管理术语

存储类链接内存管理