1.1
函数的原型和调用
1 ,定义一个函数
有返回值的情况:
double circle( double r) // 这里r 是形参 形参一定是一个变量
{
return 3.1415926 * 2 * r; //返回值的类型一定是定义的函数类型,这里是double
}
无
返回值的情况:
void sayhello(char s[])
{
printf("hello,%s!!!\n",s);
}
2 在使用函数前必须定义或者声明函数
#include <stdio.h>
double circle(double r);
void sayhello(char s[]);//当函数在main函数前定义的时候,在使用函数前,必须先声明
1.2
函数的形参与实参
在定义函数的时候,函数大多数都有参数,在被主调函数需要传递数据给函数的参数
函数定义时用的变量叫形参
传递给函数的中形参值或变量叫实参
int main()
{
double a = 12.2;
double C = circle(2.1111); //a 是实参,实参可以是你变量,也可以是常量
printf("图的周长为:%F\n", C);
sayhello("inx");
}
double circle( double r) // 这里r 是形参 形参一定是一个变量
{
return 3.1415926 * 2 * r; //返回值的类型一定是定义的函数类型,这里是double
}
注意:
1
形参在未出现函数调用时,他们并不占用内存单元,只有在发生函数调用的时候形参才被分配内存,函数调用完成后,形参所占的内存被释放
2
实参可以是变量,常量或者表达式
3
在定义函数时,一定要指定形参的数据类型
4
形参与实参的数据类型一定要可兼容
5
在
C
语言中,实参与形参的数据传递是“值传递”,即单向传递,只由实参传递给形参,而不能由形参传递给实参。
演示值传递:
#include <stdio.h>
void value_pass();
int main()
{
double a = 12.2;
value_pass(a);
printf("a=%F", a); //当a传递给函数形参a的时候,只是把值赋给a,a=12.200000
return 0;
}
void value_pass(double a)
{
a = a + 2;
printf("a=%F", a);//输出结果 a + 2;
}
输出结果:
a=14.200000
a=12.200000
注:如果函数的参数是个数组,或者字符串的时候,那么是可以通过形参修改实参的值的()
1.3
函数的返回类型与返回值
1
函数的返回值通过函数中的
return
获得,如果函数的返回值为
void
可以不需要
return
语句。
2
函数
return
语句中的返回值数据类型应该与函数定义时相同。
3
如果函数中没有
return
语句,那么函数将返回一个不确定的值。
1.4
main
函数与
exit
函数与函数的
return
语句
代码:
exit(0);//退出程序
return 0;//退出函数
1.5
多个源代码文件程序的编译
1.5.1
头文件的使用
如果把
main
函数放在第一个文件中,而把自定义函数放在第二个文件中,那么就需要在第一个文件中声明函数原型。
如果把函数原型包含在一个头文件里,那么就不必每次使用函数的时候都声明其原型了。把函数声明放入头文件是很好的习惯。
1.5.2
#include
与
#define
的意义
#include
就是简单的文件内容替换
#define
就是简单的文本替换而已
1.5.3
#ifndef
与
#endif
#ifndef
的意思就是条件预编译
,
如果
#ifndef
后面的条件成立,那么就预编译从
#ifndef
开始到
#endif
之间的代码,否则不会去预编译这段代码
1.6
函数的递归
函数可以调用自己,这就叫函数的递归:
先序递归演示:
代码
#include <stdio.h>
void test(int n)
{
printf("n=%d\n", n);
n--;
if ( n > 0)
{
test(n);
}
}
int main()
{
int i = 10;
test(i);
}
打印结果:
n=10
n=9
n=8
n=7
n=6
n=5
n=4
n=3
n=2
n=1
后序递归(主体在递归后面):
代码
#include <stdio.h>
void test(int n)
{
n--;
if ( n > 0)
{
test(n);
}
printf("n=%d\n", n);
}
int main()
{
int i = 10;
test(i);
}
显示结果:
n=0
n=1
n=2
n=3
n=4
n=5
n=6
n=7
n=8
n=9
1.6.1
递归的过程分析
有
n
个人排成一队,问第
n
个人多少岁,他回答比前面一个人大
2
岁,再问前面一个人多少岁,他回答比前面一个人大
2
岁,一直问到最后问第一个人,他回答
10
岁
代码:
#include <stdio.h>
int age(n)
{
if (n == 1)
{
return 10;
}
else
{
return age(n - 1) + 2;
}
}
int main()
{
int n = 10;
printf("第N个人%d岁\n",age(10));
}
打印结果:
第N个人28岁
将
10
进制数转化为二进制数的例子
234
在十进制下为
2 * 10
的
2
次方
+ 3 * 10
的
1
次方
+ 4*10
的
0
次方。
奇数的二进制最后一位一定是
1
,偶数的二进制最后一位一定是
0
。
可以通过
number % 2
得到二进制形式的最后一位,如果要将一个完整的整数转化为二进制就需要用到递归函数。
在递归调用之前,计算
number % 2
的值,然后在递归调用语句之后进行输出,这样计算出的第一个数值反而在最后一个输出。
为了得出下一个数,需要把原数除以
2
,这种计算相当于十进制下把小数点左移一位,如果此时得出的数是偶数,,则下一个二进制的数值是
0
,如果得出的是奇数,那么下一个二进制数为
1
。
直到被
2
除的结果小于
2
,就停止递归。
代码:
int bin(int n) //将十进制n 转化为二进制数
{
int a = n % 2;
int b = n / 2;
if (b > 0)
{
bin(b);
}
printf("%d",a);
}
int main()
{
int n = 100;
bin(n);
//printf("第N个人%d岁\n",age(10));
}
打印结果:
1100100
斐波那契数列例子
斐波那契数列指的是这样一个数列
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
第
0
项是
0
,第
1
项是第一个
1
。
这个数列从第
2
项开始,每一项都等于前两项之和。
代码:
int fib(n)
{
if (n == 1)
return 0;
if (n == 2)
{
return 1;
}
if (n >= 3)
{
return fib(n - 2) + fib(n - 1);
}
}
int main()
{
int n = 10;
printf("fibs前10项为:");
for (int i = 1; i <= n;i++)
{
printf("%d ",fib(i));
}
//printf("第N个人%d岁\n",age(10));
}
打印结果:
fibs前10项为:0 1 1 2 3 5 8 13 21 34
1.6.2
递归的优点
递归给某些编程问题提供了最简单的方法
1.6.3
递归的缺点
一个有缺陷的递归会很快耗尽计算机的资源,递归的程序难以理解和维护。