这个系列基本上是一月一更到两月一更
今天写一篇关于static的,内含大量干货,做好准备
一般来说,我们之前已经讲过的变量(或者说是内存)可以大体分为这样几种:
这里回顾一下,在C++中,使用const声明的常量是不可改变的,也就是在编译期就确定下来了。因此,即使使用指针更改也不会实际修改到它的值。对于全局变量,const出的值和字符串字面量(即使用""括起来的字符串),存在常量区,强制改变会使得程序异常退出。
对于全局变量,它由始至终都是存在的,作用域是全部。
局部变量的作用域和声明周期仅存在一个函数中,当函数返回,它就会从栈中销毁。
使用malloc分配的内存区域,它的生命周期一直到调用free为止。
对于字符串字面量和常量,它的作用域和声明周期与全局变量和局部变量类似。
我们把使用static修饰的变量和全局变量统称为静态变量。
静态变量,顾名思义,就是可以贯穿整个程序运行的时间内的变量。
我们来写一段代码,进行一个实验:
#include<iostream> #include<windows.h> using namespace std; int a;//全局变量 static int b;//全局static变量 void f(void){ static int c;//定义在函数内的static变量 printf("c..%pn",&c); } int main(){ printf("a..%pn",&a); printf("b..%pn",&b); f(); return 0; }
(注:今天我换了一台电脑进行编辑,使用的是codeblocks来编辑,编译器我设置的是VC)
输出的结果如下
可以看到,static修饰的变量,与全局变量的地址是接近的,可以证明它是在全局存储区。
还是以例子来说明,这样比较好理解。假如我们写一个将数字转为字符串的函数:
#include<iostream> #include<windows.h> using namespace std; char *toint(int x){ char s[1000]; sprintf(s,"%d",x); return s; } int main(){ char s[1000],t[1000]; strcpy(s,toint(8)); strcpy(t,toint(10)); printf("%sn%sn",s,t); return 0; }
使用sprintf函数,进行字符串间的转换。
这段代码,乍一看似乎没有问题,而且在我的环境还可以正常运行:(部分环境会Segmentation Fault,就更加能说明这个问题)
但是我们仔细看看,画面下方报出了一行警告:
(看我选中的一条,上面一条似乎是环境没有配置到位,先不管了)
这是因为,其中的s数组是局部变量,或者说是自动变量,保存在栈中,在函数返回之后,这个地址就不能再使用了,因为这个数组已经销毁了,s地址所在的地方是“无人区”,访问时就有可能访问到不该访问的数据,进而出错。
对于这一类的问题,解决方法有使用malloc和new来分配内存,这样可以在free之前多次使用:
char *toint(int x){ char *s=new char [1000]; sprintf(s,"%d",x); return s; }
这一次没有报错。
事实上,还可以使用静态变量来解决(不过静态变量主要的用途不在这里),这样这个内存就不会在返回的时候被释放。
char *toint(int x){ static char s[1000]; sprintf(s,"%d",x); return s; }
同样没有报错。
#include<iostream> #include<windows.h> using namespace std; void f(){ static int Count; printf("%dn",Count); Count++; } int main(){ for(int i=0;i<10;i++){ f(); } }
由于static的变量一直在同一个存储区,因此可以发现,退出函数时,static变量的值保持不变,输出结果为:
static的变量,只能在当前的文件内进行访问。
//a.cpp static int x; int main(){ x=100; cout<<x<<endl; f(); } //b.cpp extern int x; void f(){ cout<<x<<endl; }
在b.cpp中,无法访问a.cpp中的x变量,因为x是使用static修饰的(即使使用了extern进行声明)
包括函数也可以使用static进行修饰:
static int f();
关于更多的内容,敬请期待:
【原创】浅谈指针(十三)关于static(下)
(预计5月发布)