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,以及可选的带符号的幂。

相关推荐
yuwinter10 分钟前
鸿蒙HarmonyOS学习笔记(2)
笔记·学习·harmonyos
游走于计算机中摆烂的1 小时前
启动前后端分离项目笔记
java·vue.js·笔记
珹洺1 小时前
C语言数据结构——详细讲解 双链表
c语言·开发语言·网络·数据结构·c++·算法·leetcode
你可以叫我仔哥呀2 小时前
ElasticSearch学习笔记三:基础操作(一)
笔记·学习·elasticsearch
maxiumII2 小时前
Diving into the STM32 HAL-----DAC笔记
笔记·stm32·嵌入式硬件
.Cnn2 小时前
用邻接矩阵实现图的深度优先遍历
c语言·数据结构·算法·深度优先·图论
2401_858286112 小时前
101.【C语言】数据结构之二叉树的堆实现(顺序结构) 下
c语言·开发语言·数据结构·算法·
寻找码源3 小时前
【头歌实训:利用kmp算法求子串在主串中不重叠出现的次数】
c语言·数据结构·算法·字符串·kmp
带多刺的玫瑰5 小时前
Leecode刷题C语言之统计不是特殊数字的数字数量
java·c语言·算法
美式小田5 小时前
单片机学习笔记 9. 8×8LED点阵屏
笔记·单片机·嵌入式硬件·学习