函数和变量

参考自:《C语言程序设计(第五版)》

一、定义函数
类型名 函数名(形参表列)
{
    函数体
}
//形参表列可为空,不填或填void
//类型名表示函数返回值类型,无返回值填void。
二、调用函数

1、函数调用时的数据传递

1/ 形式参数和实际参数
在定义函数时函数名后面括号中的变量名成为“形式参数”或“虚拟参数”;
在主调函数中调用一个函数时,函数名后面括号中的参数为“实际参数”,可以是常量(如1)、变量(如a)、表达式(如a+b)。

e.g.
int max(int a,int b) //a和b是形参
{
    return a + b;
}
int m = 1;
int n = 2;
int t = max(m,n); //m和n是实参

2/ 实参和形参间的数据传递
在调用函数过程中,系统会把实参的值传递给被调用函数的形参。或者说,形参从实参得到一个值。
该值在函数调用期间有效,可以参加该函数中的运算。

形参与实参的类型应相同或赋值兼容。

2、函数调用的过程

  • 定义函数中指定的形参,在未出现函数调用时,他们并不占内存中的存储单元。
    在发生函数调用时,函数的形参才被临时分配内存单元。
  • 调用结束,形参单元被释放。
三、声明函数

1/ 在一个函数中调用另一个函数需要具备条件:

  • 被调用的函数必须是已经定义的函数(是库函数或用户自己定义的函数)。
  • 若使用库函数,应在本文件开头用#include指令将调用有关库函数时所需用到的信息“包含”到本文件中。
  • 若使用用户自己定义的函数,而该函数的位置在调用它的函数的后面(在同一个文件中),
    应在主调函数中对被调用的函数作声明

2/ 声明的作用

把函数名、函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查函数是否合法

程序进行编译时是从上到下逐行进行的,如果没有声明,当编译到调用的地方时,编译系统无法确定如上例的max是不是函数名,也无法判断实参的类型和个数是否正确,因而无法进行正确性的检查。

3/ 声明方式:

函数类型 函数名(参数类型1 参数名1,...,参数类型n 参数名n);
或
函数类型 函数名(参数类型1,...,参数类型n);

四、局部变量和全局变量

1、局部变量

  • 在函数内部定义的变量只在本函数范围内有效,在函数以外不能使用它们
  • 在复合语句内定义的变量只在本复合语句范围内有效
float f1(int a)
{
    int b,c;  //a,b,b只在这个大括号内有效
    ...
}
int main(){
    int m,n;
    ...
    return 0;   //m,n只在这个大括号里有效
}

注:

  • 主函数中定义的变量(如m,n)也只在主函数中有效,并不因为在主函数中定义而在整个文件或程序中有效;
  • 不同函数中可以使用同名的变量,它们代表不同的对象,互不干扰。
  • 形参也是局部变量;
  • 在一个函数内部,可以在复合语句中定义变量,这些变量只在本复合语句中有效,这种复合语句也称为“分程序”或“程序块”。
int main()
{
   int a,b;
   ...
   {                  //----------复合语句开始
       int c;
       c = a + b;     //c在此复合语句内有效
       ...
   }                  //----------复合语句结束
}

2、全局变量

程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。

在函数内定义的变量是局部变量,在函数之外定义的变量称为外部变量,外部变量是全局变量(也称全程变量)

全局变量可为本文件中其他函数共用。有效范围从定义变量的位置开始到本源文件结束。

注:

  • 全局变量在程序的全部执行过程中都占用存储单元,而不是仅在需要时才开辟单元。

所以建议不在必要时不要使用全局变量。


五、变量的存储方式和生存期

1.动态存储方式与静态存储方式

变量按作用域方面可分为:全局变量局部变量

变量按变量值存在的时间(即生存期)可分为:静态存储方式动态存储方式

  • 静态存储方式:在程序运行期间由系统分配固定的存储空间的方式;
  • 动态存储方式:在程序运行期间根据需要进行动态的分配存储空间的方式。

