C语言-函数

定义

若干相关的函数可以合并成一个“模块”

一个C程序由一个或多个源程序文件组成

一个源程序文件由一个或多个函数组成

在这里插入图片描述

说明:

一个源程序文件由一个或多个函数组成。

一个C程序由一个或多个源程序文件组成。

C程序的执行从main函数开始,调用其他函数后流程回到main函数,在main函数中结束整个程序运行。

所有函数都是平行的,即函数定义时是互相独立的,一个函数并不从属于另一个函数。

函数的分类:

1.从函数的定义角度分类

  1. 标准函数,即库函数
  目前为止,我们所学习的printf()、scanf()等都是ANSI C标准定义的库函数。任意符合ANSI C的编译器,不管它支持什么平台,都必须提供这些函数供用户使用。

main()稍微特殊一点点C程序的执行从main函数开始调用其他函数后流程回到main函数在main函数中结束整个程序运行

  1. 用户自定义函数

用户按自己的意愿编写自己的函数,完成人员功能。

简单的用户自定义函数

#include <stdio.h>
void pstar();
main()
{
    pstar();
}

void pstar()
{
    printf("*******************\n");
}
#include "stdio.h"

int f(int x)
{
    x += 10;
    return x;
}

int main()
{
    int y = 0, x = 10;

    y = f(x);
    printf("%d,%d\n", y, x);
}

2.从有无参数的定义角度分类

(1)无参函数。无参函数是指不带任何参数的函数。在调用一个无参函数时,主调函数与被调函数之间不进行参数传递。上图1

(2)有参函数。有参函数是指在函数定义和函数调用时带有参数的函数。函数定义时的参数称为形式参数(简称形参),函数调用时的参数称为实际参数(简称实参)在调用一个有参函数时,主调函数将实际参数的值传递给形式参数,供被调函数使用。

3.从有无返回值的角度分类

(1)有返回值函数。有返回值函数在被调用执行完后会:向主调函数返回一个执行结果,这个结果就称为函数的返回值。如数学函数就属于有返回值函数。在定义-一个有返回值函数时,应该对其返回值作类型说明。

(2)无返回值函数。无返回值函数用于完成某项特定的处理任务,执行完后不向主调函数返回一个函数值。如,前面例1中的pstar函数就是-一个无返回值函数。通常,定义一一个无返回值函数时,可说明其返回值类型为空类型,即void类型

4.从函数作用域的角度分类

(1)内部函数。内部函数是指只能被本程序文件中的其他函数调用的函数。

(2)外部函数。外部函数是指除了能被本程序文件中的其他函数调用之外,还可以被其他文件中的函数调用的函数。

模块化程序设计思想

函数特点

●C函数是一种独立性很强的程序模块,所有的函数都处于平等地位,不存在从属关系。
●一 个C程序的各个函数可以放在一一个程序文件内,也可以分散放在几个不同的程序文件中。
●通过函数调用可以实现不同函数之间的逻辑联系。
●一个C程序 总是从main函数开始执行,由main函数调用其他函数,而其他函数之间又可以相互调用。

函数定义的一般形式

定义函数的一般形式
类型标识符 函数名(形式参数表)
{
    函数体
}

在这里插入图片描述

函数的定义方法

C语言规定,函数、变量等,都应该遵循原则:先定义、后使用。如果想要
使用函数,就必须在使用前进行定义。

定义函数应包括以下几个内容:

(1)指定函数的名字,以便以后按名调用;

(2)指定函数的类型,即函数的返回值类型.

(3)指定函数的参数,包括参数的类型、个数、名称、顺序

(4)指定函数的功能,这是最重要的,一个函数应该能够完成一个或若干个功能,不能完成功能的函数没有存在的意义。

定义无参函数

一般形式

类型名 函数名()
{
   函数体
}

或

类型名 函数名(void)

{
    函数体
}

函数名后面括号内的void表示为空,即函数没有参数。

函数体包括声明部分和语句部分

定义有参函数

例子

int f(int x)
{
    x += 10;
    return x;
}

一般形式

类型名 函数名(形式参数表列)
{
   函数体
}

函数体包括声明部分和语句部分

定义空函数

类型名 函数名()

{
    
}

例如

void dummy()
{
}

函数的调用、参数和返回值

函数调用的一般形式为:
函数名();
函数名(实参表);
变量名=函数表达式(实参表);

函数的语句调用

一般形式为:
                  函数名(实参表);

说明:
这种调用方式用于调用不带有返回值的函数。
如果调用的函数无形式参数,则实参表可以没有,但函数名后面的小括号不能省略

例子

