电商专业学习嵌入式软件开发第六十三天

第5章 函数

 

第5章
函数
1.
函数
2.
变量的作用域
1.
局部变量
2.
全局变量
3.
变量的存储方式
小结

 

  • ###### C基础第三天

1. 函数

  1. 从函数定义的角度看,函数可分为库函数和用户自定义函数两种
    1)
    库函数:由C系统提供,只需在程序前包含有该函数原型的头文件即可在程序中直接调用
    2)
    用户自定义函数:由用户按需要写的函数,不仅在程序中定义函数本身,而且在主调函数模块中还必须对该被调用函数进行类型说明,然后使用
  2. 从函数兼有其它语言中的函数和过程的两个功能,又可分为有返回值函数和无返回值函数
    1)
    有返回值函数:此类函数被调用执行完后将向调用者返回一个执行结果,称为函数返回值;由用户定义的这种要返回值得函数,必须在函数定义和函数说明中明确返回值的类型
    2)
    无返回函数:此类函数在完成特定的处理任务,执行完成后不向调用者返回函数值。由于函数无须返回值,用户定义此类函数时可指定她的返回为”空类型(void)”
  3. 从主调函数和被调函数之间数据传送的角度可分为无参函数和有参函数
    1)
    无参函数:函数定义、函数说明及函数调用中均不带参数。主调函数和被调函数之间不进行参数传送。可以返回或不返回函数值
    2)
    有参函数:在函数定义及函数说明时都有参数,称为形式参数(形参)。在函数调用时也必须给出参数,称为实际参数(实参)。进行函数调用时,主调函数将把实参的值传送给形参,供被函数使用
  4. 函数定义的一般形式
    1) 无参函数的一般形式

<wiz_code_mirror>

 

 

 

 

 

1 类型说明符 函数名(){
2     类型说明
3     语句
4 }

 

 

 

其中类型说明符和函数名称为函数头
类型说明符指明了本函数的类型,函数的类型实际上是函数返回值的类型。函数名是由用户定义的标识符,函数名后有一个空括号,其中无参数,但括号不可少。{}
中的内容称为函数体。在函数体中也有类型说明,
这是对函数体内部所用到的变量的类型说明。在很多情况下都不要求无参函数有返回值void
2) 有参函数的一般形式

<wiz_code_mirror>

 

 

 

 

 

1 类型说明符 函数名(形式参数表)
2     形式参数类型说明
3     {
4     类型说明
5     语句
6     }

 

 

 

其一是形式参数表
其二是形式参数类型说明。在形参表中给出的参数称为形式参数
它们可以是各种类型的变量,必须给以类型说明,
各参数之间用逗号间隔。在进行函数调用时,主调函数将赋予这些形式参数实际的值

  1. 函数的参数:分为形参和实参;形参出现在函数定义中,在整个函数体内都可以使用,
    离开该函数则不能使用
    。实参出现在主调函数中,进入被调函数后,实参变量也不能使用,功能是作数据传送。发生函数调用时,
    主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送
    函数的形参和实参的特点
    1)
    形参变量只有在被调用时才分配内存单元,调用结束后,即刻释放所分配的内存单元。形参只有在函数内部有效,函数提哦啊用结束返回主调函数后则不能再使用该形参变量
    2)
    实参可以是常量、变量、表达式、函数等,在进行函数调用时,都必须具有确定的值,以便把这些值送给形参
    3)
    实参和形参在数量上、类型上、顺序上应严格一致,否则会发生“类型不匹配”的错误
    4)
    函数调用中发生的数据传送是单向的,即只能把实参的值传送给形参。因此在函数调用时,形参的值发生改变,而实参中的值不会变化
  2. 函数的值:指函数被调用后,执行函数体中的程序段所取得的并返回给主调函数的值,(或称函数返回值)对函数的值的说明:
    1) 函数的值只能用过 “return 表达式”
    语句返回主调函数
    ,该语句的功能是计算表达式的值,并返回给主调函数,
    2)
    函数值的类型和函数定义中函数的类型应保持一致,如果两者不一致,则以函数类型为准,自动进行类型转换
    3) 如函数值为整型,在函数定义时可以省去类型说明
    4) 不返回函数值的函数,可以明确定义为空类型 (void)
  3. 被调函数
    无参函数一般形式: 类型说明符 被调函数名()
    有参函数一般形式: 类型说明符 被调函数名(类型 形参, 类型
    形参···)
  4. 函数的递归使用:一个函数在它的函数体内调用它自身称为递归调用,为了防止递归调用无终止进行,加条件判断

