可见性,针对于编译过程,从文件头开始到文件末尾进行编译
void max()
{
x=100;
}
int x=0;
void main()
{
int y=x;
}
int z=10;
首先在上面的程序中,从可见性来看,第一个函数max()中x是无法初始化的,因为在编译过程中编译器是一行行扫码的,那么max()中的x就是没有被初始化的变量,所以这条语句没有作用。
然而对于全局变量x,z来说,当程序刚开始执行初,x和y就就被初始化了,所以它的可见性并不是整个文件,而是从它的这条语句开始到文件末尾。
之所以max()函数中的语句没有成功初始化是因为,对于这个程序来说是看不见全局变量x和z的。
所以需要记住的是生存期是针对编译通过后的执行过程的,而可见性是针对编译过程的
再次顺便解释下C语言变量初始化时的就近原则
int x=0;
void main()
{
int x=100;
int y=x;
}
上面的程序中y的初始化用的x的值是100,用的是距离变量y距离较近的变量的值,如果你想使用全局变量的值,那么我们需要使用作用域符::
如
int x=0;
void main()
{
int x=100;
int y=::x;
}
生存期:针对执行过程
在解释生存期之前,我们要先了解一下关于,栈空间为函数分配空间的过程和栈空间的问题,链接如下
函数空间分配
int *fun()
{
int x = 10;
return &x;
}
void add()
{
}
void main()
{
int *p = NULL;
p = fun();
//add();
cout << *p << endl;
}
当加上调用add()时得出的结果是一个随机值
而不调用add()时则可以得到结果10
在不调用add时,虽然fun()函数在执行完之后空间会被释放,但是在这时候没有干扰到这一块的空间,所以p=fun()依旧指向了x的值。然而当调用add时,栈帧的调用时连续的,比如main时一楼的栈帧,fun时二楼的栈帧,当fun()执行完后释放,又把fun的栈帧空间给了add(),同时在给add()时会将fun释放后的空间打扫一边会用16进制数0xcccccccc来填充。所以同时p=fun()就失效了,这是p就变成了失效指针。只要fun()被释放不管p能不能得到x的值都是失效指针。但是当printf()输出一个数组时输出的数可能不是全0xcccccccc应为printf()这个函数也会侵占上一个函数的栈帧,但是他不一定会影响上一个函数的值。如果一直测试都是那个值只能说明是运气问题总之下面这样的程序是据不允许的
但是
int fun()
{
int x = 100;
return x;
}
void mian()
{
int a = fun();
}
这样的程序是允许的应为return的x是一个临时量是放在cpu的寄存器中的
另外全局变量是存放在数据区的
char *str = "yhping"
void main()
{
char *ch = "hellow";
}
在上面的的程序中str是全局变量在数据区ch是局部变量在栈区,而hellow和yhping是常量在数据区,全局变量还有静态变量也在数据区
静态变量在第一次调用时初始化被产生而且初始化一次,它的生存期是从产生开始一直到程序的结束。
int *fun(int x)
{
static int a = x;//静态变量只在执行时初始化一次,所以后来的x也没有是a再次初始化。存放于数据区,将a的空间分配于数据区
之所以之初始化一次,是应为在第一次初始化其时,在他的空间处设计了一个标记域,在未初始化之前比如标记域的值为0;
而初始化之后把他改为1,这样在第二次初始化时检查到标记域的值为1,这样就进行第二次初始化
static int b = 0;//b是一个常量在编译时就会完成,在数据区开辟空间存放数
++a;
cout << a;
return &a;
}
void main()
{
int *p = NULL;
for (int i = 10; i > 0; --i)
{
p = fun(i);//之所以可以这样做是应为静态变量即使在fun()函数被释放后依然存在于数据区,所以可以执行
*p += 100;//这样是会改变静态变量a的值的
}
}
正是应为静态变量的这种特性,所以为了返回数组时,可以把数组定义为静态变量,就可已返回数组的值,但是这样的方式有局限性,所以当需要返回多个类型不同的值时建议使用结构体进行返回
struct student
{
char id[10];
char name[10];
char sex;
int age;
};
student *fun()
{
student s = { "20180101", "yhping", 'm', 28 };
return &s;
}
void main()
{
student *sp = fun();
cout <<sp->age;
}
这样虽然可能得到结果,这是应为没有被别的函数在获取内存空间是没有被替代,但是这样做是不合法的,可能会造成错误,这就是函数的生存期问题。所以最好把整个结构体返回
但是有一个例外就是malloc开辟的堆内存空间
int *getarray(int n)//不再生存期问题中,函数空间在栈中,malloc在堆中,虽然函数死亡,但是堆空间开辟的内存空间依旧存在
{
int *s = (int *)malloc(sizeof(int)*n);
return s; //所以s在main中依旧能够在主函数中调用
}
void main()
{
int n;
cin >> n;
int *p = getarray(n);
for (int i = 0; i < n; i++)
p[i] = i;
for (int i = 0; i < n; i++)
cout << p[i] << endl;
free(p);
p = NULL;
}