#include <stdio.h>
void sum(int a, int b, int c);

main()
{
    int num1, num2, num3;
    printf("num1=");
    scanf("%d", &num1);
    printf("num2=");
    scanf("%d", &num2);
    printf("num3=");
    scanf("%d", &num3);
    sum(num1, num2, num3);
}

void sum(int a, int b, int c)
{
    int s;
    s = a + b + c;
    printf("%d+%d+%d=%d", a, b, c, s);
}

函数表达式调用

一般形式为:
                  变量名=函数表达式(实参表)

说明:
这种调用方式用于调用带有返回值的函数,函数的返回值将参加表达式的运算

例子

//表达式
int sum(int a, int b, int c);

main()
{
    int num1, num2, num3, s;
    printf("num1=");
    scanf("%d", &num1);
    printf("num2=");
    scanf("%d", &num2);
    printf("num3=");
    scanf("%d", &num3);

    s = sum(num1, num2, num3);
    printf("%d+%d+%d=%d", num1, num2, num3, s);
}

int sum(int a, int b, int c)
{
    int s;
    s = a + b + c;
    return s;
}

函数的调用几种形式:

  1. 无参数,无返回值时的调用
pstar ()
  1. 有参数,无返回值时的调用
min(a, b) ;
  1. 有参数,有返回值时的调用
c = min(a,b) ;
  1. 函数调用作为算术表达式的一部分
sum=f (num1) +f (num2) ;
  1. 函数调用作为另外-一个函数调用的参数
minnum = min(min(a,b), c) ;

函数的参数用于建立函数之间的数据联系。当一个函数调用另一个函数时,实际参数的值会传递给形式参数,以实现主调函数与被调函数之间的数据通信。同时,函数参数的运用还可提高一个函数的灵活性和通用性。

用函数的方法求1+2+100

#include <stdio.h>

void fun1();

main()
{
    fun1();
}

void fun1()
{
    int i, s = 0;
    for (i = 1; i <= 100; i++)
        s += i;
    printf("%d", s);
}

函数的嵌套调用

在这里插入图片描述

使用函数嵌套调用,求三个数的最小值

#include <stdio.h>
int min_3(int, int, int);
int min_2(int, int);

main()
{
    int a, b, c, minnum;
    printf("a=");
    scanf("%d", &a);
    printf("b=");
    scanf("%d", &b);
    printf("c=");
    scanf("%d", &c);
    minnum = min_3(a, b, c);
    printf("min is %d\n", minnum);
}

int min_3(int x, int y, int z)
{
    int minnum;
    minnum = min_2(min_2(x, y), z);
    return minnum;
}
int min_2(int x, int y)
{
    if (x < y)
        return x;

    else
        return y;
}

函数的递归调用

形式参数和实际参数:

形式参数(简称“形参”)是指定义函数时,跟在函数名后的小括号内的变量名。实际参数(简称“实参”)则是指调用函数时,跟在函数名后的小括号内的表达式。

实际参数与形式参数的关系如下:

(1)实参的数量应该与形参相同。如果一一个函数在定义时没有形参,则调用该函数时就不应有实参。

(2)实参的类型必须与形参一一致。

(3)定义函数时的形参只能是变量名,而调用函数时的实参则可以是变量名,也可以是常量或表达式。

(4)当简单变量作函数参数时,参数的传递是“值传递”,这是一种单向传递,即数据只能由实参传给形参,而不能由形参传回给实参。

函数的返回值

通常我们希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。

  1. 函数的返回值是通过函数中的 return 语句获得的。return语句将被调函数中的一个确定的值带回到主调函数中,供主调函数使用。
    在这里插入图片描述

2.函数值的类型。既然函数有返回值,这个值当然应属于某一个确定的类型,应当在定义函数时指定函数值的类型,例如下面是3个函数的首行;

  int max(float x,float y)    ;  //函数值为整型
   char letter(char c1 ,char c2);   //函数值为字符型
   double min (int x,int y) ;  //函数值为双精度型

在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。函数类型决定返回值的类型

对于不带回值的函数,应当用定义函数为void类型

关于函数返回值的说明:

1.并不是每-一个自定义函数都必须有returm语句,如果–个函数不需要带回任何数据,那么这个函数可以没有returm语句。

2.函数中可以有多个returm语句,但这并不意味着一一个函数可以同时返回多个值。当执行到被调函数中的第-一个return语句时,就会立即返回到主调函数。也就是说,多个return语句中只有-一个return语句才有机会被执行。该函数时就不应有实参。

形式参数与实在参数的两种传递方式

