1 对象:从硬件角度看,每个数据值都需要占用物理内存,这个物理内存在C语言中称之为对象;
对象:可以存储一个或多个值的物理内存;
对象使用"存储期"描述物理内存属性,"作用域"和"链接"来描述使用属性;
int i = 3; /*该声明创建了标识符 i ,也就是存储着数据3的对象 i ;*/
/*程序通过创建标识符来表示特定的对象,实现访问物理内存;*/
1.1 存储期:在内存中保存的时间;
1.1.1 静态存储期:程序开始执行到结束的时期;静态指的是变量的内存地址不会改变,是静态的;供静态变量使用;
1.1.2 自动存储期:程序进入变量所在块到退出变量所在块的时期;程序进入块时为块区域变量分配内存,退出块时释放内存;以堆栈的方式来处理;供自动变量使用;
1.1.4 线程存储期:程序执行被分为多个线程,在某个线程中被声明之后一直存在直到线程结束的时期;属于以 _Thread_local声明的对象,每个线程都有该变量的私有备份;
1.1.3 动态分配存储期:由程序调用malloc()等来分配,内存块较为分散导致速度慢;供动态内存函数分配使用;
1.2 链接属性
1.2.1 无链接属性:变量为当前块私有;
#includeint count; static int num; void main(void) { int apple;/*作用域在当前块,无链接属性*/ ....; }
1.2.2 内部链接属性:变量为当前文件私有;
#includeint count; /*变量为外部链接属性,可与其他.h文件共享*/ static int num; /*变量为内部链接属性,不与其他.h文件共享*/ void main(void) {
extern int count;/*与前面的count是同一个count,此处声明可省略*/
int count; /*与前面的count不是同一个count,这个作用域为当前区域块*/
}
1.2.3 外部链接属性:变量与其他.h文件共享时怎么调用;
#includeextern int count ; /*在其他文件中声明的具有文件作用域的变量,本文件调用的话要用extern重新声明一下*/ int sum ; /*全局变量未初始化,会默认初始化为0,局部变量不会默认初始化*/ void main(void) {
...
}
/*关键字extern声明属于引用声明,extern声明不会引起内存分配,该变量必须在其他文件中有过定义声明(第1次声明)*/
1.3 作用域:对象可以被访问的区域;
1.3.1 文件作用域:从定义处到当前文件结尾的区域;定义在函数体外的变量具有文件作用域;有链接属性;
#includeint units =0 ; /*具有文件作用域,被称为全局变量*/ int index ; //外部链接属性,静态存储期 static int inter_uints = 0 ; //内部链接属性,静态存储期 int main(void) { int x = 33; //外层块变量 while(x++<36) { int x =100 ; //内层块变量,与外层x不是一个变量; printf("%d,x here is 100",x); } printf("%d,x here is 33",x); for(i=0;i<3;i++) { static int stay = 1; printf("%d,print stay result is 1,2,3",stay); stay++; //所有静态变量在程序载入内存时初始化已经执行完毕;此处写初始化表示作用域只在当前块区域 //静态变量只会初始化1次,具有时序记忆性;如果不赋值,默认初始化为0; //不能在函数的形参中使用static; } }
1.3.2 块作用域 :花括号括起来的区域;定义在块中的变量具有块作用域;无链接属性;
void function(int i,int j) { /*i,j,k的块作用域*/ int k; //无链接属性,自动存储期 static int p ; //无链接属性,静态存储期 for( int m=0;m) { /*m,n的块作用域*/ int n; } } /*其他函数可以通过指针形参或返回值,间接访问块区域的静态变量*/
1.4 存储类说明符
1.4.1 register:寄存器类型
register int i ; //寄存器变量存储在寄存器中,无法获取寄存器变量的地址 //如果寄存器不够,编译器就会将其设置为自动变量;
1.4.2 auto:自动存储类型
auto int apple; /*代码块内声明的变量默认为auto类型;无链接属性;自动变量不会默认初始值;*/
1.4.3 static :静态存储类型
static int apple ; /*不管声明在什么位置,作用域都是当前文件;全局变量(静态变量)默认初始值为0;*/
1.4.4 extern:外部链接类型
extern int count ;
/*在其他文件中声明的具有文件作用域的变量,本文件调用的话要用extern重新声明一下*/ /*关键字extern声明属于引用声明,extern声明不会引起内存分配,该变量必须在其他文件中有过定义声明(第1次声明)*/
1.4.5 typedef (用法相近所以放在此处)
2 动态内存分配
2.1 malloc()与free()
double * ptr ; ptr = ( double * ) malloc( 33*sizeof(double) ) ; /*malloc()根据所需内存字节数33*sizeof(double) ,从物理内存中找到适合的空闲块,将该空闲块的首地址作为void类型的指针返回*/ /* void类型的指针可以被强制转换为任意类型的指针,如指向数组的指针,指向结构的指针等; */ /*malloc()动态分配不到内存,返回NULL空指针;*/ int * array; int i=0; array = (int *) malloc(10* sizeof(int) ); while(i<10 && scanf("%d", &array[i])==1) i++; printf("enter done ! "); /*分配了一个10个int型的动态内存,然后将键盘输入填入内存*/ free(array); /*释放malloc()动态分配的内存*/
int * array; array = (int *) malloc(10* sizeof(int) ); free(array); /*malloc()与free()在一个函数中应该成对使用;*/ /*如果一个函数每次调用malloc(),执行完之后没有调用free(),那么该函数返回后,指向malloc内存的指针释放,但是malloc分配的内存却还是在;*/ /*如此多次调用之后内存可能就会耗尽,这类问题称为内存泄漏;*/
2.1 calloc()与free()
double * price; price=(double *) calloc(100,sizeof(double)); /*calloc()分配了100个存储单元,每个单元的大小为一个double型 的动态内存;*/ /*并且calloc()会默认把块中的所有位都置为0;*/ ... free(price); /*释放内存;*/
3 ANSI C类型限定符
3.1 const
const int size = 12 ; const int days[12]={31,28,31,30,3,30,31,31,30,31,30,31}; /*const将变量声明为常量,只有第一次对变量赋值有效,之后赋值无效*/ const int size ; size = 12 ; /*此处为无效错误示范*/
3.1.1 const 与指针
// const double * ptr ; 常用于函数形参中 void sum(const double *ptr , int size); { double rates[size]; for(int i=0; i) { rates[i]=*ptr ; ptr++; } ... } /* const double * ptr ; 表示该指针指向的数据类型不会被指针修改,但是指针指向的地址可以修改*/ /*需要注意:非const类型的数据地址可以赋值给const的地址,这只是表示我们使用该const变量的时候不会改变数据*/ /*另外一提:普通指针不能指向const数据类型:普通指针可以修改数据,但是const数据又不许修改*/ //double * const ptr2 ; double rates[5]={8.9,[3]=3.2}; double * const ptr2=rates; *ptr2=100.5; /* double * const ptr2 ; 表示该指针指向的地址不允许修改,但是该地址内的数据可以修改*/ /* const double * const ptr; 表示不修改指针指向的数据类型和存储的地址*/ /* const double *ptr;和 double const * ptr;是等价的;*/
3.2 volatile:告诉编译器不要优化编译,主要用于硬件地址以及在其他程序或其他线程中共享数据;
volatile int i ; int val1,val2; val1=i; .../*一些不改变 i 值的代码*/ val2=i; /*编译器第一次使用了i的值之后在寄存器中有临时缓存,val2再使用i值时默认从寄存器中提取,优化编译器速度;*/ /*使用volatile,则告诉编译器不要优化,应该从内存地址中查找使用值;该值可能会被其他程序或硬件改变了*/
volitile const int loc ; volitile const int *ploc ; /*表示 用const将硬件时钟设置为不能更改的变量,但是可以通过代理(其他程序或硬件)改变;我不理解这个意思*/ /*const 和 volitile 同时使用的顺序不重要,反正都是限定符;*/
3.3 restrict :告诉编译器要优化编译,只能用于指针,表明该指针是访问对象唯一且初始的方式;
int * ptr = (int * ) calloc(100,sizeof(int)); ptr[2]+3; prt[2]+5; /*表示 指针ptr 是唯一且初始的访问动态内存的方式;*/ /*ptr[2]+3,ptr[2]+5 可以一起优化成 ptr[2]+8 编译;而不用担心中途ptr[2]的数值是否被其他代理改变了*/ int array[10]; int * parray = array ; /*此处的指针parray并不是访问数组array的唯一方式,也不是初始方式;其他地方如果有使用,编译器不会去优化编译;*/
3.4 _Atomic:声明原子变量,由stdatomic.h和threads.h管理;
#includeage; age = 12 ; /*可以替换如下,将其变为原子对象,当程序对原子对象进行操作时,其他线程不能访问该对象;*/ _Atomic int age ; atomic_store(&age,12) ; /*C11新特性,有的编译器不一定支持;*/
#include
int