C语言KR圣经笔记 4.1函数基础

第4章 函数

函数将大的计算任务拆分成小份,还能让我们在他人已完成的基础上开发,而不必从头开始。恰当的函数隐藏了程序中那些不需要知道操作细节的部分,这样就使整体更加清晰,并且能减少修改的痛苦。

C的设计使得函数的使用高效而简单;C程序通常由很多小函数,而不是由几个大函数构成。一个程序可以放在一个或多个源文件中。多个源文件可以分开编译,并与库中早已编译好的函数一起加载。然而我们这里不会介绍这个过程,因为各个系统的细节都不一样。

函数声明和定义是ANSI标准对C语言做出最显著改动的地方。如我们最早在第一章所见,当函数声明时可以声明参数的类型。函数定义的语法也改了,这样声明和定义就匹配了。这使编译器有可能比之前检测到更多的错误。更进一步,当参数被正确声明后,会自动执行合适的强制类型转换。

标准澄清了名称范围的规则;还特别要求每个外部对象只能有一个定义。初始化更加通用:可以初始化自动数组和结构。

C预处理也得到加强。新的预处理机制包含了一套更完整的条件编译指令集合,从宏参数中创建字符串的方式,以及对宏扩展过程更好的控制。

4.1函数基础

首先,让我们设计并编写一个程序,它将打印包含某个特定“样式”或字符串的输入行。(这是Unix程序 grep的一个特例。)例如,在下列行中搜索包含“ould” 这几个字母的样式

Ah Love! could you and I with Fate conspire

To grasp this sorry Scheme of Things entire,

Would not we shatter it to bits -- and then

Re-mould it nearer to the Heart's Desire!

会得到

Ah Love! could you and I with Fate conspire

Would not we shatter it to bits -- and then

Re-mould it nearer to the Heart's Desire!

这项工作可以很整齐地分为三部分:

while (there is another line)

        if (the line contains the patten)

                print it

尽管可以将所有这些代码都放到 main 函数里,但更好的方式是把每个部分都做成独立的函数,以便合理利用这个结构。三个小块比一个大块好处理,因为无关的细节可以隐藏到函数里,而且把多余交互的机会最小化了。另外这些小块甚至可能用到其他程序中。

“while (there is another line) ”就是 getline,我们第一章写的函数。而 “print it ” 就是 printf ,别人早已经提供给我们了。这意味着我们只需要写一个例程来确定该行是否包含了样式。

解决这个问题,可以写一个函数 strindex(s, t) 返回字符串 t 在字符串 s 中的起始位置或索引,如果 s 不包含 t 则返回 -1。因为 C 的数组位置从0开始,索引下标只能是 0 或正数,这样负数如 -1 就能方便地用于标识失败。当我们后续需要更复杂的样式匹配时,我们只需要替换 strindex,其他代码都保持不变。(标准库提供了一个类似 strindex 的函数 strstr,不过它返回的是指针而不是索引。)

给出那么多设计之后,填充程序的细节就很简单了。下面是全部内容,你可以看到各个部分是如何结合在一起的。

#include <stdio.h>
#define MAX_LINE 1000    /* 输入行的最大长度 */int getline(char line[], int max);
int strindex(char source[], char searchfor[]);char pattern = "ould";    /* 要查找的样式 *//* 找到所有匹配样式的行 */
main()
{char line[MAX_LINE];int found = 0;while (getline(line, MAX_LINE) > 0)if (strindex(line, pattern) >= 0) {printf("%s", line);found++;}return found;
}/* getline: 把行存入s, 返回长度 */
int getline(char s[], int lim)
{int c, i;i = 0;while (--lim > 0 && (c = getchar()) != EOF && c != '\n')s[i++] = c;if (c == '\n')s[i++] = c;s[i] = '\0';return i;
}/* strindex: 返回s中t的索引,没有则返回-1 */
int strindex(char s[], char t[])
{int i, j, k;for (i = 0; s[i] != '\0'; i++) {for (j=i, k=0; t[k]!='\0' && s[j]==t[k]; j++, k++);if (k > 0 && t[k] == '\0')return i;}return -1;
}

每个函数定义都有如下格式

返回类型  函数名(参数声明)

{

        声明和语句

}

一些部分可以省略;最小的函数为

dummy() {}

它什么也不做,什么也不返回。像这样什么都不做的函数,有时在程序开发过程中被用来占位。如果没有返回类型,则假定返回int。

一个程序其实就是一系列变量定义和函数定义的集合。函数之间的通信是通过参数和函数的返回值,以及外部变量来完成。在源文件中,多个函数可以按任意顺序排列,而一个源程序也可以拆分成多个源文件,只要别把单个函数拆分开就行。

return 语句是把值从被调函数返回给调用者的机制。任何表达式都能跟在return后面:

return 表达式;

