c primer plus 第十二章学习笔记(存储类型,链接和内存管理)

1.作用域

主要分为块作用域,函数作用域,函数原型作用域,文件作用域。

之前大部分都是块作用域,即在一个花括号中所使用的代码区域所使用的变量,但这个变量在下一个函数 中并不能得到正常的调用,即可能造成非法的读取和修改(类似于病毒的情况?)但在某些部分当中也有这种块作用域的存在比如说在for函数中for(int i=0;i<len;i++)这里的i在某些编辑器中并不能得到正常的结果,或者说是正常的调用,毕竟这里也有使用到花括号

像下面的这个函数中具有的变量就有块作用域

double blocky(double clso)
{
    doubel patrick =0.0;
    ...
    return patrick;
}

这里的cleo和patrick就是具有块作用域的变量 

这里可以发现,作用在内层快中进行声明的,它的作用也就只能限制于所在的块。

比如说在上面说到的for函数中的i,这个在离开了for循环之后便并不可能拥有真实的含义,也就不能再进行访问。(c99中进行的规定)

而函数原型作用域的范围只能是从形参定义开始一直到原型的声明,这和块作用域并不相同,他在处理函数原型参数的时候只在意所谓的类型,函数形参名在这里可以说是一个无关紧要的东西。所以就算说要有函数形参名,匹配上面原函数的特定参数名字也是没有必要的。(起码在我学到的范围里面还没有)

文件作用域是把变量定义在函数外面的,具有文件作用域的变量,从他的定义到文件的结尾都是可见的

#include<stdio.h>
int units = 0;
void critic(void)
int main(){
...
}
void critic(void){
...
}

其中的units就具有文件作用域,在main()函数和critic()函数中都是可以使用到的。

 即在整个程序里面都是适用的

链接

 在c语言中存在三种不同的链接,外部链接和内部链接还有无链接(并不能理解为什么要写这个。。。可能是因为更加严谨吧)

当具有块作用域,函数,函数原型作用域的变量的都是属于无链接变量,这说明他的变量的定义属于这个程序的私有,但只要有了文件作用域的变量,就存在可能是外部链接或者内部链接,外部链接可以在多文件中使用,内部文件链接只能在一个文件中使用,即在一个翻译单元中使用

可以说,内部链接是文件作用域(头文件和源文件代码)外部文件被简称为全局作用域在使用static的情况下,直接定义的是外部链接,前面加上static的大多数的都是内部链接

static:
int giants=5;
static int dodgers=3;
int main(){
...
}
...

在这个情况下,文件中可以都可以使用giants,但dodgers只能说是这个文件私有的,一旦在外部使用便可能造成内存的泄露(好吧,这个不会造成内存泄露,在文件之外也只能找到giants这个变量,所以可以放下这个内存泄露的问题了)

储存期

 储存期表明这些变量的生存时间,c语言包括四种存储期,静态存储期,线程存储期,自动存储期,动态存储期。当程序执行期间一直存在,那么说明他具有静态存储期,比如说,以static声明的文件不管是具有内部链接还是外部链接,其变量都是具有静态存储期。

线程存储期用于并发程序设计,程序被分为多个线程,这个存储期作用只能到达这个线程结束,用关键字_Thread_local声明一个对象,这个变量就会变成当前线程的私有辈分

但如果我忘记了对变量进行存储,那会不会变成全局变量声明的啊,个人感觉不不会,块作用域都是具有自动存储期,当退出块的时候这些使用的内存会自动释放刚才为变量分配的内存,我感觉这里可以说是把一个变量存放到了早已经准备好的一个工作区,所以我认为这个可以重复使用这个空间用于存储变量。

在使用函数的时候更加明显这个特点,在型参定义下来的时候并不一定已经给了一份空间,但在调用参数的时候,系统互为他分配一段空间,在函数调用结束时会将这个部分全部释放掉

块定义域也可以具有静态存储器,如果要创建这样的变量那么就要把变量说明在块中,且在声明当中加上关键字static才可以

void more(int number):
{
int index;
static int ct =0;
,,
return 0;
}

ct 存储在静态变量,所以在程序当中是可以一直找到他的存在,但也有一个问题,他是定义在了函数当中,所以他只有在执行这个函数的时候才可以访问到ct这个变量所指向的变量。

