学习笔记7 —— 函数

一、自定义函数

1.函数的定义

函数在使用前也需要定义,定义的格式如下:

数据类型 函数名([数据类型 参数1],[数据类型 参数2]...)
{
	语句
}

大多数函数都会通过return语句返回一个值,前面函数名之前的数据类型就是该返回值的类型。函数名和变量名的定义规则一样。即使函数没有参数(即使参数个数为0),小括号也是不可省略的。
函数是不允许嵌套定义的。但可以在一个函数中调用另外一个函数。

2.函数的调用

格式:

函数名([参数1],[参数2]...);

函数名后面的小括号内根据需要给出相应的参数。同样地,即使不需要参数,这个小括号也不能省略。
函数调用时的小括号内的参数称为实际参数,简称实参,而把函数定义时的小括号内的参数称为形式参数,简称形参。当函数执行时,会将实参的值赋给相对应的形参,所以实参的类型、顺序、和数量要和形参的类型、顺序和数量一一匹配。
在进行函数调用时,程序的执行流程从当前语句转入函数,在函数执行完毕后,再返回至函数调用的语句,继续向下执行。

3.函数的声明

格式:将函数的函数头部分取出来,后面加上一个分号。
在函数声明中,形参的变量名是可以被省略的,但形参的数据类型不可省略。
自定义函数在主函数之前,所以在主函数中调用自定义函数时,不需要进行函数的声明。
自定义函数在主函数之后,所以在主函数中调用自定义函数时,需要进行函数的声明。
函数的声明位置和次数是无限制的,我们可以把函数声明和函数的调用放在同一个函数中,那么在该函数中,函数声明可以覆盖之后的所有函数调用,但其它函数中的函数调用仍然需要进行函数声明;也可以把函数声明放于包含函数调用的函数之前,这样函数声明可以覆盖其后的所有函数中的函数调用。

二、函数的分类

1.无返回值的函数

void放在函数名的前面,用来表示这个函数是没有返回值的。
无返回值的函数有什么好处呢
我们编写一个名为showInfo的无返回值函数

void showInfo()
{
	printf("~~~~~~~~~~~~~~~\n");
	printf("please enter an integer:\n");
	printf("~~~~~~~~~~~~~~~\n");
}

1、可以精简代码。
2、便于代码维护,以后需要改动的就改动函数而不用去主函数逐一修改。

2.有返回值的函数

如果这个函数要把数值返回给调用函数的地方,就是一个有返回值的函数了

int getUserEnter()
{
	int n;
	printf("~~~~~~~~~~~~~~~\n");
	printf("please enter an integer:\n");
	printf("~~~~~~~~~~~~~~~\n");
	scanf("%d",&n);
	return n;
}

函数名之前的int,表示函数是有返回值的,而且返回值的类型是int
在返回值函数中,数据类型必须是非void的,而且在函数体中必须有return语句。函数能够通过return语句返回一个值,即采用return表达式的形式,return关键字后面的表达式的类型必须和函数名前所定义的数据类型匹配。一旦return语句被执行它会结束函数的执行流程,并将表达式的值返回到函数调用的地方。

3.无参函数

所谓无参函数,就是没有参数的函数,即函数名后面是一对空的小括号。
定义无参函数的时候,小括号内可以是空的,也可以放入一个void关键字。

void showInfo2(void)
{
	printf("~~~~~~~~~~~~~~~\n");
	printf("please enter an integer:\n");
	printf("~~~~~~~~~~~~~~~\n");
}

4.有参函数

和无参函数相对应的是带参函数,也就是需要参数的函数,即在函数名后面的小括号内必须有一个或多个的参数,如果是多个参数,参数之间使用逗号进行分隔。

void printResult(int res)
{
	printf("result:%d\n",res);
}

最后总结一下四种类型的函数头定义示例
void func()
void func(int a,float b,double c)
int func()
int func(int a,float b,double c)

三、再谈函数调用

1.函数的嵌套调用

函数是不能嵌套定义的,但是函数是可以嵌套调用的。所谓函数的嵌套调用,就是在一个函数体中又出现了函数调用语句。简单说,就是函数又调用了函数。

void A()
{
	printf("Start function A.\n");
	printf("End function A.\n");
}
void B()
{
	printf("Start function B.\n");
	A();
	printf("End function B.\n");
}
int main()
{
	printf("Start main function.\n");
	B();
	printf("End main function.\n");
	return 0;
}