形式参数就是在定义函数时,写在参数列表里面的内容。实际参数就是在调用函数时,传入的量。

  1. 形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。实参出现在主调函数中,进入被调函数后,实参变量不能使用。

  2. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。而实参在主调函数中已分配内存单元。

  3. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,都必须具有确定的值,以便把这些值传送给形参。

  4. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。

  5. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。

值传递方式:

#include<stdio.h>
void fun(int a, int b)  // 此处a, b为形参
{
    a++;
    b++;
}
void mian()
{
    int a=1, b=2;    
    fun(a, b);  // 按传值方式调用函数fun,此处a,b为实参
    printf("%d, %d\n", a, b);  // 输出a=1, b=2
}

地址传递方式:

#include<stdio.h>
void fun(int *a, int *b)  
{
    *a = 4;
    *b = 5;
}
void mian()
{
    int a=1, b=2;    
    fun(&a, &b);  // 按传地址方式调用函数fun
    printf("%d, %d\n", a, b);  // 输出a=4, b=5
}

变量的作用域(局部变量和全局变量)

在这里插入图片描述

变量按作用域分:

全局变量:在整个工程文件内都有效;“在函数外定义的变量”,即从定义变量的位置到本源文件结束都有效。由于同一文件中的所有函数都能引用全局变量的值,因此如果在一个函数中改变了全局变量的值, 就能影响到其他函数中全局变量的值。
静态全局变量:只在定义它的文件内有效,效果和全局变量一样,不过就在本文件内部;
静态局部变量:只在定义它的函数内有效,只是程序仅分配一次内存,函数返回后,该变量不会消失;静态局部变量的生存期虽然为整个工程,但是其作用仍与局部变量相同,即只能在定义该变量的函数内使用该变量。退出该函数后, 尽管该变量还继续存在,但不能使用它。     

局部变量:在定义它的函数内有效,但是函数返回后失效。“在函数内定义的变量”,即在一个函数内部定义的变量,只在本函数范围内有效。

变量的存储类别(自动、静态、外部),变量的生存期

有4种存储类型,分别是auto(自动型)、static(静态型)、register(寄存器型)和extern(外部型)

register:

变量值存放在运算器的寄存器中

说明:

只有非静态局部变量和形参可定义为register变量,全局变量和静态局部变量不能定义为register变量。
一个系统中的寄存器数目是有限的,不能定义任意多个register变量。
在实践中很少使用register变量,因为目前很多编译器都具有优化选项,会自动把一些频繁使用的变量放在寄存器中以提高效率

auto

变量值存放在主存储器的动态存储区变量定义若缺省存储类型,则默认为“auto”。

说明:

动态存储方式,存储在动态存储区
变量定义中存储类别省略时,默认为auto型
auto型变量在函数/语句块被调用时分配内存,每次调用都重新分配,重新赋初值,调用结束则释放空间。
auto型变量如果不赋初值,则其值是一个不确定的值。

static

变量值存放在主存储器的静态存储区;程序执行开始至结束,始终占用该存储空间;

说明:

静态存储方式,在静态存储区分配单元,在程序运行期间都不释放。
静态局部变量具有可继承性,在整个程序运行期间只赋一次初值,以后调用不在重新赋初值,而只是保留上次调用后的值。
在定义时如果没有赋初值,则自动赋初值为该类型的零值。
静态局部变量具有全局的寿命和局部的可见性,作用域仍然是该函数/语句块内。。

extern

:声明可以多次,定义只能一次。

变量值存放在主存储器的静态存储区;程序执行开始至结束,始终占用该存储空间,其值可供其他源文件使用;

extern使用方法总结

在这里插入图片描述

变量的生存期:变量从生成到被撤销的这段时间。实际上就是变量占用内存的时间。
按其生存期可分为 动态变量和静态变量

变量只能在其生存期内被引用,而变量的作用域直接影响变量的生存期

局部变量的作用域和生存期

在函数内部作定义说明的变量,也成内部变量,仅限于函数内。

生存期是从函数被调用的时刻到函数返回调用处的时刻(静态局部变量除外)。

内存中的用户存储区划分如下

程序程序代码
静态存储区全局变量,静态局部变量
动态存储区局部变量,形式参数等

##变量的生存期

所有变量都占着内存,变量什么时候占着内存,什么时候从内存消失,这叫做变量的生存周期。

总结:

对变量的定义,有两种属性:数据类型和存储类别,例如:

static int x;(定义静态局部变量或定义限于本文件使用的全局变量)

auto int y;(定义自动变量,即局部变量)

regiter int a;(定义寄存器变量,函数内部定义)

extern int b;(定义可被外文件引用的全局变量或声明已经定义的全局变量)

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值