如有必要,表达式会被转换成函数的返回类型。表达式经常用括号括起来,不过这是可选的。

调用者函数可以自由地忽略返回值。更进一步地说,return后面不必有表达式;这种情况下没有值被返回给调用者。而当执行到函数最末尾的右大括号时,控制流程也同样返回给了调用者,并且不带返回值。如果一个函数在某些地方返回值,但在另一些地方不返回值,这不会不合法,但可能是麻烦的信号。不管怎样,如果一个函数无法返回值,它的“值”一定是垃圾值。

上面的样式搜索程序从main中返回一个状态,即匹配的次数。这个值对调用程序的环境来说是有价值的。

对于如何编译并加载有多个源文件的C程序,不同的系统有不同的机制。例如,在UNIX系统下是用第一章提到的 cc 命令。假设三个函数分别位于三个文件 main.c ,getline.c 和 strindex.c中,则命令

cc main.c getline.c strindex.c

会编译三个文件,并将目标代码分别放到 main.o, getline.o 和 strindex.o 三个文件内,然后将它们都加载到一个叫做 a.out 的可执行文件中。如果其中某个文件存在错误,假设就是main.c,则这个文件可以(修改后再次)单独编译,并将编译结果和之前成功的目标文件一起加载,使用如下命令:

cc main.c getline.o strindex.o

cc命令通过 “.c” 和 “.o”这样的命名规则来区分源文件和目标文件。

练习4-1:写函数 strrindex(s, t) ,返回 t 在 s 中最右侧的位置,若不包含则返回-1。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/189001.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2023-12-01 事业-代号s-引流技巧和营销思路

摘要: 2023-12-01 事业-代号s-引流技巧和营销思路 引流技巧和营销思路 独立站流量渠道主要有以下几种:1、CPC付费广告:搜索引擎、社交平台、广告联盟平台。2、网红营销:youtube、INS、博客论文、TT直播。适合比较时尚品类3、Affiliate促销网站:优惠券折扣网站发布产品优惠…

miot-plugin-sdk. npm install安装失败

miot-plugin-sdk-npm install安装失败 最紧公司要开发一台智能设备&#xff0c;经过同事的对比&#xff0c;选中了米家作为云平台&#xff0c;于是&#xff0c;我就负责开发app界面端&#xff0c;根据官方文档教程 下载了miot-plugin-sdk 程序&#xff0c;准备开始开发,结果悲…

PMIC : 一颗芯片解决N多问题

1、什么是PMIC Power Management Integrated Circuit&#xff08;PMIC&#xff09;中文是电源管理集成电路&#xff0c;主要特点是高集成度&#xff0c;将传统的多路输出电源封装在一颗芯片内&#xff0c;使得多电源应用场景高效率更高&#xff0c;体积更小。 PMIC 是当今电子…

嵌入式基础电路设计和常用芯片用法

文章目录 一、基础电路1. 按键电路2. 晶振电路3. 降压电路 二、常见芯片1. SN74HC244PWR2. TLP23623. ACS7244. LM3585. EL357-NB6. SMBJ30CA 一、基础电路 1. 按键电路 观察以上电路可知&#xff1a; 在按键SW1不按下的时候引脚BTN1是接着3V3的&#xff0c;所以默认为高电平…

windows判断端口是否在使用的bat脚本

脚本 REM 查询端口是否占用 netstat -ano|findstr 3306 >nul &&echo y >1.log ||echo n >1.log REM 读取文本内容赋值给变量 set /P resu<1.log if %resu% y (echo port in use ) else (echo port not in use ) mysql服务不运行的时候检测效果 mysql服…

Linux体系架构----Linux根目录下常见一级子目录的作用

文章目录 Linux 根目录下的一级子目录扮演着重要的角色&#xff0c;每个子目录都有其特定的作用和功能。以下是常见的 Linux 根目录下一级子目录及其作用&#xff1a; /bin&#xff08;Binary&#xff09;&#xff1a; 作用&#xff1a;存放系统启动和恢复所需的基本命令&#…

基于SpringBoot高校心理教育辅导设计与实现

摘 要 随着Internet技术的发展&#xff0c;心理教育辅导系统应运而生&#xff0c;心理教育辅导系统为用户提供了一个更为便利的心理测试咨询平台。所以&#xff0c;为了充分满足高校学生心理教育辅导的需求&#xff0c;特开发了本高校心理教育辅导系统。 本高校心理教育辅导系统…

【华为OD题库-050】树状结构查询-java

题目 通常使用多行的节点、父节点表示—棵树&#xff0c;比如: 西安 陕西 陕西 中国 江西 中国 中国 亚洲 泰国 亚洲 输入一个节点之后&#xff0c;请打印出来树中他的所有下层节点 输入描述 第一行输入行数&#xff0c;下面是多行数据&#xff0c;每行以空格区分节点和父节点 …

真实的软件测试日常工作是咋样的?

