强化C【C语言笔记】——函数

c

函数概述

函数是C源程序的基本模块,通过对函数模块的调用实现特定的功能。C语言不仅提供了极为丰富的库函数(如Turbo C,MS C都提供了三百多个库函数),还允许用户建立自己定义的函数

C语言中从不同角度对函数进行分类:

  • 从函数定义的角度看

    • 库函数

    • 用户定义函数

  • 函数中有函数和过程两种功能

    • 有返回值函数

    • 无返回值函数

  • 从被调用函数之间数据传送

    • 无参数

    • 有参数

  • C语言中提供了丰富的库函数

    • 字符类型分类函数

    • 转换函数

    • 目录路径函数

    • 诊断函数

    • 图形函数

    • 输入输出函数

    • 接口函数

    • 字符串函数

    • 内存管理函数

    • 数字函数

    • 日期和时间函数

    • 进程控制函数

    • 其他函数

函数定义的一般形式

无参函数的定义形式

类型标识符 函数名()

       {声明部分

      语句

   }

其中类型标识符和函数名称为函数头
类型标识符指明了本函数的类型,函数的类型实际上是函数返回值的类型

有参函数的定义形式

类型标识符 函数名(形式参数表列)

       {声明部分

      语句

   }

在形参表中给出的参数称为形式参数,它们可以是各种类型的变量,各参数之间用逗号间隔

函数的参数和函数的值

形式参数和实际参数

函数的参数分为形参和实参两种,形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用实参出现在主调函数中,进入被调函数后,实参变量也不能使用

形参和实参的功能是作数据传送

函数的形参和实参具有以下特点:

  • 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元

  • 实参在进行函数调用时,它都必须具有确定的值,以便把这些值传送给形参

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

  • 函数调用中发生的数据传送是单向的;即只能把实参的值传送给形参

函数的返回值

函数的值是指函数被调用之后,执行函数体中的程序段所取得的并返回给主调函数的值,对函数的值有说明:

  • 函数的值只能通过return语句返回主调函数

return 语句的一般形式为:return 表达式;

  • 函数值的类型和函数定义中的函数类型应保持一直

  • 函数值为整型,定义时可以省去类型说明

  • 无返回值的函数,可以明确定义为空类型(void)

函数的调用

函数调用的一般形式

C语言中,函数调用的一般形式为:

    函数名(实际参数表)

被调用函数的声明和函数原型

在主调函数中调用某函数之前应对该被调函数进行说明(声明),这与使用变量之前要先进行变量说明是一样的

其一般形式为:

        类型说明符 被调函数名(类型 形参,类型 形参…); 

或为:

        类型说明符 被调函数名(类型,类型…); 

函数的嵌套调用

C语言中不允许作嵌套的函数定义。因此各函数之间是平行的,不存在上一级函数和下一级函数的问题

但是C语言允许在一个函数的定义中出现对另一个函数的调用。这样就出现了函数的嵌套调用

函数的递归调用

一个函数在它的函数体内调用它自身称为递归调用。这种函数称为递归函数

执行递归函数将反复调用其自身,每调用一次就进入新的一层

为了防止递归调用无终止地进行,必须在函数内有终止递归调用的手段。常用的办法是加条件判断,满足某种条件后就不再作递归调用,然后逐层返回

数组作为函数参数

数组可以作为函数的参数使用,进行数据传送

数组用作函数参数有两种形式,一种是把数组元素(下标变量)作为实参使用;另一种是把数组名作为函数的形参和实参使用

数组元素作函数实参

数组元素就是下标变量,它与普通变量并无区别

数组名作为函数参数

用数组名作函数参数时,则要求形参和相对应的实参都必须是类型相同的数组,都必须有明确的数组说明。当形参和实参二者不一致时,即会发生错误

在数组名作函数参数时所进行的传送只是地址的传送,也就是说把实参数组的首地址赋予形参数组名。形参数组名取得该首地址之后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间

当形参数组a和实参数组b的长度不一致。编译能够通过,但从结果看,数组a的多余的元素显然是无意义的

局部变量和全局变量

局部变量

