第七章 函数(六)

六、变量的存储和引用与内部和外部函数

1、变量的存储类别

函数(五)讲解了局部变量和全局变量,这是从变量的作用域角度来划分,如果换一个划分角度,从变量存在的时间(生存期)角度来划分,则可以划分为"静态存储变量"和"动态存储变量",从而就引出了"静态存储方式"和”动态存储方式"。

1)静态存储方式:在程序运行期间分配固定的存储空间的方式。

2)动态存储方式:在程序运行期间根据需要进行动态的分配存储空间的方式。

程序在内存中存储空间图:

存储空间分成三个主要部分:

程序代码区、静态存储区和动态存储区,程序执行所需的数据就放在静态存储区和动态存储区中,存储区就理解成内存。

全局变量(在函数的外部定义的)放在静态存储区中,程序开始执行时给全局变量分配存储区,程序执行完毕后释放这些存储区,在程序执行过程中它们占据固定的存储单元而不是动态地分配和释放。

那么动态存储区中存储哪些数据?

1)函数形参,函数形参被看作局部变量

2)局部变量,在函数内定义的一些变量

3)函数调用时调用现场的一些数据和返回地址等

一般来说,这些数据在函数调用开始时分配存储空间,函数调用完毕后这些空间就被释放掉了(也称为回收)。这种分配和释放就认为是动态的,如果两次调用同一个函数,分配给此函数的局部变量的存储空间地址可能是不同的。

2、局部变量的存储方式

1)传统情形

函数中的局部变量,一般来说,都是动态分配存储空间,也就是说存储在动态存储区中,这些变量分配和释放存储由系统自动处理,函数被调用分配存储间,函数执行完成后自动释放其所占用的存储空间。

2)特殊情形

有时希望函数中局部变量的值在函数调用结束后不消失(不被系统自动释放)而保留原值,也就是说,它占用的存储单元不释放,在下次调用这个函数时该变盘保存的值,就是上次这个函数调用结束时的值,这是可以做到的,只需指定该局部变量为"局部静态变量”,用static关键字加以说明即可。

例:传统的函数内的局部变量输出求值结果

执行上面的代码可以看到,程序连续输出三次相同的结果,如下:

现在,修改上述的自定义函数funcTest(),修改"int c=4;"这行的容,其他内容不变,修改后的内容如下:

再次执行上面的代码可以看到,程序次输出的结果发生了改变,如下:

上面的代码,通过分析执行的结果不难发现,定义一个变量时,在前面加上static(局部静态说明)变量的表现就不同了,具体有如下几点不同:

(1)在静态存储区中分配存储单元,程序整个运行期间都不释放

(2)局部静态变量是在编译赋初值的只赋初值一次,在程序运行的时候它已经有了初值,以后每次调用函数时不再重新赋初值,只是保留上次函数调用结束时的值,而普通变量的定义和赋值是在函数调用时才进行

(3)定义局部静态变量,如果不赋初值,则编译时自动给其赋初值0,而常规变量如果不赋初值,则它是一个不确定的值

(4)虽然局部静态变量在函数调用结束后仍然存在,但在其他函数中是不能引用的。

(5)局部静态变量长期占用内存,降低了程序可读性(当多次调用该函数时,往往弄不清当前该静态变量的值是多少)

所以得到一个结论,如非必要,不要过多使用局部静态变量。

3、全局变量跨文件引用

这个话题在前面简单说过,在这里将进行更详细的讲解,因为在实际的工作盘跨文件引用的情形经常发生。

一个项目可以通过编译、链接等步骤最后生成一个可执行文件,在Windows下可执行文件就是扩展名为exe的文件,而在Linux下可执行文件就是具有可执行权限的文件。

在Xcode中,一个项目由一个或多个源程序文件组成,一般在Xcode中,C语言的源程序文件扩展名为.cpp(或c),因为目前演示的代码比较简单,因此只用了一个源程序文件MyProject.cpp,也可以建立另一个源程序文件。

例:现在准备新建立个叫作MyProject2.cpp的源程序文件。编译的时候,Xcode会把这些源程序文件分别编译,最终统一链接成为个可执行文件。

(1)在Xcode左侧单击右键,打开所在的文件夹,也可以去桌面直接打开文件夹。

