当前位置: 首页 > news >正文

C语言学习——函数

目录

八、函数

8.1概述

8.2函数定义的一般形式

无参函数

有参函数

空函数

8.3函数参数和函数的值

形式参数和实际参数

函数的返回值

8.4函数的调用

函数调用的一般形式

函数调用的方式

1.函数语句

2.函数表达式

3.函数参数

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

8.5函数的嵌套调用

8.6函数的递归调用


八、函数

8.1概述

        一个较大的程序一般应分为若干程序模块,每一个模块用来实现一个特定的功能。所有高级语言中都有子程序这个概念,用子程序实现模块的功能。在C语言中,子程序的作用是由函数来完成的。一个C程序可由一个主函数和若干函数来构成的。由主函数调用其他函数,其他函数也可以相互调用。同一个函数可以被一个或者多个函数调用任意多次。

        在程序开发中,常将一些常用的功能模块编写成函数,放在公共函数库供大家选用。所以,我们要善于利用函数,以减少重复编写程序段的工作量。

8.2函数定义的一般形式

无参函数

定义无参函数的一般形式:

类型标识符 函数名 ()

{

声明部分

语句部分

}

有参函数

定义有参函数的一般形式:

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

{

声明部分

语句部分

}

例如:

int max(int x, int y)
{int z;      //函数体中的声明部分z = x>y?x:y;return z;
}

如果在定义函数时不指定函数类型,系统会隐含指定函数类型为int型。因此上面定义的max函数左端的int可以省写。

空函数

空函数的定义形式为:

类型说明符 函数名()

{ }

例如:

int dummy(){}

8.3函数参数和函数的值

形式参数和实际参数

在调用函数时,大多数情况下,主函数和调用函数之间有数据传递的关系。这就是前面提到的有参函数。

在定义函数时函数名后面括号中的变量名称为“形式参数”,简称“形参”。

在主函数中调用一个函数时,函数后面括号中的参数(可以是一个表达式)称为“实际参数”,简称“实参”

调用函数时的数据传递