今天讲的是函数,明天开始讲指针。现在出现在笔记中的代码都是我写不出来的,看了一下这两天的代码量,感觉很是头疼,背下来都有难度。

2. 变量的作用域

//static静态局部变量
#include <stdio.h>
int fun(int a)
{
//  const int b = 2;//const代表不能修改后面的值
    static int b = 2;//static会保留上一次的值
    b++;
    return a+b;
}
int main(int argc,char *argv[])
{   
    int i;
    for(i = 0;i < 4;i++)//0,1,2,3
    {
        printf("%dn",fun(i));
    }
    return 0;
}

//函数递归-阶乘
#include <stdio.h>
long jiecheng(int n)//n = 5
{
    long ret = -1;
    if(n < 0)
        printf("n < 0,input error!n");
    else if(n == 0||n == 1)
        ret = 1;
    else
        ret = jiecheng(n-1)*n;//jiecheng(4)*5
    return ret;
}
int main(int argc,char *argv[])
{
    int n;
    long y;
    printf("请输入一个数:");
    scanf("%d",&n);
    y = jiecheng(n);
    printf("%d! = %ldn",n,y);
    return 0;
}

//函数嵌套-阶乘
#include <stdio.h>
int pf(int i)
{
    return i * i;
}
int jc(int a)
{
    int i;
    int s = 1;
    a = pf(a);//函数嵌套
    for(i = 1;i <= a;i++)
    {
        s*=i;
    }
    return s;
}
int main(int argc,char *argv[])
{
    int i;
    int sum = 0;
    for(i = 1;i <= 3;i++)
    {
        sum += jc(i);
    }
    printf("%dn",sum);
    return 0;
}

//函数嵌套调用-最大值
#include <stdio.h>
int max(int x,int y)
{
    return x > y ? x : y;
}
int add(int x,int y)
{
    return x+y;
}
int main(int argc,char *argv[])
{
    int a,b,c;
    printf("请输入两个数:");
    scanf("%d%d",&a,&b);
    printf("%dn",max(a,b));//函数实参
//  c = max(a,b);//函数表达式
//  printf("%dn",c);//函数语句
    c = max(a,add(a,b));
    printf("%dn",c);//函数语句
    return 0;
}

//函数调用-简易计算器
#if 0
#include <stdio.h>
void add(float x,float y)
{
    printf("x+y = %.2fn",x+y);
}
void sub(float x,float y)
{
    printf("x-y = %.2fn",x-y);
}
void mul(float x,float y)
{
    printf("x*y = %.2fn",x*y);
}
void div(float x,float y)
{
    printf("x/y = %.2fn",x/y);
}
int main(int argc,char *argv[])
{
    float a,b;
    char c;
    printf("请输算式:");
    scanf("%f%c%f",&a,&c,&b);
    switch(c)   
    {
        case '+':add(a,b);break;
        case '-':sub(a,b);break;
        case '*':mul(a,b);break;
        case '/':div(a,b);break;
        default:printf("input error !n");
    }
    return 0;
}
#else
#include <stdio.h>
float add(float x,float y)
{
    return x+y;
}
float sub(float x,float y)
{
    return x-y;
}
float mul(float x,float y)
{
    return x*y;
}
float div(float x,float y)
{
    return x/y;
}
int main(int argc,char *argv[])
{
    float a,b,c;
    char d;
    printf("请输算式:");
    scanf("%f%c%f",&a,&d,&b);
    switch(d)   
    {
        case '+':c = add(a,b);break;
        case '-':c = sub(a,b);break;
        case '*':c = mul(a,b);break;
        case '/':c = div(a,b);break;
        default:printf("input error !n");
    }
    printf("%.2fn",c);
    return 0;
}
#endif

//函数调用
#include <stdio.h>
void hello()
{
    printf("hello wordn");
}
void add1()
{
    int a,b;
    printf("请输入a和b的值:");
    scanf("%d%d",&a,&b);
    printf("%dn",a+b);
}
void add2(int a,int b)
{
    int c = a+b;
    printf("%dn",c);
}
int add3()
{
    int a,b;
    printf("请输入a和b的值:");
    scanf("%d%d",&a,&b);
    return a+b;
}
int add4(int a,int b)
{
    return a+b;
}
int main(int argc,char *argv[])
{
    hello();
    add2(12,46);

    return 0;
}