(2)复制后重命名,回到Xcode,在左侧文件夹上单击右键,选add添加文件,添加到项目中来。也可以在左侧单击右键,创建新文件。

如果在myProject2中定义一个全局变量,在myProject中如何调用?

myProject2中的代码:

int g_a=6;

myProject中的代码:

extern int g_a;  //不加extern,会报错:Use of undeclared identifier 'g_a'

printf("g_a=%d\n",g_a);

如果想在一个源程序文件中引用另外个源程序文件中定义的全局变量,也可以用extern关键字,在引用该全局变量的源程序文件的开头做外部变量说明即可,以表明在例子中出现的变量是一个已经在其他源程序文件中定义过的外部变量,本文件不必为它再分配内存。

一般来说个全局变量的作用域是从它定义的点,到整个源程序文件结束,但是,通过使用extern,将它的作用域扩大到了有extern说明的其他源程序文件,如果再有更多的源程序文件中要引用这个全局变量,也要在这些源程序文件的开头用extern来说明这个全局变量为外部全局变量。

这种跨文件使全局变量的extern关键字用法,一般都是要求将extern说明在源程序文件的开头〈一般位于#include语句行之后)。.另外,使用这种跨文件的全局变量要很小心,因为在某个源程序文件的某个函数中改变了这些全局变量的值,也会影响到其他源程序文件中使用该全局变量值的函数。

如果希望某些全局变量只能在本源程序文件中被使用,不想被其他源程序文件进行跨文件引用,那也很简单,在定义这个全局变量时在是前面加上static关键字。

myProject2中的代码:

static int g_a=6;

这个时候如果其他文件再使extern int g_a;时,编译时就会出现诸如"无法解析的外部符号"之类的错误提示,大家可以自己测试并观察编译结果。

这样做有个优点:如果在myProject.cpp和myProject2.cpp中定义了两个相同名字全局变量,那么如果不加static,则编译会报错。但如果在定义这两个全局变量时,都在前而加了statlc关键字,则自己的源程序文件用自己文件里定义的全局变量,互相不受影响,编译链接时也不会再报错。

4、函数的跨文件调用

根据在某个源程序文件中定义的函数能否被其他源程序文件所调用,将函数分为内部函数和外部函数。

1)内部函数

只能被本文件中其他函数调用,定义内部函数时,在最前面加static关键字即可形式

例:

static  返问类型  函数名(形参表){ ... }

内部函数又称为静态函数,使用内部函数,可以使函数只局限于其定义所在的源程序文件中,所以不同源程序文件中的同名函数彼此不受干扰,试想,如果分工不同的两个人编写两个不同的.cpp源程序文件,如果他们所写的函数同名,则在编译链接时会报错,如果用static修饰这些函数,那么即使所起的函数名相同,也互相不受影响(因为这些函数被限制在当前定义所在的源文件中)

2)外部函数

定义一个函数时,如果在其前面不使用static关键字修饰,它就是外部函数形式。

例:

返问类型  函数名(形参表){ ... }

在需要调用此函数的其他源程序文件中,只需要增加该函数的函数声明即可。

例:

现在希望在myProject2函数中调用这个函数,那么首先要在myProject中的开头部分书写这个函数的声明。

开发技巧:可以将这些外部函数的声明(不限于外部函数声明,其实可以针对所有函数的声明)语句,统一放到一个.h头文件中,任何源程序代码文件(.cpp文件)只要在开头#include这个.h头文件,则在这些源程序代码文件中,就可以任意调用其他源程序代码中所定义的外部函敷。

5、static关键字法总结

1)函数内部在定义一个局部变量时,在前面使用static关键字,这个变量会保存在静态存储区,在编译的时候被初始化,如果不给初始值,它的值会被初始化为0,并且,下次调用该函数时该变量保持上次离开该函数时的值。

例:

voidfunTest(){

    static int c=4;  

}

2)在定义全局变量时,前面使用static关键字,那么该全局变量只在本文件用,无法在其他文件中被引用(使用)。

static int g_a;

3)在函数定义之前增加static,那么该函数只能在本源程序文件中调用,无法在其源程序文件中调用。

例:

static void fun(){ … };

  • 14
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值