函数(Function)
0.引言
算法的结构化设计
标准函数(库函数)和自定义函数
程序从main函数开始,在main函数结束
main函数可以调用其他函数,但是其他函数不能调用main函数,main函数是系统调用的。
————————————————————————————————————————————————————————————————————————————————————
1.有参函数和无参函数
参数:函数的一个明显特征是使用时带(),必要时,括号里面还要包括数据或是变量,称为参数;
所以,函数又可以分为有参函数和无参函数
无参函数
返回类型 函数名()
{
函数体
}
有参函数
返回类型 函数名(函数参数列表)
{
函数体
}
实际参数和形式参数
形参:被调用函数后面括号里面的变量名称
实参:主调用函数调用一个函数时函数后面括号里面的参数
函数不允许嵌套定义
void a()
{
……
void b()
{
……
}
……
}
————————————————————————————————————————————————————————————————————————————————————
2.返回值
通过return 语句进行返回的内容;
返回值的类型必须和返回类型相同(函数返回值的类型要和函数类型相同);
void:
1.返回值(无返回值)
2.参数
Void func()
{
}
调用的时候直接用func();
————————————————————————————————————————————————————————————————————————————————————
3.函数的直接调用和间接调用
调用一个函数的时候必须要保证要么调用的函数定义在我的前面,要么就是已经完成了对函数的说明(把函数头抄一遍就行)
声明的作用是把函数名,函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统
能够正确识别函数并检查调用是否合法
int sum(int a,int b)
{
return a + b;
}
//int sub(int ,int );
int main()
{
int sub(int a,int b);(这两句声明都可以,位置也都可以)
printf("sum = %d\n",sub(3,2));
printf("sub = %d\n",sum(3,2));
return 0;
}
int sub(int a,int b)
{
return a - b;
}
声明和定义是有区别的!!!
函数要注意的几个点:
1、形参只能是变量或表达式,不能是常量;
2、实参和对应的形参占用不同的存储单元,但共用同一段存储空间,都在栈里面。
3、实参将数据传给形参后,主调函数结束,才释放原来占用的存储单元。同样,被调用函数结束,形参才释放。
4、实参传递给形参是单向传递,形参变量在未出现函数调用时,并不占用内存,只在调用时才占用。调用结束后,将释放内存。执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数中的实参的值。
//值传递 其实质是将数值传递给其他俩个变量,自己变量里面的值并没有改变----所以说是值传递。
# include
void exchange();
int main (void)
{
int x,y;
x=3;
y=4;
exchange(x,y); //这就是典型的值传递,它把X,Y的值传递给变a和b;
printf("%d %d\n",x,y); //a,b的值进行交换,但是变量X,Y里面的值并没有交换。
return 0;
}
void exchange(int a,int b)
{
int temp;
temp =a;
a=b;
b=temp;
printf("%d %d\n",a,b);
}
//地址传递 (提到地址二字,应该始终明确,C语言中的地址是基于指针的,所以地址传递是一定会用指针的)
# include
void exchange();
int main (void)
{
int x,y;
x=3;
y=4;
exchange(&x,&y); //这就是典型的地址传递,它把X,Y变量地址传递给指针a和b;
printf("%d %d\n",x,y); //*a,*b的值进行交换,就是找到a,b对应的地址交换地址里面的值,其实也就是
//找到 a,b值进行交换。
return 0;
}
void exchange(int *a,int*b)
{
int temp;
temp =*a;
*a=*b;
*b=temp;
printf("%d %d\n",*a,*b);
}
在调用一个函数的过程中,直接或者是间接的调用本身,称为函数的递归调用
1.n!问题
#include
int jiecheng(int n)
{
if(n==1)
return 1;
else
return n*jiecheng(n-1);
}
int main ()
{
int a;
scanf("%d",&a);
printf("result=%d\n",jiecheng(a));
return 0;
}
#include
int niansui(int n)
{
if(n==10)
return 10;
else
return niansui(n+1)+2;
}
int main ()
{
int a;
scanf("%d",&a);
if(a<0||a>10)
return -1;
printf("result=%d\n",niansui(a));
return 0;
}
03.猴子吃桃子问题
有一堆桃子不知其数,猴子每天吃前一天的一半多一个,到第10天只剩一个,试编程求这堆桃子的个数。
(假如第1天剩余10个桃子,吃掉一半加一个得到4个,此时下天是4个桃子,接着吃掉一半加一个得到1个,再下一天是1个桃子。)
#include
int taozi(int n)
{
if(n==10)
return 1;
else
return 2*taozi(n+1)+2;
}
int main ()
{
printf("第一天桃子数=%d\n",taozi(1));
return 0;
}
做递归题目:
————————————————————————————————————————————————————————————————————————————————————
4.局部变量和全局变量
局部:在函数内定义的变量(包括形参)
全局: 在函数外定义的变量
局部可以和全局重名
同名不要紧,只要域不同
具体看哪个,就近往上找
————————————————————————————————————————————————————————————————————————————————————
5.进程的地址空间
详见图示
————————————————————————————————————————————————————————————————————————————————————
6.存储变量类别
自动的 auto 可以省略的,所有变量默认都是auto的,也就是自动分配内存空间
静态的 static
1. 局部变量,局部变量只初始化一次;
2. 全局变量,函数,代表只能在本文件被使用
#include
Int main()
{
func(int a,int b)
Int k=4,m=1,p;
P=func(k,m);
Printf(“%d”,p)
P=func(k,m)
Printf(“%d\n”,p);
}
func(int a,int b)
{
Static int m=0,i=2;
i+=m+1;
m=i+a+b;
return (m);
}
结果 8,17;调用第一次函数后i=3,m=8;第二次调用时因为是static ,所以I,M不用再初始化,直接用3,8代入计算;
外部的 extern(见预处理部分)
只能修饰全局变量和函数,代表可以被其他文件引用
寄存器的 register
请求编译器将其尽可能的存放在CPU内部的寄存器里面,而不是通过内存寻址,以提高效率
register int a;
补充:
1、
主被调函数值的传递
右边结果为3.000000;
2、
Float为单精度,内存中占4个字节,有效数位是7位(因为有正负,所以不是8位);double为双精度,占8个字节,有效数位是16位,一般乌帮图精确到小数点后六位。
Printf(“%.3f”,sum(1.0,2));
打印结果为3.000
1个字节(byte)=8个比特位(bit)
1个汉字占2个字节,1个英文字母占1个字节。
Short int 2个字节16位;
Int 4个字节,32位;
Long int和int一样
Long long int8个字节,32位;
signed short int 能表达的整数范围从-32768到32767最大值前面一个0,后面15个1,(2^15-1);最小值前面一个1+后面15个0,(-2^15);
unsigned short int 能表达的整数范围从0到65535,最大值16个1,2^16-1。
signed long int 就是int能表达的范围从-2147783648到2147483647 最大值前面一个0,后面31个1;(2^31-1)最小值前面一个1,后面31个0 (-2^31);
unsigned long int 能表达的范围从0到4294967265 (2^32-1);
如果超出上述范围就溢出,编译器会随即赋一个值给溢出变量
int值域 4字节 - 2147 438 648~+ 2 147 438 647
long int 4字节 - 2 147 438 648 ~ + 2 147 438 647
long long int 8字节 - 9 223 372 036 854 775 808 ~ + 9 223 372 036 854 775 807
( lld )
4、
进制英文:
BIN表示二进制;
oct表示八进制;
dec表示表示十进制;
hex表示十六进制;
作业一、用递归逆序打印字符串;
#include
void nixu()
{
char ch;
ch=getchar();
if(ch=='\n')
return;
else
{
nixu();
printf("%c",ch);//putchar( ch);
}
}
int main (void)
{
nixu();
printf("\n");
return 0;
}
作业二、输入一串数字,用递归打印出一串字符串;
#include
void quzhi(int n)
{
if(n==0)
return;
else
{
quzhi(n/10);
printf("%c",n%10+'0');
}
}
int main ()
{
int n;
scanf("%d",&n);
quzhi(n);
printf("\n");
return 0;
}
作业三、斐波拉切数列
有一整数序列
1,1,2,3, 5, 8, 13,21......
求出这个数列的前20项之和。
#include
int fun(int i)
{
if(i==1||i==2)
{
return 1;
}
else
{
return fun(i-1)+fun(i-2);
}
}
int main (void)
{
int i,s=0;
for(i=1;i<=20;i++)
{
s+=fun(i);
}
printf("前二十项之和=%d\n",s);
return 0;
}
作业四、3、有一分数序列
2/1, 3/2, 5/3, 8/5, 13/8, 21/13,......
求出这个数列的前20项之和。
#include
float fun(int i)
{
if(i==1)
{
return 1;
}
if(i==2)
return 2;
else
{
return fun(i-1)+fun(i-2);
}
}
float oob(int i)
{
if(i==1)
return 2;
if(i==2)
return 3;
else
return oob(i-1)+oob(i-2);
}
int main (void)
{
int i;
float s=0;
for(i=1;i<=20;i++)
{
s+=oob(i)/fun(i);
}
printf("前二十项之和=%f\n",s);
return 0;
}