内存中供用户使用的存储空间可以分为3部分:

  • 程序区
  • 静态存储区
全局变量全部存放在这个区,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。

在程序执行过程中他们占据固定的存储单元,而不是动态进行分配和释放。
  • 动态存储区
 存放以下数据:
 
 
 - 函数形式参数。在调用函数时给形参分配存储空间。
 - 函数中定义的没有static关键字的变量,即自动变量。
 - 函数调用时的现场保护和返回地址等。
 
 在函数调用开始时分配动态存储空间,函数结束时释放这些空间。
六、变量的存储类别

在C中,每个变量和函数都有两个属性:数据类型数据的存储类别

局部变量的存储类别

1、自动变量(auto变量)

函数的局部变量,若不专门声明为static存储类别,则都是动态地分配存储空间,数据存储在动态存储区。

int f(int a)
{
   auto int b,c = 3; //定义b,c为自动变量,auto可以省略
   ...
}

2、静态局部变量(static)

  • 静态局部变量属于静态存储类别,在静态存储区分配存储单元。在程序整个运行期间都不释放

  • 对静态局部变量是在编译时赋初值的,即只赋初值一次,在程序运行时它已有初值

    以后每次调用函数时,不再重新赋初值而只是保留上次函数调用结束时的值。

    而对于自动变量赋初值,不是在编译时进行的,而是在函数调用时进行的,每调用一次函数重新给一次初值,相当于执行一次赋值语句。

  • 若在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符’\0’(对字符变量)。

    而对自动变量,它的值是一个不确定的值,这是由于每次函数调用结束后存储单元已释放,下次调用时又重新另分配存储单元,而所分配的单元中的内容是不可知的。

  • 静态局部变量依旧是局部变量,只能被本函数引用。

3、寄存器变量(register变量)

一般变量的值是存放在内存中的,当程序用到哪一个变量时,由控制器发出指令将内存中该变量的值送到运算器中。

可以将一些使用频繁的局部变量(如一个函数中执行10000次循环,每次循环都要引用某局部变量,则为存取变量的值要花费不少时间),将局部变量的值放在CPU的寄存器中,需要用时直接存寄存器取出,不必到内存中去存取,可以提高执行效率。

因为对寄存器的存取速度要远高于对内存的存取速度。

register int f;  //定义f为寄存器变量

全局变量的存储类别

1、extern作用域扩展

extern对外部变量作“外部变量声明”,表示把该外部变量的作用域扩展到此位置

因为外部变量是在函数外部定义的全局变量,作用域是从变量的定义处开始,到本程序文件的末尾。

1/ 如在第10行定义了外部变量,但是在同文件的第五行处的一个函数里想用这个变量,则要声明;
如果这个变量的定义写在了文件的开头则不需要再声明;

2/ 如果一个文件想用另一个文件的外部变量,则用extern声明。
A文件:
int A;
...

B文件:
extern A;
...

注:
把建立存储空间的声明称为定义,不需要建立存储空间的声明称为声明。

所以extern是声明。

2、static作用域限定

加了static的外部变量,称为“静态外部变量”,只能用于本文件。

回顾总结static:

  • 对局部变量用static,把它分配在静态存储区,该变量在整个程序执行期间不释放,其所分配的空间始终存在;
  • 对全局变量用static,则该变量的作用域只限于本文件模块(即被声明的文件中)。

七、内部函数和外部函数

1.内部函数:只能被本文件中其他函数所调用的函数。(又称静态函数)(static)

//定义内部函数时,前面加上static。
static 类型名 函数名(形参表);

//与其他文件中内部函数同名也互不干扰。

2.外部函数:可供其他文件调用。(extern)

//定义外部函数时,前面加上extern。(extern可省略,默认为外部函数)
函数首行:extern int fun(int a,int b);

在另一个文件想使用这个函数时,需要先声明,要加extern关键字,表示该函数是在其他文件中定义的外部函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值