C语言K&R圣经笔记 4.2返回非整数的函数

4.2 返回非整数的函数

到目前为止,我们给出的函数样例,不是不返回值(void)就是返回 int。如果函数必须要返回其他类型呢?许多的数值函数如 sqrt,sin 和 cos 返回 double;其他特定的函数返回其他类型的值。为了说明该如何处理这种情况,我们来编写并使用函数 atof(s),它将字符串 s 转换成对应的双精度浮点数。 atof 是 我们在第二章和第三章所展示的 atoi 函数的扩展。它能处理可选的正负号和小数点,以及可能缺失的整数或小数部分。我们即将给出的版本不是一个高质量的输入转换例程,因为我们不想占用更多篇幅。标准库中包含了一个 atof,在头文件 <stdlib.h>中声明。

首先,因为不返回int,故atof 必须声明它的返回值。返回类型放在函数名称的前面:

c 复制代码
#include <ctype.h>

/* atof: 将字符串s转换成double */
double atof(char s[])
{
	double val, power;
	int i, sign;
	
	for (i = 0; isspace(s[i]); i++)  /* 跳过空格 */
		;
	sign = s[i] == '-' ? -1 : 1;
	if (s[i] == '+' || s[i] == '-')
		i++;
	for (val = 0.0; isdigit(s[i]); i++)
		val = 10.0 * val + (s[i] - '0');
	if (s[i] == '.')
		i++;
	for (power = 1.0; isdigit(s[i]); i+) {
		val = 10.0 * val + (s[i] - '0');
		power *= 10.0;
	}
	return sign * val / power;
}

其次,但是也同样重要的,调用者必须知道 atof 返回非int值。保证这一点的一种办法是在调用者函数内显式声明 atof。这种方法展示在下面这个简单的计算器中(勉强够用来做账单结算)。计算器每行读取一个可能带符号的数,将它们加起来,并在每次输入后打印当前的和。

c 复制代码
#include <stdio.h>

#define MAXLINE 100

/* 简单的计算器 */
main()
{
	double sum, atof(char []);
	char line[MAXLINE];
	int getline(char line[], int max);

	sum = 0;
	while (getline(line, MAXLINE) > 0)
		printf("\t%g\n", sum += atof(line));
	return 0;
}

其中的声明

c 复制代码
double sum, atof(char []);

表示sum 是一个double变量,而 atof 是一个函数,它有一个 char\[\] 参数,并返回double。

函数 atof 的声明和定义必须一致。如果在同一个源文件内, atof 自身定义的类型与 main 调用它时声明的类型不一致,则编译器能检测到这个错误。但如果(更有可能)atof 是分开编译的,无法检测到两者不匹配,atof 返回 double 而 main 将它当作 int,就会得到无意义的结果。

鉴于我们说过声明必须与定义匹配,这个说法可能令人吃惊。导致不匹配发生的原因在于,如果没有函数原型,则该函数第一次在表达式中出现时,它会被隐式声明,比如

c 复制代码
sum += atof(line)

如果一个没有被事先声明的名称出现在表达式中,而且名字后面还跟着左括号,则它被根据上下文声明为一个函数名称,该函数被假定返回int,且对其参数不做任何假定。更进一步,如果函数声明没有包括参数,例如

c 复制代码
double atof();

此时同样也不会对 atof 的参数做任何假定;所有参数校验都会被关闭。对空参数列表的这种特殊处理,是为了让新编译器能够编译旧的C程序。但新写的程序如果还这么做,会是非常糟糕的。如果函数有参数,就要声明出来;如果没有参数,使用void。

有了正确声明的atof,我们就能用它来写atoi(把字符串转换成int):

c 复制代码
/* atoi: 使用atof将字符串s转换成整数 */
int atoi(char s[])
{
	double atof(char s[]);
	return (int) atof(s);
}

注意其中的声明结构和 return 语句。

c 复制代码
return 表达式;

在返回发生之前,其中表达式的值会被转换成函数的类型。因此,当出现在这个 return 里面时,atof 的值 ,一个 double,会自动被转换成 int,因为 atoi 函数返回一个 int。然而,这个操作会潜在地丢失信息,因此一些编译器会给出警告。强制类型转换显式地告知编译器,这个操作是有意的,从而抑制了告警。

练习 4-2:扩展 atof,使之能处理科学计数形式

c 复制代码
123.45e-6

其中的浮点数后面可以跟着 e 或 E,以及可选的带符号的幂。

相关推荐
暴躁小师兄数据学院40 分钟前
【AI大数据工程师特训笔记】第14讲:Linux操作系统与shell脚本
大数据·人工智能·笔记
QiLinkOS1 小时前
《打破“用爱发电”:一种基于 Gitee 与时间戳的开源权益分配机制探索》
c语言·数据结构·c++·科技·算法·gitee·开源
土狗TuGou1 小时前
SQL内功笔记 · 第8篇:事务的四大特性与隔离级别
数据库·笔记·后端·sql·mysql·oracle
智者知已应修善业2 小时前
【51单片机用T0定时器方式1,实现0.5S的时间间隔实现第一次一个灯亮、第二次二个灯亮,直到全部灯亮,然后重复整个过程】2023-12-29
c++·经验分享·笔记·算法·51单片机
社交怪人2 小时前
【范围判断】信息学奥赛一本通C语言解法(题号2052)
c语言
智者知已应修善业2 小时前
【51单片机4位静态数码管显示1234】2023-11-14
c++·经验分享·笔记·算法·51单片机
whyTeaFo3 小时前
MIT6.1810: xv6 book Chapter4: Traps and system calls 笔记
笔记
jimbo_lee3 小时前
yocto 用法(随手笔记,记录以备不时之需)
笔记·yocto
LONGZETECH4 小时前
软硬协同+故障注入:无人机仿真维修与操控仿真底层算法逻辑拆解
大数据·c语言·算法·3d·unity·无人机
zlinear数据采集卡4 小时前
SPI Flash存储电路深度解析:从芯片选型到ZLinear采集卡的实战设计
c语言·嵌入式硬件·自动化·硬件架构