#include<stdio.h>
​
int main()
{int max(int x, int y);   //对max函数声明int a,b,c;scanf("%d%d",&a,&b);c = max(a,b);printf("max is %d\n",c); return 0;} int max(int x, int y)
{int z;z = x>y?x:y;return z;
}

关于形参和实参的说明:

  • 在定义函数中指定的形参,在未出现函数调用时,它们并不占内存中的存储单元。只有在发生函数调用时,函数max中的形参才被分配到内存单元,在调用结束后,形参所占的内存单元也被释放。

  • 实参可以是常量、变量或表达式。例如:max(3,a+b),但是要求他们有确定的值,在调用时将实参的值赋给形参。

  • 在被定义的函数中,必须指定形参的类型。

  • 实参和形参的类型应相同或赋值兼容。

  • 在C语言中,实参向形参的数据传递是“值传递”,单向传递,只由实参传给形参,而不能有形参传回来给实参。在内存中,实参单元与形参单元是不同的单元。

    在调用函数时,给形参分配存储单元,并将实参对应的值传递给形参,调用结束后,形参单元被释放,实参单元仍保留并维持原值。因此,在执行一个被调用函数时,形参的值如果发生改变,并不会改变主调函数的实参的值。

函数的返回值

通常,希望通过函数调用使主调函数能得到一个确定的值,这就是函数的返回值。下面对函数值作一些说明:

(1)函数的返回值是通过函数中的return语句获得的。return语句将被调用函数中的一个确定的值带回主调函数中去。如果需要从被调用函数带回一个函数值(供主函数使用),被调用函数中必须包含一个return语句。如果不需要从被调函数带回函数值可以不要return语句。

return语句后面的括号也可以不要,如“return z”等价于“return (z)”。

return后面的值可以是一个表达式。

(2)函数值的类型函数的返回值属于某一确定的类型,所以,应当在定义函数时指定函数值的类型。

在C语言中,凡不加类型说明的函数,自动按整型处理。

(3)在定义函数时指定的函数类型一般应该和return语句中的表达式类型一致。

如果函数值的类型和return语句中表达式的类型不一致,则以函数类型的为准。对数值型数据,可以自动进行类型转换。即函数类型决定返回值的类型。

返回值类型于函数类型不同。将上面的代码稍作改动(注意:是变量的类型改动)

#include<stdio.h>
​
int main()
{int max(float x, float y);   //对max函数声明float a,b;int c;scanf("%f%f",&a,&b);c = max(a,b);printf("max is %d\n",c); return 0;} int max(float x, float y)
{float z;  z = x>y?x:y;return z;
}
//输入 1.5 2.5
//输出:max is 2

解释:函数max定义为整型,而return语句中的z为实型,二者不一致。按上述规定,现将z转换为整型,然后max(x,y)带回一个数值2返回主调函数main。如果将main函数中的c定义为实型,用%f格式输出,也是输出2.000000。

(4)对于不带回值的函数,应当用“void”定义函数为“无类型”(或称“空类型”)。这样,系统就保证不使函数带回任何值,即禁止在调用函数中使用被调函数的返回值。此时,在函数体中不得出现有返回值的return语句。

8.4函数的调用

函数调用的一般形式

函数名(实参表列)

  • 如果是调用无参函数,则:实参表列“可以没有,但括号不能省略。

  • 如果实参表列包含多个实参,则各个参数间用逗号隔开。

  • 实参和形参的个数应相等,类型应匹配。

  • 实参和形参按顺序对应,一一传递数据。

函数调用的方式

按函数在程序中出现的位置来分,可以有以下3种函数调用方式。

1.函数语句

把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定的操作。

max();
2.函数表达式

函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值一参加表达式的计算。

c = 2*max(a,b); //max只是表达式的一部分
3.函数参数

函数调用作为一个函数的实参。例如:

//1.
m = max(a,mx(b,c));
//2.
printf("%d",max(a,b));

函数调用作为函数的参数,实质上也是函数表达式形式调用的一种,因为函数参数本来就要求表达式形式。

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

在一个函数中调用另一个函数(即被调用函数)需要具备的条件如下。

  • 首先调用的函数必须是已经存在的函数(是函数库或者用户自己定义的函数)。

  • 如果使用库函数,还应该在本文件开头用#include命令将调用有关函数时所需用到的信息“包含”到本文件中。

  • 如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一文件中),应该在主调函数中队被调用的函数作声明。

函数原型的一般形式有两种:

  • 函数类型 函数名(参数类型1,参数类型2,··· 参数类型n);

  • 函数类型 函数名(参数类型1 参数名1,参数类型2 参数名2, ··· ,参数类型n 参数名n);

8.5函数的嵌套调用

C语言的函数定义是互相平行、独立的,也就是说,在定义函数时,一个函数内不能包含另一个函数。

C语言不能嵌套定义函数,但可以嵌套调用函数,也就是说,在调用一个函数的过程中,又调用另一个函数。

8.6函数的递归调用

在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。C语言的特点之一就是在于允许函数的递归调用。例如:

int f(int x)
{int y,z;z=f(y);return (2*z);
}

递归调用会无终止的自身调用。而程序中是不应该出现这种情况的,而应出现有限次数、有终止的递归调用,这可以用if语句来控制,只有在某一条件成立时才继续执行递归调用;否则就不再继续。

声明:本文章为个人学习笔记,资料整理参考谭浩强《C程序设计(第三版)》如有错误,欢迎大家指正!

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • MySQL常用的日期和时间函数
  • oracle 比较两个值取小使用LEAST函数
  • 2024年湖北省建筑施工特种作业人员证书延期申请/年审
  • 精彩回顾 | ROS暑期“无人机自主追踪小车”训练营
  • 深度学习四大框架之争(Tensorflow、Pytorch、Keras和Paddle)
  • 鸿蒙笔记--Socket
  • 数据结构(邓俊辉)学习笔记】词典 02—— 散列函数
  • 用python实现求两个整数的最大公约数
  • vue 开发工具 Hbuilder 简介及应用
  • Python教程(十二):面向对象高级编程详解
  • haproxy的安装和服务信息
  • 管好“黄金数据”,浪潮海岳助力企业释放主数据潜能
  • LVS集群中的负载均衡技术
  • springboot怎么使用Redisson
  • C#表达式编程指南: 执行表达式、解释表达式、生成表达式,翻译表达式的详解与示例
  • SegmentFault for Android 3.0 发布
  • 【刷算法】从上往下打印二叉树
  • C++类中的特殊成员函数
  • git 常用命令
  • JavaScript 无符号位移运算符 三个大于号 的使用方法
  • Redux 中间件分析
  • storm drpc实例
  • Vue2 SSR 的优化之旅
  • Webpack 4 学习01(基础配置)
  • yii2中session跨域名的问题
  • 阿里云容器服务区块链解决方案全新升级 支持Hyperledger Fabric v1.1
  • 基于游标的分页接口实现
  • 记一次和乔布斯合作最难忘的经历
  • 精益 React 学习指南 (Lean React)- 1.5 React 与 DOM
  • 容器服务kubernetes弹性伸缩高级用法
  • 数据科学 第 3 章 11 字符串处理
  • 思维导图—你不知道的JavaScript中卷
  • 微信小程序填坑清单
  • 应用生命周期终极 DevOps 工具包
  • RDS-Mysql 物理备份恢复到本地数据库上
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • #define MODIFY_REG(REG, CLEARMASK, SETMASK)
  • (BAT向)Java岗常问高频面试汇总:MyBatis 微服务 Spring 分布式 MySQL等(1)
  • (C语言)strcpy与strcpy详解,与模拟实现
  • (Redis使用系列) SpringBoot 中对应2.0.x版本的Redis配置 一
  • (七)glDrawArry绘制
  • (七)微服务分布式云架构spring cloud - common-service 项目构建过程
  • (四)Controller接口控制器详解(三)
  • (已解决)vue+element-ui实现个人中心,仿照原神
  • .describe() python_Python-Win32com-Excel
  • .h头文件 .lib动态链接库文件 .dll 动态链接库
  • .net 7 上传文件踩坑
  • .NET 材料检测系统崩溃分析
  • .NET/C# 使用 SpanT 为字符串处理提升性能
  • .NetCore 如何动态路由
  • .NetCore实践篇:分布式监控Zipkin持久化之殇
  • .net中的Queue和Stack
  • @RequestMapping-占位符映射
  • [AI StoryDiffusion] 创造神奇故事,AI漫画大乱斗!
  • [Android]Android开发入门之HelloWorld