属于自动存储类被的变量具有自动存储期,块作用,而且没有链接,这个时候如果为了覆盖一个外部变量定义,或者强调不要把该变量改为其他存储类型,可以使用关键字auto

int main(){
auto int plox;}

但这个关键字并不能在c++语言中正常使用,所以说最好不要用auto关键字来写一个变量说明符,当在同一个函数的不同部分中使用了相同名字的变量,这个可能会是不同的。

比如说

int loop(int n)
{
int m;//m,n的作用域的开始
scanf("%d ",&m):
{
int i;//i作用域的开始
for(i=m;i<n;i++)
puts("hello world\n");//i作用域的结束
}
return m;//m,n作用域的结束
{

 那么做一个不像是人会干的事情,我在内层块里面使用和外层块相同的变量名会怎么样

#include<stdio.h>
int main(){
	int x=30;
	printf("%d,%p\n",x,&x);
	{int x=77;
	printf("%d ,%p\n",x,&x);
	}
	printf("%d ,%p\n",x,&x);
	while(x++<33){
		int x=100;
		x++;
		printf("%d ,%p\n",x,&x);
	}
	return 0;
} 

 其结果可以得到

30,000000000062FE1C
77 ,000000000062FE18
30 ,000000000062FE1C
101 ,000000000062FE14
101 ,000000000062FE14
101 ,000000000062FE14

那么可以得到在同一个函数当中,不同的块,的确会造成不同的情况。这里面可能存在问题的地方就是while循环,这个可以理解为我进行了一个定义,在这个定义当中,x在进去之后会发现,是一个新的地址的x,即不同的x。

当然,在所有的c语言的程序中括号并不是必须的,在if,for里面,可能没有花括号的存在,也可以说这是在同一个块里面,那么,在这种情况下我觉得最好是在同样的缩进里面,或者最好就只有一行。不管怎么说我觉得,最好不要在不同的块里面使用相同的变量名字,即使不会对自己的程序造成什么大的影响,但在可读性和后期维护方面东坑能造成过多的时间浪费

寄存器的保存

变量通常是保存在了计算机的内存里面,如果愿意多花一点运气,肯会将这个保存在cpu里面的高速缓存里面,但我目前感觉没用过这种情况,这样子 好像可以做到更高速的对程序的反应,所以可以在这里使用储存类型的说明符register进行说明寄存器变量,但这个样子下来,并不一定可以做到将要求的变量储存到缓存里面,因为这个是一种请求,那么计算机就有权利对你这种请求进行驳回(感觉没事就驳回我啊)在这种情况下,寄存器中的变量便会变成普通的变量,而且并不是所有的数据类型都可以使用segister,比如说double类型,这个并不能使用,因为一些处理器的寄存器可能没有那么大的空间储存。

在使用关键字register时,可以写成void macho(register int n)

静态变量听起来比较矛盾,其实这个并不是原地不动的意思,而是这只会保持下去,期储存的地址不会发生变化,所以说,在离开他的函数之后也可以正常的保留下来,也就是说,这种函数中定义下来不是一个线程存储期(好像是废话)在块中用类别标识符static来保存

#include<stdio.h>
void try(void)
{
int fade =1;
static int stay=1;//静态变量
printf("%d %d ",fade++,stay++);
}
int main(){
in count;
for(count =1;count<=3;count++){
printf("%d \n",count);
try();
}

其打印出来可以发现fade变量并不会随着发生改变,try()会在每一次使用内部的fade变量的时候进行一次变量的初始化,但stay变量只会在最开始进行一次变量的初始化,但如果没有对他们进行静态变量的初始化操作,他们的会被初始化为0.

而且在调试的时候可以发现,fade的确是原来函数的一部分,但stay并不是这个函数的一部分,或者说,在函数当中调试到这一步的时候,会进行一次跳步,但这个声明只有try函数可以看到,但在运行的时候并没有得到执行

特殊情况时像

int az(static int aq);

这个用法在c语言里面可以说是违法的存在。

静态变量也可以称为局部静态变量

外部链接的静态变量

外部链接的静态变量具有文件作用域,外部链接,静态存储期。其把变量的定义型声明放在了所有函数的最外面创建了外部变量。当然,在函数中使用这个变量,可以使用extern 这个关键字进行声明。如果在一个源文件中要调用定义在其他源文件外部变量,也要使用extern

int er;
double up[100];
extern int mai;//mai在外部文件的话必须要定义声明
void next(void);
{
...
}
int main(){
extern int er;//可以选择的声明
extern double up[];//可以选择的声明
...
}

在这个main函数中,extern使用定义变量并不是必要的,这两个变量在整个文件中都是可见的。而且也没有必要在这里对数组的长度进行说明

但如果在中间main函数省略了extern的话,那么只能在main函数中生成一个int 类型的变量,其和外部定义的变量并不一样。如果对其查看地址也可以发现这一点。外部变量也是具有静态存储期。所以说,数组或者er定义下来的值都不会再发生改变。

int hocus;
int magic(){
extern int hocus;//
}
int main(){
extern int hocus;//和上面的extern int hocus;相同
}

int hocus;
int magic(){
extern int hocus;//
}
int main(){
//虽然没有extern int hocus;但依然可以使用hocus
}

 值得注意的是,在函数中如果使用int hor这样的语句,那么在外面定义下来的hor便不会在这里面可见。

int hocus;
int magic(){
auto int hocus;
..
}
int main()
{
int hocus;
}
int pocus;
...

当然面对这种情况就会考虑怎么初始化外部变量,,当没有对外部变量进行定义是,那么这个会自动定义成为0,也可以这样定义

int x=10;
int y=10+2;
size_t z =sizeof(int);

 这种写法其实是错误的

int x2=x*2;

那么有一个例子可以对这个进行说明。

#include<stdio.h>
int units=10;
void critic(void ){
	printf("no luck,again\n");
	scanf("%d",&units);
}
int main(){
	extern int units;
	printf("how many pounds to a firkin of butter\n");
	while(inits !=56){
		critic();
	}
	printf("luck\n");
	return 0;
}

当这个程序里面的while循环结束的时候,main()和critic()函数也会发生变化,所以在后面的函数可以访问到的那个值已经被函数里面改变 

当然在文件当中要进行一次思考就会发现有一个有意思的现象

int er;
int main(){
extern int er;//可以选择的声明
}

这里大家都知道了,最上面是定义了一个叫er的变量,然后在下面对这个变量引用,关键字extern表明这个声明不是在定义,而是在引用

但假如这个样子

extern int tern ;
int main(){
}

说明在这个程序当中, tern这个变量在程序的其他地方或者在其他文件当中,所以不会为他再分配一段空间

外部变量只能初始化一次,而且必须在定义该变量的时候。假如说我在其定义之后在对其进行改变,其一定会造成系统的报错。

内部链接的静态变量

在函数中使用说明符static说明具有这种存储类别。比如说:static int az =1;这个可以说是静态变量,内部链接。其过去被称为外部静态变量,这个词我觉得更好理解一些。普通外部变量可以作用在任意文件的函数,但内部链接的静态变量著能做用同一个文件中的函数,其可以使用关键字extern来解决

存储类别说明符

在这六种关键字中,可以进行一个总结。

typedef关键字可以说是和任何的内存存储无关,在绝大多数的情况下,typedef关键字会和其他的存储类别说明符不能共存,所以这意味着不能使用多种存储类别说明符作为typedef的一部分

auto是表明自动存储期,只能作用块作用域的变量说明,,使用其主要是为了明确表达作用要和使用的外部变量同名的局部变量。

register只能作用于块作用域的变量,是请求最快速度访问该变量,同时还保护了该变量的地址不被获取。

用static说明符创建的对象具有静态存储期,期只能用于文件作用域,作用域还会是受到限制。当他作用于什么作用域时,其就会受限制于什么作用域。,块作用域的静态变量没有链接,文件作用域的静态变量具有内部链接。

extern说明符表明说明的变量的定义在其他地方,包含extern 的说明具有文件作用域,引用的变量必须要有外部链接,具有块作用域的话,必须要具有外部链接或者内部链接,这个是取决于对该变量的定义说明

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值