存储类别
在了解存储类别之前,我们先来了解作用域,链接和存储期给含义。
作用域
作用域描述程序中可访问标识符的区域。作用域包括块作用域,函数作用域,函数原型作用域和文件作用域。
1.块作用域
块作用域的可见范围是从定义处到包含该定义的块的末尾。即如果A的作用域仅限于内层块,那么就只有内层块中的代码能访问A。
*以前,具有块作用域的变量必须声明在块的开头,而C99标准则放宽了这一限制,允许在块中的任意位置声明变量。例如
for(int i=0;i<10;i++)
printf("A C99 feature: i=%d", i);
2.函数作用域
函数作用域仅用于goto语句的标签。这意味着即使一个标签首次出现在函数的内层块中,它的作用域也将延伸至整个函数,如果在两个块中使用相同的标签会很混乱。标签的函数作用域防止了这样的事情发生。
goto语句也称为无条件转移语句,其一般格式如下: goto 语句标号; 其中语句标号是按标识符规定书写的符号, 放在某一语句行的前面,标号后加冒号(:)。语句标号起标识语句的作用,与goto 语句配合使用。
如: label: i++;
loop: while(x<7);
goto loop;goto语句的语义是改变程序流向, 转去执行语句标号所标识的语句。
goto语句通常与条件语句配合使用。可用来实现条件转移, 构成循环,跳出循环体等功能。
但是,在结构化程序设计中一般不主张使用goto语句, 以免造成程序流程的混乱,使理解和调试程序都产生困难.
标签的作用:
标明位置 :
比喻说用个goto语句 不管goto case1; 这句在du什么地方,执行完这句后程序就会跳转到case1这个位置开始执行
3.函数原型作用域
函数形参作用域用于函数原型中的形参名(变量名)
形参就是形式参数,用一个变量代表大家。实参就是实际参数,用一个确切的数值代替形式参数,可以是表达式。实际参数与形式参数的参数个数、类型和顺序都应一样,如果不一样的话,系统会强制转换,这样会造成数据的丢失。实
参向形参的传递是值的传递。
这个值就是对实参的表达式进行计算的结果,它可以是常量值、变量值、数组元素、函数值等。如果实参是数组名了,那么它传送的就是地址的值了。比如:
double
power(double x , int n)定义一个双精度参数
power(3.0,5)
调用
x,n是形参, 3.0,5是实参。如果上面定义的是整形
double
power(int x,int n),下面调用的是power(3.3,5)那么实参中3.3会被转换成3,一部分数据丢失了。
函数原型的作用域是从形参定义出到原型声明结束。这意味着,编译器在处理函数原型时只关心它的类型,而形参名通常无关紧要。而且,即使有形参名,也不必与函数定义中的形参名相匹配,只有在变长数组中,形参名才有用。
[百度]https://blog.csdn.net/houzijushi/article/details/80245894
下面是一个变长数组:
void use_a_VLA(int n,int m,ar[n][m]);
方括号中必须使用在函数原型中已经声明的名称。
4.文件作用域
变量的定义在函数的外面,具有文件作用域,具有文件作用域的变量,从他的定义到该处定义所在的文件的末尾均可见。
#include <stdio.h>
int units=0;
void critic(void);
int main(void)
{
}
void critic(void)
{
}
在这里,变量units具有文件作用域,main()函数和critic()函数都可以使用它,由于这样的变量可用于多个函数,所以文件作用域变量也称为全局变量。
链接
C语言中链接包括三种。外部链接,内部链接或无链接,具有块作用域,函数作用域或函数原型作用域的变量都是无连接变量。这意味着这些变量属于定义它们的块,函数或原型私有。具有文件作用域的变量可以时外部链接或内部链接,外部链接变量可以在多文件程序中使用,内部链接变量只能在一个翻译单元中使用。
编译器源代码文件和所有的头文件都可以看成时一个包含信息的单独文件,这个文件被称为翻译单元。
外部链接的文件作用域描述可延伸至其他翻译单元的作用域
内部链接的文件作用域简称文件作用域,外部链接的文件作用域简称全局作用域或程序作用域。
想知道文件作用域变量时内部链接还是外部链接,;可通过存储类别说明符static来判断,若有则为内部链接。
static int a=3;
存储期
作用域和链接描述了标识符的可见性,存储期描述了通过这些标识符访问的对象的生存期。
静态存储期
如果对象具有静态存储期,那么它在程序的执行期间一直存在,文件作用域变量具有静态存储期。
线程存储期
用于并发程序设计,程序执行可被分为多个线程,从被声明到线程结束一直存在。
自动存储期
块作用域的变量通常拥有自动存储期,当程序进入定义这些变量的块时,为这些变量分配内存,退出时,释放内存。变长数组的存储期是从声明出到块的结尾。,若要使块作用域变量也能具有静态存储期,要把变量声明在块中,且在声明前加上关键字static。
C语言的5 中存储类别
[百度]https://www.cnblogs.com/chenxiao3602/p/13658660.html
存储类别说明符
auto说明符表明变量是自动存储期,只能用于块作用域的变量声明中。
register说明符也只用于块作用域的变量,它把变量归为寄存器存储类别。
用static说明符创做的对象具有静态存储期。
extern说明符表明声明的变量定义在别处。
此外还有typedef和_Thread_local,其中_Thread_local可与static和extern一起使用。
随机函数和静态变量
rand()函数可用于生成随机数,可引入strand()函数重置种子,使得每次生成的随机数不同.使用以上两个函数需要包含stdlib.c头文件。
time()函数用于返回系统时间,time()函数返回值的类型名是time_t
分配内存
double * ptd;
ptd = (double*)malloc(30*sizeof(double));
malloc()函数,该函数接受一个参数,所需的内存字节数,,malloc()函数分配内存,但是不会为其赋名,而是返回动态分配内存块的首字节地址,因此,可以把该地址赋给一个指针变量,并用指针访问这块内存。malloc()函数可用于返回指向数组的指针,指向结构的指针等,所以通常该函数的返回值会被强制转化为匹配的类型。而指向void的指针类型则相当于一个通用指针,把指向void 的指针赋给任意类型的指针完全不用考虑类型匹配的问题。
`
` 通常,malloc()函数要和free()函数配套使用,free()函数的参数是之前malloc()返回的地址,该函数释放之前malloc() 函数分配的内存。因此,动态分配内存的调用期从malloc()分配内存到free()释放内存为止。
free()的参数应该是一个指针,指向右malloc()分配的一块内存,不能用free()释放通过其他方式(如,声明一个数组的方式)分配的内存,malloc()和free()的原型都在stdlib.h头文件中。
如果内存分配失败,可使用exit()结束程序,原型也在stdlib.h头文件中。
分配内存还可以用calloc(),典型用法如下,
long *newmem;
newmem = (long*)calloc(100,sizeof(long));
和malloc()类似,在ANSI之前,calloc()也返回指向char的指针;在ANSI之后,返回指向void的指针,如果要存储不同的类型,应使用强制类型转换符。calloc()接受两个无符号整数作为参数,一个是所需的存储单元数量,另一个是存储单元的大小,在上面的例子中,Long为4字节,所以,前面的代码创建了100个四个字节大小的存储单元,总共400字节。
calloc()函数还有一个特性,它把块中所有的位置都设置为0.
变长数组
变长数组(VLA)和malloc()都可以用于创建在运行时确定大小的数组。
int vlamal()
{
int n;
int * pi;
scanf("%d",&n);
pi = (int*)malloc(n*sizeof(int));
int ar[n]; //变长数组
pi[2]=ar[2]=-5;
...
}
ANSI C 类型限定符
const类型限定符
const 关键字声明的对象,其值不可随意更改。
const int nochange;/*限定nochange的值不能被修改
nochange = 12;/*不允许*
编译器会报错,但是可以初始化const变量
const int nochange = 12;
可以用const关键字创建不允许修改的数组
const int days[12]={12,42,53,7,5,6,5,455,6,334,567,78};
在指针和形参声明中使用const
const float * pf; /*pf指向一个float类型的const值
float * const pf; /* pt 是一个const指针
const float*const ptr;
const 在星号左边时,表明指针指向的数据不能改变。当const 在星号右边时,限定了指针本身不能改变。
在函数原型和函数头,形参声明const int array[]与const int * array相同,表明不能更改array指向的数据。
volatile类型限定符
volatile类型限定符告知计算机,代理(而不是变量所在的程序)可以改变该变量的值。
colatile int locl; /*locl是一个易变的位置*/
colatile int * ploc; /*ploc是一个指向易变的位置的指针*/
除此之外,还有restrict 和_Atomic两种类型限定符。
okk,本章小结就暂时到这里啦,欢迎大家的指正哦!