C语言--函数

函数(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;

 

}

  1. 年岁问题,总共有10个人,问第一人说比第二个大两岁,问第二个说比第三个大两岁,一直问,问到第十个人的时候,他说他10岁,请问第一个人多少岁。

#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;

}

  1. hanoi 问题

做递归题目:

  1. 理解清楚题意;
  2. 找到归点
  3. 找递归过程中相似的步骤,表现出来;

 

————————————————————————————————————————————————————————————————————————————————————

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. int能表示的范围?long int以及long long int;(32位机)

 

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;

}

 

 

 

你可能感兴趣的:(C语言--函数)