函数分类
1.标准库函数
2.用户自定义函数(必须先定义才能调用)
函数组成
1.函数说明部分(函数类型、函数名、形式参数名)
2.函数体(类型说明部分、可执行语句部分)
函数定义
1.有参函数的一般形式
函数类型 函数名(参数表)
{
函数体
}
2.无参函数的一般形式
函数类型 函数名(void)
{
函数体
}
3.空函数(无参数)
函数类型 函数名(void)
{
}
函数调用
1.形式
函数名(实参表);
对于无参函数,调用时没有参数表,但不可忽略函数名后的括号。
2.分类
(1)将函数当作一个功能语句。
(2)要求函数有返回值,并参与表达式(函数表达式)的运算。
(3)将函数的返回值作为另一个函数的参数。
3.形式参数与实际参数
形参:定义函数时使用的参数(变量),标识了该函数使用时传递数据的个数和类型,没有具体值。
实参:函数调用时使用的参数,将具体的数据传递给相应的形参,供函数使用。
注意:
(1)形参和实参的类型、个数和次序的一致。
(2)形参出现在函数定义中,只能在该函数体内使用。函数未调用时,形参不占内存中的存储单元,只在函数被调用时才分配内存单元。函数调用结束后,形参所占用的内存单元被释放。
(3)实参可以为常量、变量、表达式或函数值,函数调用时必须有确定的值,以便把这些值传递给形参。因此,应预先用赋值、输入等方法使实参得到确定的值。
(4)实参对形参的数据传送是“值传送”,即是单向的,只能由实参传送给形参,即形参的变化不影响实参。
(5)在内存中,实参和形参占用不同的单元,即使是同名也互不影响。
函数返回值
函数返回值也称函数值,一般通过return(返回语句)得到,一个函数体中可以包含多个return语句,程序执行到哪一个就返回哪一个的结果。
1.形式
return;
return 表达式;
return(表达式);
2.类型
(1)定义函数时,一般指明函数的返回值类型,没有说明时,默认为整形(int)。
(2)函数返回值的数据类型一般和函数体中return语句的表达式类型一致,不一致的话,系统会自动进行类型转换,使return语句返回值的类型与函数类型统一。
(3)void类型
若函数不需要返回值,可将函数类型定义为void,即“空类型”或“无类型”。
函数类型声明
用户自定义的函数若在程序中被其他函数调用(主调函数),且其函数定义在主调函数之后,则需在主调函数中对该函数进行“函数类型声明”。
1.格式
函数返回类型 函数名(参数类型1,参数类型2…);
注意:
(1)函数类型声明不包括形参变量名和函数体。
(2)函数类型声明和函数定义必须在返回类型、函数名、参数类型上完全一致。
2.说明
(1)被调用函数的定义出现在主调函数前,可省去对被调函数的声明。
(2)若在所有函数定义前,在函数外部对各函数进行了声明,在主调函数可省去对被调函数的声明。
(3)对库函数调用不用声明,但须用文件包含命令将其头文件包含。
数组或字符串作为函数参数
1.数组作为函数的参数
数组元素 (下标变量)只能作为函数的实参,是值传递
数组名 作为函数参数是地址传递,传递整个数组
(1)一维数组名作为函数实参
用数组名作函数参数,此时实参与形参都应用数组名。
在执行函数时形参数组与实参数组从首地址起共享存储单元,所以对形参数组的说明要简单,必须说明数组的类型、名称(可以与实参数组相同)和维数,维大小可以不必说明。
(2)多维数组名作为函数实参
可以指定每一维的大小,也可省去第一维的大小说明,但从第二维开始,每一维的大小必须说明。
例如:
int array [] [10];
和int array [5] [10];
都是合法的
int array [5] [];
和int array [] [];
都是非法的
2.字符串作为函数参数
在C语言中,字符串是以一维数组的形式存放的,用字符数组名作为函数的参数,在被调函数中可以改变字符串的内容,在主调函数中可以得到改变了的字符串。
函数的嵌套调用和递归调用
1.函数的嵌套调用
函数定义时不允许嵌套,但可以嵌套调用。
嵌套调用过程示意图:
2.函数的递归调用
(1)形式
a.直接递归
int fn1(int x)
{
if (x>5)
return fn1(x-1); /*在函数中调用自身*/
else
return 5;
}
b.间接递归
int fn1(int x)
{
int a=fn2(x+1); /*在fn1函数定义中调用fn2函数*/
}
int fn2(int y)
{
int b=fn1(y-1); /*在fn2函数定义中调用fn1函数*/
}
(2)消去递归
大多数递归函数都可以用非递归函数来代替。
大部分函数的递归形式比非递归形式运行速度慢(附加的函数调用增加了时间开销)。
递归函数可以简化程序设计,有些问题不用递归算法无法解决(例如:汉诺塔问题)
变量存储类型
1.局部变量与全局变量
(1)局部变量
在函数内部定义的变量,也称内部变量。
a.主函数main()中定义的变量也是局部变量,只在main()函数体内有效。main()函数也不能使用其他函数定义的局部变量。
b.在不同的函数中可以使用相同的局部变量名,互不干扰。
c.函数的形参也是局部变量。
d.在复合语句中也可以定义局部变量,其有效范围只在该复合语句当中。
e.局部变量在函数运行时分配存储空间,函数执行完毕,程将自动释放所分配的存储空间。
(2)全局变量
在函数外部定义的变量,也称外部变量。外部变量不属于任何一个函数。
a.外部变量的定义必须在所以函数之外,且只能定义一次。
b.外部变量的声明是在使用该外部变量的函数之内,且可多次出现。
c.外部变量在定义时分配存储单元,且可初始化;声明时不能再赋值。
2.自动变量
自动变量的定义形式是在变量类型前加关键字auto。
例如:
void func(void)
{
auto int a,b,c; /*定义三个自动变量a,b,c*/
...
}
关键字auto可以省略。
3.寄存器变量
变量的值一般存放在内存中,如果在程序中需要对某个变量频繁使用,为提高执行速度,可以将局部变量定义为寄存器型。寄存器变量的值存放在CPU的寄存器中,使用时直接从寄存器取出进行计算,而不必访问内存。
寄存器变量定义的形式是在变量的前面加关键字register。
例如:
void func(void)
{
register int x,y,z; /*定义三个寄存器变量x,y,z*/
...
}
4.外部变量
外部变量的值存放在静态存储区,整个程序执行期间均占据存储空间。
(1)允许其他源文件中的函数访问
默认情况下,一个全局变量允许被其它源文件访问,但需要在访问它的文件中,用关键字extern说明。
(2)不允许被其他源文件访问
在定义外部变量时前面加关键字static,这样定义的外部变量(全局变量)称为“静态外部变量”。
在多人合作的程序开发中,将全局变量声明为静态外部变量可以避免模块间的冲突和误操作。
5.静态变量
(1)内部静态变量
(2)外部静态变量
内部函数与外部函数
1.内部函数(“静态函数”)
只能在源文件内使用
定义形式:
static 函数类型 函数名(参数表)
{
函数体
}
static:静态存储类型标识符
2.外部函数
在定义它的文件之外的函数中使用
定义形式:
extern 函数类型 函数名(参数表)
{
函数体
}
extern:外部存储类型标识符
在函数定义时如果省略extern,则系统默认其为外部函数。
其他文件需要使用外部函数时要对函数进行声明,并在函数类型名前加上extern,表明是在调用一个外部函数。
(文章内容部分借鉴教材,仅用于个人记录。)