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

4.2 返回非整数的函数

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

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

#include 

/* 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。这种方法展示在下面这个简单的计算器中(勉强够用来做账单结算)。计算器每行读取一个可能带符号的数,将它们加起来,并在每次输入后打印当前的和。

#include 

#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;
}

其中的声明

double sum, atof(char []);

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

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

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

sum += atof(line)

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

double atof();

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

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

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

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

return 表达式;

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

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

123.45e-6

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

你可能感兴趣的:(C语言,c语言,笔记)