局部变量也称为内部变量。局部变量是在函数内作定义说明的。其作用域仅限于函数内, 离开该函数后再使用这种变量是非法的

关于局部变量的作用域还要说明以下几点:

  • 主函数中定义的变量也只能在主函数中使用,不能在其它函数中使用

  • 形参变量是属于被调函数的局部变量,实参变量是属于主调函数的局部变量

  • 允许在不同的函数中使用相同的变量名,它们代表不同的对象,分配不同的单元,互不干扰,也不会发生混淆

  • 在复合语句中也可定义变量,其作用域只在复合语句范围内

全局变量

全局变量也称为外部变量,它是在函数外部定义的变量,其作用域是整个源程序。在函数中使用全局变量,一般应作全局变量说明

如果同一个源文件中,外部变量与局部变量同名,则在局部变量的作用范围内,外部变量被“屏蔽”,即它不起作用

变量的存储类别

动态存储方式和静态动态存储方式

从变量值存在的作时间(即生存期)角度来分,可以分为静态存储方式和动态存储方式。

静态存储方式:是指在程序运行期间分配固定的存储空间的方式。

动态存储方式:是在程序运行期间根据需要进行动态的分配存储空间的方式。

用户存储空间可以分为三个部分

  • 程序区

  • 静态存储区

  • 动态存储区

全局变量全部存放在静态存储区,在程序开始执行时给全局变量分配存储区,程序行完毕就释放

动态存储区存放以下数据:

  • 函数形式参数

  • 自动变量

  • 函数调用时的现场保护和返回地址

auto变量

在函数的局部变量,不专门声明为static存储类别,都是动态地分配存储空间的,数据存储在动态存储区中

关键字auto可以省略,auto不写则隐含定为“自动存储类别”,属于动态存储方式

用static声明局部变量

希望函数中的局部变量的值在函数调用结束后不消失而保留原值,这时就应该指定局部变量为“静态局部变量”,用关键字static进行声明

对静态局部变量的说明:

  • 静态局部变量属于静态存储类别,在静态存储区内分配存储单元

  • 静态局部变量在编译时赋初值,即只赋初值一次

  • 如果在定义局部变量时不赋初值的话,则对静态局部变量来说,编译时自动赋初值0(对数值型变量)或空字符(对字符变量)。而对自动变量来说,如果不赋初值则它的值是一个不确定的值

register变量

为了提高效率,C语言允许将局部变量得值放在CPU中的寄存器中,这种变量叫“寄存器变量”,用关键字register作声明

  • 只有局部自动变量和形式参数可以作为寄存器变量

  • 一个计算机系统中的寄存器数目有限,不能定义任意多个寄存器变量

  • 局部静态变量不能定义为寄存器变量

用extern声明外部示例页面变量

外部变量(即全局变量)是在函数的外部定义的,它的作用域为从变量定义处开始,到本程序文件的末尾

在定义点之前的函数想引用该外部变量,则应该在引用之前用关键字extern对该变量作“外部变量声明”

相关文章

【数据结构】——哈夫曼树

速通回忆 这里是完整的代码和运行结果,可以直接选择看下面代码的思路去快速回忆哈夫曼树,或从下面理论部分开始学习 ``` #include "stdio.h" #include "stdlib.h" /* 哈夫曼树结点的结构体 */ typedef struct { int weight; /* 权重 */ int parent; /* 父母结点下标 */ int l...

c

强化C【C语言笔记】——位运算

位运算符C语言提供了六种位运算符 - &:按位与 - !:按位或 - ^:异或 - ~:取反 - <<:左移 - \>>:右移 按位与运算 **其功能是参与运算的两数各对应的二进位相与。只有对应的两个二进位均为1时,结果位才为1,否则为0** 按位与运算通常用来对某些位清0 按位或运算 **其功能是参与运算的两数各对应的二进位相或。只要对应的二个二进位有一个为1时,结果位就...

c

C语言中规中矩的大树

**没事干,写个树玩玩,真正的“撸树”** 在Ubuntu终端、VScode终端显示 代码 ``` #include "stdio.h" int main(){ int high = 5; //层高 int count = 5; //层数 int start; //每层开始*数 int...

c