//斐波那契数列
#include <stdio.h>
int main()
{
    int n;
    int b[20];
    b[1] = 1;b[2] = 1;
    for(n = 3;n <= 20;n++)
    {
        b[n] = b[n - 1]+b[n - 2];
    }
    for(n = 1;n <= 20;n++)
    {
        printf("%dn",b[n]);
    }
    return 0;
}

1. 局部变量

  1. 局部变量:也称为内部变量。在函数内做定义说明的。其作用域仅限于函数内,离开函数后再使用变量是违法的
    局部变量作用域说明
    1) 主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用
    2)
    形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量
    3) 允许在不同的函数中使用相同的变量名

1、什么是函数,为什么要使用函数?
函数是完成特定任务的独立代码单元;
降低复杂性,避免重复代码段,限制了改动带来的影响,隐含顺序,改进性能,
进行集中控制,隐含数据结构,隐含指针操作,隐含全局变量。
2、C语言函数的几种分类
从函数定义角度分类:库函数(#include<stdio.h>)
用户自定义函数(#include “add.h”)
按有无返回值分类: 有返回值函数和无返回值函数
从主调函数和被调函数之间数据传送的角度分类:有参函数和无参函数
库函数从功能的角度分类:字符型分类函数、转换函数、目录路径函数、诊断函数、图形函数、输入输出函数、接口函数、字符串函数、内存管理函数、数学函数、日期和时间函数、进程控制函数等。

2. 全局变量

  1. 全局变量:也称为外部变量,是在函数外部定义的变量;其作用域是整个源程序,只有在函数内经过说明的全局变量才能使用,全局变量说符为extern
    全局变量作用域说明
    1) 外部变量定义必须在所有的函数之外,且只能定义一次。一般形式:
    [extern] 类型说明符 变量名, 变量名··· extern int a, b
    2)
    外部变量可加强函数模块之间的数据联系但会使得函数的独立性降低
    3)
    在同一源文件中,允许全局变量和局部变量同名,在局部变量的作用域内,全局变量不起作用

3、函数定义的一般形式
1、无参函数的定义形式
类型标识符 函数名()
{
声明部分
语句
}

3. 变量的存储方式

  1. 静态存储 和 动态存储
    静态存储变量通常是在
    常量定义时就分定存储单元并一直不变,直至整个程序结束;全局变量即属于此类存储方式;
    动态存储变量是在程序执行过程中,使用它时才分配存储单元,使用完毕立即释放,函数的形式参数即属于此类存储方式
    静态存储变量是一直存在的,而动态存储变量则时有时无,对变量的存储类型说明:
auto 自动变量
register 寄存器变量
extern 外部变量
static 静态变量
  • 自动变量和寄存器变量属于动态存储方式
    外部变量和静态变量属于静态存储方式
 例、void Hello()
 {
 printf("hello worldn");
 }

小结

  1. 函数的分类
    1) 库函数:由C系统提供的函数
    2) 用户定义函数:由用户自己定义的函数
    3)
    有返回值的函数向调用者返回函数值,应说明函数类型(即返回值的类型)
    4) 无返回值的函数:不返回函数值,说明为空(void)类型
    5) 有参函数:主调函数向被调函数传送数据
    6) 无参函数:主调函数与被调函数无传送数据
    7) 内部函数:只能在本院文件中使用的函数
    8) 外部函数:可在整个源程序中使用的函数
  2. 函数 定义 的一般形式
    [extern/static] 类型说明符 函数名([形参表]) 方括号内为可选框
  3. 函数 说明 的一般形式
    [extern] 类型说明符 函数名 ([形参表])
  4. 函数 调用 的一般形式
    函数名 ([实参表])
  5. 函数的参数
    分为形参 和
    实参
    ,形参出现在函数定义中,实参出现在函数调用中,发生函数调用时,将把实参的值送给形参
  6. 函数的值
    指函数的返回值,是在函数中由 return 语句返回的
  7. 数组名作为函数参数
    不进行值传送而进行地址传送,形参和实参实际上为同一个数组的两个名称,因此形参和实参同时变化
  8. C语言中,允许函数的嵌套调用 和 函数的递归调用
  9. 可根据变量的数据类型、变量作用域和变量的存储类型对变量分类
  10. 变量的作用域是指变量在程序中的有效范围,分为局部变量 和 全局变量
  11. 变量的存储类型是指变量在内存中的存储方式,分为静态存储 和
    动态存储
    ,表示了变量的生存期

