12.1 存储类别
目前程序示例,从硬件来看,被存储的每个值都占用一定的屋里内存,C语言把这样一块内存称为对象,对象可以存储一个或多个值,
声明变量可以访问对象,标识符可以来指定特定的对象内容。
存储期来描述对象在内存中保留了多长时间,标识符用于访问对象,可用作用域和链接来描述标识符。
12.1.1 作用域
作用域来描述程序中可访问标识符的区域。
块作用域:整个函数是一个块,函数中的任意语句也是一个块,块作用域变量可见范围是从定义处到包含该定义的结尾
函数作用域:仅用于goto语句的标签。
函数原型作用域:从形参定义处到原型声明处结束。
文件作用域:变量定义在函数外面具有文件作用域。
注意:编译器源代码文件和所有头文件都看成是一个包含信息的单独文件,被称为翻译单元。描述一个具有文件作用域的变量,它实际可见范围是整个翻译单元。
12.2 链接
c变量有3种属性,外部链接,内部链接,无链接。
使用存储类别说明符static的是内部链接。
12.1.3 存储期
作用域和链接描述了标识符的可见性,存储期描述了通过这些标识符访问对象的生命周期。
c语言有4种存储期:静态存储期。线程存储期,自动存储器,动态分配存储期。
静态存储期:它在程序执行时一直存在,文件作用域变量具有静态存储期。
线程存储期:用于并发设计。程序执行被分为多个线程。具有线程存储期的对象,从声明到线程结束一直存在以_Thread_local声明一个对象时,每个线程都获得该变量的私有备份。
自动存储期:快作用域变量具有自动存储期。
动态分配存储期:手动创建,手动释放。
12.1.4 自动变量
属于自动存储类型类别的变量具有自动存储期,块作用域且无链接。
默认情况:在块或函数头中任何变量都属于自动存储类别,也可以显式的使用关键字auto
c99特性:作为for循环或if语句的一部分,即使不使用花括号也是一个块,完整来说整个循环是它所在的子块,循环体是整个循环的子块。
12.1.5 寄存器变量
register int n 请求寄存器变量。
12.1.6 块作用域的静态变量
即块作用域变量在函数结束后任然存在。
12.1.7 外部链接的静态变量
具有文件作用域和外部链接,静态变量。
如果为了源代码使用的外部变量在另一个文件中,必须使用extern在该文件中重新声明变量。
int tern=1//定义式声明
int main
{extern int tern;//引用式声明
}
12.1.8 内部链接的静态变量
具有内部链接,静态变量,文件作用域。
12.1.9多文件
12.1.10 存储类别说明符
auto:只用于块作用域的变量声明,由于在块中声明的变量本身就是自动存储,所以使用auto只是为了明确表示使用与外部变量同名的局部变量的意图。
register:只用于块作用域,它把变量归于寄存器类别。
static:用于说明创建的变量具有静态存储期,如果static用于文件作用域声明,则该变量受限于文件。如果用于块作用域,则该变量具有静态存储。
extern:说明声明的变量定义在别处
_Thread_local,typedef
12.1.11 存储类别和函数
12.1.12 存储类别的选择
12.2 随机函数和静态变量
函数位于stdlib.h头文件中
rand()产生随机数,srand()产生随机数种子。
函数位于time.h头文件中
例:srand(unsigned int)time(NULL)获取随机数种子。
12.4 分配内存:malloc()和free()
声明数组的3中方法
声明数组时,用常量表达式表示数组维度,用数组名来访问数组的元素,可以用静态内存或自动内存来创建。
声明变长数组(c99)用变量表达式来表示数组维度,具有这种特性的数组只能在自动内存中创建
声明一个指针,调用malloc()将其返回值赋给指针,使用指针访问数组元素,该指针可自动或静态。double *ptd=(double*)malloc (n*sizeof(double))
12.4.1 free()的重要性
一定要释放内存。
12.4.2 calloc()函数
long *ptd=(long *)calloc(n,sizeof(long))
在ANSI后calloc类似malloc返回void的指针,所以要使用强制类型转化符,接受两个无符号整数作为参数,ANSI规定为size_t类型。
12.4.3 动态内存分配和变长数组
区别:变长数组是自动存储类型。
12.4.4 存储类别和动态内存分配
理想化模型:内存分为三部分
一部分为具有外部链接,内部链接和无链接的静态内存使用、一部分供自动变量使用、一部分供动态内纯分配。
静态存储类别所用内存数量在编译时确定。
自动存储类别在程序进入变量定义所在块时存在,离开块时消失。(一般作为桟处理)
动态内存在调用malloc()或相关函数时存在,在调用free()后释放。
12.5 ANSI C类型限定符
c99新增可以在一条声明中多次使用同一个限定符
12.5.1 const类型限定符
const float* pt 表示不能通过pt修改它指向的值。
float* const pt 表示不能修改pt的值。
简而言之,const放在*左侧任意位置,限定了指针指向的数据不能改变,放在*右侧,指针本身不能改变。
12.5.2 volatile类型限定符
volatile表示计算机,代理可能改变该变量的值,表示该值有可能发生变化。
12.5.3 restrict类型限定符
只能用于指针,表示该指针是访问数据对象唯一且初始的方式
12.5.4 _Atomic类型限定符(c11)
_Atomic int hogs://int hogs
atomic_store(&hogs,12)// hogs=12
12.9 编程练习
5.
#include<stdio.h> #include<stdlib.h> #include<time.h> int main() { int num[100]; int n; srand((unsigned int)time(NULL)); for (int i = 0; i < 100; i++) { num[i]=(rand()%10)+1; printf("(%-2d)",num[i]); } puts(""); for (int i = 0; i < 100; i++) { for (int j = i+1; j < 100; j++) { if (num[i]<num[j]) { n=num[i]; num[i]=num[j]; num[j]=n; } } printf("(%-2d)",num[i]); } system("pause"); }
9.
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<string.h> 4 #include<time.h> 5 #include<ctype.h> 6 int main() 7 { 8 int word_num; 9 char nu[100]; 10 puts("请输入单词数"); 11 scanf("%d",&word_num); 12 char **ch=(char **)malloc(word_num*6*sizeof(char)); 13 while (getchar()!='\n') 14 continue; 15 puts("请输入字符串"); 16 gets(nu); 17 puts(nu); 18 int n=0; 19 for (int i = 0,j=0; i < strlen(nu)+1; i++) 20 { 21 if(isalnum(nu[i])&&(n==0)) 22 { 23 n=1; 24 ch[j]=&nu[i]; 25 j++; 26 } 27 else if(!isalnum(nu[i])&&(n==1)) 28 { 29 n=0; 30 nu[i]='\0'; 31 } 32 } 33 printf("%u",sizeof(ch)); 34 for (int i = 0; i < word_num; i++) 35 { 36 printf("%s",ch[i]); 37 } 38 39 40 41 42 system("pause"); 43 }
9.
#include<stdio.h> #include<string.h> #include<ctype.h> #include<stdlib.h> int main() { int word_num; char nu[100]; puts("请输入单词数"); scanf("%d",&word_num); char **ch=(char **)malloc(word_num*sizeof(char*)); while (getchar()!='\n') continue; puts("请输入字符串"); gets(nu); int num=strlen(nu); for (int i = 0,n=0; i < num; i++) { if(isalnum(nu[i])&&(n==0)) n=1; else if(!isalnum(nu[i])) { n=0; nu[i]='\0'; } } for (int i = 0,n=0,j=0; i < num; i++) { if(isalnum(nu[i])&&(n==0)) { ch[j]=(char *)malloc(strlen(&nu[i])*sizeof(char)); ch[j]=&nu[i]; j++; n=1; } else if(!isalnum(nu[i])) n=0; } for (int i = 0; i < word_num; i++) { puts(ch[i]); } system("pause"); return 0; }