目录

一、自定义函数

二、函数参数 、传值调用和传址调用

2、1传值调用

2、2传址调用

三、函数的嵌套和链式访问

四、函数递归


一、自定义函数

C语言中有两类函数,一类是库函数,另外一类是自定义函数。自定义函数从字面意思上理解就是自己定义的函数,因为库函数不能满足大家的所有需求,所以有时候需要程序员自己编写属于自己的函数。

自定义函数的语法结构为:

ret_type fun_name(variable )

{

statement ;

}

ret_type 是函数的返回类型

fun_name是函数名

variable是函数的变量

statement是语句;它同大括号一起组成函数的函数体

看下面的一个代码:

#includeint ADD(int x, int y){returnx + y;}int main(){int number1 = 0;int number2 = 0;printf("请输入两个数字: ");scanf("%d%d",&number1,&number2);int ret = ADD(number1, number2);printf("%d+%d=%d ",number1,number2,ret);return 0;}

在这里面我们使用了函数ADD实现两个数的求和;ADD函数中:

int ADD(int x, int y)
{
return x + y;
}

int 是返回类型

ADD是函数名

{

return x + y;

}

是函数体

二、函数参数 、传值调用和传址调用

函数参数分为实际参数和形式参数;真实传递给函数的参数叫实际参数;形式参数是指函数名后面括号中的变量。在下面函数的传值调用与传址调用中可以更深层次的体会这两个参数的意义。

2、1传值调用

看下面代码:

#includeint ADD(int x,int y){return x + y;}int main(){int a = 20;int b = 30;int ret = ADD(a, b);printf("%d",ret);return 0;}

在这里main函数里面的ADD函数里面的变量a与b叫实际参数(实参);然后main函数外边的函数名ADD里面的变量x与y叫形式参数(形参);之所以是传值调用是因为形参只是实际参数的一份临时拷贝,改变形式参数的值并不改变实际参数的值。他两不是指向同一个地址,可以通过下面的图片得到更深层次的理解:

上图可以看出,a的地址与接收它的形式参数x的地址不是同一个地址;b的地址与接收它的形式参数y的地址不是同一个地址。这里在x与y调用之后拥有了自己的空间,同时拥有了和实参一样的内容,可以简单认为:形参实例化之后其实相当于实际参数的一份临时拷贝。下面的一张图片可以说明上面这段字的内容。

2、2传址调用

通过下面的代码讲解传址调用:

#includevoid exchange(int* x, int* y){int tmp = *x;*x = *y;*y = tmp;}int main(){int n =20;int k =30;printf("交换前:n=%dk=%d\n", n, k); exchange(&n, &k); printf("交换后:n=%dk=%d", n, k);return 0;}

通过上面可以看到,实际参数n与形式参数x的地址是一样的,实际参数k与形式参数y的地址是一样的,也就是说n与x,k与y分别指向了同一个内存空间;这就是传址调用的特点:

传址调用就是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。

这种方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操作函数外部的变量

三、函数的嵌套和链式访问

函数的嵌套就是一个函数里面包含另外一个函数,值得注意的是函数可以嵌套使用;但是函数不能嵌套定义。

#includevoid hello_world(){printf("hello world\n");}void test(){hello_world();}int main(){test();return 0;}

例如上面的例子就是函数嵌套的典型案例;main函数里面嵌套了test()函数,test()函数嵌套使用了hello_world()函数

函数的返回值作为函数的参数就叫链式访问。

#includeint ADD(int x, int y){return x + y;}int main(){int a = 0;int b = 20;int ret = ADD(a, b);printf("%d ",ret);return 0;}

上面代码a+b的返回值20赋值给ret之后;再打印ret的结果;可以做如下修改:

#includeint ADD(int x, int y){return x + y;}int main(){int a = 0;int b = 20;printf("%d ", ADD(a, b));return 0;}

也就是直接把返回值作为printf函数的参数输出;这就叫链式访问。

四、函数递归

程序调用自身的编程技巧叫递归,但是注意递归有限制条件,当满足这个限制条件时候,递归不在继续;每次递归之后越来越接近这个限制条件。

以一个例子讲解:用递归的方式打印n的k次方(使用Pow(n,k))

n的k次方可以转化为n*n的k减1次方

n的k-1次方可以转化为n*n的k减2次方

………………………………………………

分析:当k为大于0的数的时候,返回值为n*Pow(n,k-1)

当k为小于0的数的时候,返回值为1/Pow(n,k);

当k为0的时候,返回值为1;

代码如下所示:

#includedouble Pow(int n, int k){if (k > 0){return n* Pow(n, k - 1);}else if (k < 0){return 1/ Pow(n, -k);}else{return 1;}}int main(){int n = 0;int k = 0;printf("请输入两个数:");scanf("%d%d",&n,&k);doubleret = Pow(n, k);printf("%d的%d次方为%lf",n,k,ret);return 0;}

递归可以理解为传递和回归,下面一个例子来讲解这个思想:

#includeint Power(int n){if (n>1){return n * Power(n - 1);}else {return 1;}}int main(){int n = 0;scanf("%d",&n);int ret = Power(n);printf("%d",ret);}

整个递归过程如下图所示:

函数的递归有两个层面的理解,第一个层面是传递,如上图中红色线条部分,另外一个层面是回归,如蓝色部分;但是在使用递归时,大家应当注意栈溢出的情况,不是所有的题目都可以选择使用递归来实现。递归也有他的局限性。