2、有参函数的定义形式
类型标识符 函数名(形式参数列表)
{
声明部分
语句
}

例、int max(int a,int b,int c)    //max 是一个整型函数,返回值是一个整数,形参a、b均为整型量。
 {
 int maxx=0;
 if (a>b)
 maxx=a;
 else
 maxx=b;

 if (max>c)
 return maxx;
 else
 return c;
 }

 我们可以直接在main函数中调用以上两个函数

 int main(int argc, char const *argv[])
 {
 int m=4,n=5,c=6;
 int d=0;
 d=max(m,n,c)
 printf("%dn",d);
 return 0;
 }

4、形式参数和实际参数
1、形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用(如31行中的,a、b);
2、实参出现在主调函数中,进入被调函数中也不能使用(如43行的m、n),实参可以是常量、变量、表达式、函数等,
3、在进行函数调用时,都必须具有确定的值,以便把值传给形参;
4、实参和形参在数量上、类型上、顺序上应严格一致,否则会报错(类型不匹配)
5、函数调用中发生的数据传送是单向的,只能把实参的值传送给形参,在函数调用过程中,形参的值发生改变,实参的值不改变

例、
#include <stdio.h>
void text(int n ); //函数的声明
void text(int n)       //函数的定义
{
int i;
for (i = n-1; i > 0; i--)
{
n=n+i;
}
printf("函数中的n=%dn",n);
}

int    main(int argc, char const *argv[])
{
int n;
printf("请输入一个数:");
scanf("%d",&n);
text(n);           //函数的调用
printf("原来的n=%dn",n);
return 0;
}

5、函数的返回值
函数的返回值只能通过return语句返回主调函数
return 语句的一般形式为:
return 表达式;或 return (表达式);
1、该语句的功能是计算表达式的值,并返回给主调函数,函数中允许多个return语句,但是每次调用函数只能有一个return语句
被执行,每次调用只能有一个返回值。
2、函数值的类型和函数定义中的函数类型应该保持一致,如果不一致,以函数类型为准
3、无返回值的函数,可以明确定义为”空类型”,类型说明符为”void”

6、函数的调用
在程序中是通过对函数的调用来执行函数体的
C语言中函数调用的一般形式
函数名 (实际参数表) //无参函数则无实际参数,如果有多个参数则用逗号隔开
函数调用的几种方式:
1、函数表达式:z=max(x,y);//一个赋值表达式,函数作为表达式的一项出现,这种方式要求函数是有返回值的
2、函数语句:printf(“%d”,a);scanf(“%d”,&b);//函数调用的一般形式加上分号构成语句;
3、函数实参:printf(“%dn”,max(x,y));
函数作为另一个函数调用的实际参数出现;

计算数组元素的和
int sum(int *a,int n)
{
int sum=0;
int i;
for (i = 0; i < n; ++i)
{
sum+=a[i];
}
return sum;
}

int main(int argc, char const *argv[])
{
int a[10]={1,2,3,4,5,6,7,8,9,10};
int s=0;
s=sum(a,10);
printf("累加结果为:%dn",s );
return 0;
}

 交换两个数的值
 void swap(int x,int y)
 {
 int t=0;
 t=x;
 x=y;
 y=t;
 // printf("在函数中x=%d,y=%dn",x,y);
 }
 void swap2(int *x,int *y)
 {
 int t=0;
 t=*x;
 *x=*y;
 *y=t;
 }
 int main(int argc, char const *argv[])
 {
 int a=3,b=8;
 int *p,*q;
 p=&a;
 q=&b;
 printf("交换前a=%d,b=%dn",a,b);
 swap(a,b);
 swap2(p,q);
 printf("交换后a=%d,b=%dn",a,b );
 return 0;
 }
 int main(int argc, char const *argv[])
 {
 int x=3,y=5,t=0;
 printf("交换前x=%d,y=%dn",x,y );
 t=x;
 x=y;
 y=t;
 printf("交换后x=%d,y=%dn",x,y );
 return 0;
 }

被调函数的声明和函数原型:
在主调函数中调用某函数之前应对该被调函数进行声明,这于使用变量之前对变量进行变量说明是一样的。目的是使辨析系统知道
被调函数的返回值类型。
其一般形式为
类型说明符 被调函数名(类型 形参,类型 形参,……);
或者
类型说明符 被调函数名(类型,类型………);

发表评论

电子邮件地址不会被公开。 必填项已用*标注