C语言学习第二十六天,今天学习函数。
4.2 返回非整数的函数
之前讨论的函数都是不返回任何值(void)或只返回int类型的函数。我们通过函数atof(s)来说明函数返回非整型值的方法。该函数把字符串s转换为相应的双精度浮点数。atof函数是atoi函数的扩展,atof函数需要处理可选的符号和小数点,并要考虑可能缺少整数部分或小数部分的情况。标准库中包含类似功能的atof函数,在头文件<stdlib.h>中声明。
首先,由于atof函数的返回值类型不是int,因此该函数必须声明返回值的类型。返回值的类型名应放在函数名字之前,如下所示:
#include <ctype.h>
/* atof函数: 把字符串s转换为相应的双精度浮点数 */
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函数返回的是非整型值,这一点也是很重要的。为了达到该目的,一种方法是调用函数中显示声明atof函数。下面所示的基本计算器程序(仅适用于支票薄计算)中有类似的声明。该程序在每行中读取一个数(数的前面可能有正负号),并对它们求和,在每次输入完成后把这些数的累计总和打印出来:
#include <stdio.h>
#define MAXLINE 100
/* 简单计算器程序 */
main() {
double sum, atof(char []);
char line[MAXLINE];
int getline1(char line[], int max);
sum = 0;
while (getline1(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类型,但上下文并不对其参数作任何假设。如果函数带有参数,则要声明它们;如果没有参数,则使用void进行声明。
在正确进行声明的函数atof基础上,我们可以利用它编写出函数atoi(将字符串转换为int类型) :
/* atoi函数:利用atof函数把字符串s转换为整数 */
int atoi(char s[]) {
double atof (char s[]);
return (int) atof(s);
}
在下列形式的return语句中:
return(表达式) ;
其中,表达式的值在返回之前将被转换为函数的类型。因为函数atoi的返回值为int类型, 所以,return语句中的atof函数的double类型值将被自动转换为int类型值。但是,这种操作可能会丢失信息,某些编译器可能会对此给出警告信息。在该函数中,由于采用了类型转换的方法显式声明了所要执行的转换操作,因此可以防止有关的警告信息。
练习4-2 对atof函数进行扩充,使它可以处理形如 123.45e-6 的科学表示法,其中,浮点数后面可能会紧跟一个e或E以及一个指数(可能有正负号)。
/* atof函数: 把字符串s转换为相应的双精度浮点数 */
double atof(char s[]) {
double val, power;
int i, sign, powerSign, powerNum;
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;
}
val = sign * val / power;
if(s[i] == 'e' || s[i] == 'E')
i++;
powerSign = '+';
if(s[i] == '+' || s[i] == '-') {
powerSign = s[i++];
}
for (powerNum=0;isdigit(s[i]); i++)
powerNum = 10.0 * powerNum +(s[i] - '0');
for (i = 0; i < powerNum; i++) {
if (powerSign == '-' ) {
val /= 10;
} else {
val *= 10;
}
}
return val;
}