17、黑马程序员-C语言static和extern

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

一、在Java中,全局变量的定义没有严格的位置规定

全局变量可以定义在类的最前面,也可以定义在类的最尾端,也就说一个方法可以访问在它之后定义的变量。

可以看到,第4行定义的test方法可以访问第8行定义的变量a,这是完全没有问题的。

二、在C语言中,全局变量定义的位置是有限制的
默认情况下,一个函数不可以访问在它后面定义的全局变量

在第4行定义的main函数中尝试访问第9行定义的变量a,编译器直接报错了。
解决这个错误的话,有2种办法:

第1种办法:将变量a定义在main函数的前面


这样做编译器就不会找你麻烦了。

 
第2种办法:在main函数前面对变量a进行提前声明
也就是让main函数知道变量a的存在就行了,至于变量a定义在哪个位置,main函数不用管。
* 完整的变量声明需要用extern关键字

第3行是对变量a进行声明,第10行是定义变量a,再次强调,声明和定义是两码事。在第6行操作的就是第10行定义的变量a。
注意:你不能省略第10行的定义,只留下第3行的声明,因为extern是用来声明一个已经定义过的变量。
 
三、重复定义同一个变量
* 其实,你也可以直接在main函数前面再定义一次a


看到这一幕,你可能很惊讶,但编译器是不会报错的。在这种情况下,第3行和第10行的变量a代表着同一个变量。

 
* 以此类推,如果我们写了无数遍全局变量int a;,它们代表的都是同一个变量。


第3到第6行、第13到第17行的变量a都代表着同一个变量。

 * 还要注意的一点是,我们也可以将全局变量a声明为局部变量后再使用!!!




注意:第2、第5、第6、第10行都代表着同一个变量。其实,从第6行a的颜色(浅蓝色)都可以看出,这个a依然是个全局变量。

(这是Xcode的特性,如果在函数内部访问了全局变量,全局变量就会显示浅蓝色,如果函数内部访问的是局部变量,局部变量就显示普通的黑色。当然,不同的开发工具有不同的显示方案)
 
* 但是,如果你将第5行的extern去掉,那情况就完全不一样了,相信有编程经验的你都懂得这是什么情况了

第2、第10行代表着同一个全局变量,而第5、第6行则是一个局部变量,跟外面的那个全局变量没有半毛钱的关系。其实从第5、6行a的颜色(黑色)都可以看出是个局部变量。
 
四、static关键字

Static在C语言里面有两个作用,第一个是修饰变量,第二个是修饰函数

1、Static修饰变量

按照作用范围的不同,变量分为局部变量全局变量。如果用static修饰变量,不论这个变量是全局的还是局部的都是存储在静态数据区。下面分开来讲:

如果用static修饰全局变量,我们称其为静态全局变量。

我们用static修饰全局变量的主要目的就是:使得其作用域仅限于变量被定义的文件中(即从变量定义处到本文件结尾处),其它文件不论通过什么方式都不能访问。

如果用static修饰局部变量,我们称其为静态局部变量。

我们用static修饰局部变量的目的主要有两个:

1)         在某个函数体里面定义的静态局部变量,只能在本函数体被访问,即使同一个文件的其它函数也访问不了。

2)         静态局部变量总存储在静态数据区,所以即使这个函数运行结束,这个静态局部变量的值不会被销毁,函数下次使用时仍然要用到这个值。

 下面给出一个例程:

 
#include <stdio.h>
static int j;  // 静态全局变量

int fun1(void)
{
     static int i = 0;
     i++;
     return i;
}
int fun2(void)
{
     j = 0;
     j++;
     return j;
}
int main(int argc, char *argv[])
{
     int k = 0, m = 0, n = 0;
     for(k=0; k<10; k++)
     {
         m = fun1( );
         n = fun2( );
         printf("%d,%d\n", m, n);
     }
     return 0;
}
 
结果:
1,1
2,1
3,1
4,1
5,1
6,1
7,1
8,1
9,1
10,1

 从例程的运行结果可以看出:

对于fun1( ),运行一次之后,变量i保持了原来的数据,并没有销毁,而是在下一次调用的时候继续使用,所以才会有1、2、3…10这样的结果。而对于fun2( ),运行一次之后,变量j的值被销毁了,所以第二次调用结束j仍然保持原值“1”,所以循环十次,每次都是1

2、Static修饰函数

在函数前加static,则此函数成为静态函数(内部函数),我们用static修饰函数的主要目的是:用来表示不能被其它文件访问的一个函数(和用static修饰全局变量的目的一样,都是不允许其它文件访问)。这样一来便有一个好处:程序员不用担心自己编写的函数与其他文件的函数同名

(1)静态局部变量数据属于静态存储类别,在静态存储区内分配内存单元,在整个程序运行期间都不释放。而自动变量(即动态局部变量)属于动态存储类别,占动态存储区空间而不占用静态存储区空间,函数调用结束后立即释放空间。

(2)静态局部变量时在编译时被赋值的,即自始至终只赋值一次,在程序运行时它已经有初值。以后每次调用函数时不再重新赋初值而只是保留上次函数调用结束时的值。而自动变量赋初值,不是在编译时进行的,而是在运行时进行,所以每调用一次函数就赋一次初值。

(3)如在定义局部变量时不赋初值,则对静态局部变量来说,编译时自动赋一个初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值,则它的值是一个不确定的值。这是由每次动态分配的内存单元不同所决定的。


五、static和extern的总结
1.extern可以用来声明一个全局变量,但是不能用来定义变量
2.默认情况下,一个全局变量是可以供多个源文件共享的,也就说,多个源文件中同名的全局变量都代表着同一个变量

3.如果在定义全局变量的时候加上static关键字,此时static的作用在于限制该全局变量的作用域,只能在定义该全局变量的文件中才能使用,跟其他源文件中的同名变量互不干


------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值