执行后结果为
Start main function.
Start function B.
Start function A.
End function A.
End function B.
End main function.

2.函数的递归调用

(1)递归调用与递归函数
函数的递归调用的原理很简单,就是函数的自身调用。它其实就是一种特殊的函数嵌套调用。C语言允许函数调用自身,也就是在一个函数的函数体中,又调用了函数自己。

void A()
{
	A();
}

函数A是一个递归函数,通过它的执行能引起函数的递归调用。
(2)递归调用的终止
怎么才能让递归调用终止呢?还得依靠我们的老朋友return语句。也就是在进行递归调用时,需要在满足某种条件的情况下,通过return语句来终止递归调用。
(3)递归调用的算法原理
大家有没有考虑过,为什么要有递归调用?什么情况下才需要使用递归调用?这就需要了解递归调用的算法原理,也就是需要如何通过递归调用来达到所要求的功能。
它的主体思想就是对于一个我们不容易完成的、比较大的目标,通过不断地对它进行分解化小,直到小到极致,也就是可以轻松完成的时候,再反过来一点点由小到大,最终完成那个大的目标。
(4)编写递归函数
编写一个递归函数,能够计算1~n的累加值,其中n的值大于等于1,并在主函数中调用该函数。

int sum(int n)
{
	if(n == 1)
		return 1;
	return sum(n - 1) + n;
}

四、再谈变量

1.自动变量与静态变量

变量在定义的时候,除了需要指定数据类型之外,还可以指定它的存储类型。在C语言中,可以使用autostatic两个关键字来指定变量的存储类型。

auto int a;//自动存储类型变量,简称自动变量
static int b;//静态存储类型变量,简称静态变量

默认情况下,在函数中定义的变量属于自动变量,所以前面的auto关键字是可以省略的,即auto int a与int a是一样的,都表示自动变量。

(1)存储位置
代码区:程序文件的二进制码
静态区:字符串常量、全局变量、静态变量等
堆:由程序员管理的内存区域
栈:自动变量、函数参数等,这是由系统管理的内存区域

栈是由系统管理的一块内存区域,例如我们定义一个自动变量时,系统会根据变量的数据类型大小在栈内开辟一块内存,当不再使用这个变量时,系统会将它所使用的内存回收。
而堆是由程序员管理的一块内存区域,其中内存的分配、使用和回收都是由程序员通过调用相应的内存管理函数来完成。
(2)初始化
自动变量不会被默认初始化,而静态变量会被默认初始化(默认为0)。
(3)生命期
只有在变量的生命期内,用户才可以去使用这个变量。在之前和结束都无法使用这个变量。
自动变量的生命期是从变量所在的函数被执行后,变量被定义时开始,至函数结束时,其生命期结束,也可以说自动变量是属于函数生命期。
静态变量的生命期是从程序运行时开始,至程序结束时,其生命期结束,也可以说静态变量属于程序生命期。

2.局部变量与全局变量

按照定义的位置不同,变量还可以分为局部变量与全局变量,在函数内定义的变量是局部变量,包括形参变量,在函数外定义的变量是全局变量。

int a;
void test(int b)
{
	int c;
	static int d;
}

a全局变量;b、c、d局部变量
(1)作用域
生命期控制着变量的生命权限,而作用域控制着变量的访问权限。
局部变量的作用域从定义开始,直到函数的结尾处。
全局变量的作用域是所有程序文件。
(2)全局变量的声明
函数的作用域也是所有的程序文件,所以全局变量和函数拥有同样的作用域。而且在使用时,全局变量与函数也非常相似,即全局变量在使用前也要进行声明。
在其它文件使用这个文件的全局变量之前,我们可以对它进行声明

extern int a;

注意:在对全局变量进行声明时,不要对它进行初始化。

(3)全局变量的存储类型
全局变量存储在静态区,和静态变量一样,也是属于静态存储类型,因此它拥有和静态变零一样的生命期,即程序生命期。
和静态变量另外一个相同之处是,全局变量在定义时,如果没有对其初始化,编译器会自动将其值初始化为0。

3.只读变量

只读变量只能被访问,而其值是不允许被修改的。但只读变量不是常量,因为它的值并非真正地无法改变,通过后面介绍的指针,还可以间接地修改它的值。

const int a = 10;

能访问它的值,但不能通过变量名来修改它的值。

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是北豼不太皮吖

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值