最近很多粉丝问我&#xff0c;小姐姐&#xff0c;现在大环境不景气&#xff0c;传统行业不好做了&#xff0c;想转行软件测试&#xff0c;想知道软件测试日常工作是咋样的&#xff1f;平常的工作内容是什么&#xff1f; 别急&#xff0c;今天跟大家细细说一下一个合格的软件测…

WordPress:解决xmlrpc.php被扫描爆破的风险

使用WordPress的朋友都知道&#xff0c;一些【垃圾渣渣】会利用xmlrpc.php文件来进行攻击&#xff0c;绕过WP后台错误登录次数限制进行爆破。虽然密码复杂的极难爆破&#xff0c;但及其占用服务器资源。 方法一、利用宝塔防火墙&#xff08;收费版&#xff09; 一般可以直接使…

springboot(ssm电影播放平台 在线电影系统Java(codeLW)

springboot(ssm电影播放平台 在线电影系统Java(code&LW) 开发语言&#xff1a;Java 框架&#xff1a;ssm/springboot vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff1a;mysql 5.7&#xff08;或8.0&#xff09…

MySQL锁篇

目录 一、MySQL中的锁 1.1、全局锁 1.2、表级锁 1.2.1、表锁 1.2.2、元数据锁&#xff08;MDL&#xff09; 1.2.3、意向锁 1.2.4、AUTO-INC 锁 1.3、行级锁 1.3.2、Gap Lock 1.3.3、Next-Key Lock 1.3.4、插入意向锁 二、MySQL 是怎么加锁的&#xff1f; 2.1、为什…

2312skia,11管理颜色及下载等

管理颜色 Skia使用的所有颜色空间,通过如何从该颜色空间,转换为叫XYZD50的通用"连接"颜色空间,来描述自己.可从相同描述中,推导出如何从XYZD50空间转换回原颜色空间. XYZD50是像RGB一样以三维表示的颜色空间,但XYZ部分则根本不像RGB,而是这些通道的线性混杂.Y最接近…

使用ttyd为你的Anroid设备提供web版控制台

嵌入式Android设备&#xff0c;众所周知要调试要开adb&#xff0c;涉及到安全问题通常要走一系列流程&#xff0c;非常复杂&#xff0c;对于维护人员要求比较高。因此考虑有没有一个方便的调试手段。 此外&#xff0c;我们还需要考虑x86的嵌入式设备的方案&#xff0c;最好有类…

四、C语言数据类型和变量

目录 1. 数据类型介绍 1.1 字符型 1.2 整型 1.3 浮点型 1.4 布尔类型 1.5 各种数据类型的长度 1.5.1 sizeof 操作符 1.5.2 数据类型长度 2. signed 和 unsigned 3. 数据类型的取值范围 4. 变量 4.1 变量的创建 4.2 变量的分类 5. 算术操作符&#xff1a;、-、*、…

SpringBoot——Quartz 定时任务

优质博文&#xff1a;IT-BLOG-CN 一、Scheduled 定时任务 【1】添加Scheduled相关依赖&#xff0c;它是Spring自带的一个jar包因此引入Spring的依赖&#xff1a; <dependency><groupId>org.springframework</groupId><artifactId>spring-context-su…

MySQL图书管理系统(49-94)源码

-- 九、 子查询 -- 无关子查询 -- 比较子查询&#xff1a;能确切知道子查询返回的是单值时&#xff0c;可以用>&#xff0c;<&#xff0c;&#xff0c;>&#xff0c;<&#xff0c;!或<>等比较运算符。 -- 49、 查询与“俞心怡”在同一个部门的读者的借…

诊所小程序开发,需要包含哪些功能,有什么注意事项?

开发一个诊所预约小程序&#xff0c;可以提高口腔诊所的服务效率和客户体验。那么&#xff0c;一般小程序的流程和功能包含哪些内容&#xff1f; 注册登录&#xff1a;用户可以快速授权并登录(可定制多种登录方式) 预约挂号&#xff1a;用户可以选择科室、医生、日期和时段进行…

为什么不能用System.currentTimeMillis()计算执行时间?

1. 前提概要 System.currentTimeMillis()是系统时间&#xff0c;系统时间修改、闰秒会导致跳动。System.nanoTime()仅用于计算耗时&#xff0c;和系统时间没有强关联。System.nanoTime()单位是纳秒&#xff0c;但不保证有纳秒的精度&#xff0c;但保证精度至少比System.curren…

Unity中Shader指令优化(编译后指令解析)

文章目录 前言一、我们先创建一个简单的Shader二、编译这个Shader&#xff0c;并且打开1、编译后注意事项2、编译平台 和 编译指令数3、顶点着色器用到的信息4、顶点着色器计算的核心部分5、片元着色器用到的信息6、片元着色器核心部分 前言 我们先读懂Shader编译后代码&#…