数字即能以字符串形式也能 以数字形式存储。以字符串形式存储数字就是存储数字字符。例如,数字213即能以数字'2'、‘1’、‘3’、‘\0’的形式存储在一个字符串数组中。以数字形式存储213意味着把字存储为 一个int数值。对于数字运算C要求数字形式。但是在屏幕上显示数字却要求字符串形式,这是因为屏幕显示的字符。printf()和sprintf()函数通过%d或其他说明符把数字形式转换为字符串形式或者相反。C还有一些函数专门用于把字符串形式转换为数字形式。
假如,您想编写一个使用数字命令程序。很不巧的是,命令行参数是以字符串形式被读取的。因此,要想使用数字值,就必须先把字符串转换为数字。如果数字是个整数,那就可以使用atoi()(代表alphanumeric to integer)。atoi()函数以字符串为参数,返回相应的整数值。
程序清单11.28 hello.c程序
/*hello.c 把命令行参数转换成数字*/
#include <stdio.h>
#include <stdlib.h>
int main(int argc,char *argv[])
{
int i,times;
if(argc<2 || (times = atoi(argv[1]))<1)
printf("Usage: %s positive-number\n",argv[0]);
else
for(i=0;i<times;i++)
puts("Hello,good looking!");
return 0;
}
下面是一个运行示例:
% hello 3
Hello,good looking!
Hello,good looking!
Hello,good looking!
%是UNIX提示符。命令行参数3以字符串"3\0"的形式存放。atoi()函数把这个字符串转换为整数3.然后把3赋给times。这样就决定了for循环执行的次数。
如果运行程序时没有提供命令行参数,argc<2判断就会中断程序并给出一个提示信息。如果times为0或为负,也会发生同样的情况。C的逻辑运算符的运算顺序确保:如果argc<2,就不再运算atoi(argv[1])。
如果字符串只是以一个整数开头,atoi()函数仍然可以工作。这种情况下,atoi()函数遇到非整数部分之前一直转换字符。例如,atoi("42regular")返回整数42。如果命令行类似hello what,又会出现什么情况呢?在我们使用的C的实现上,如果参数不能识别为数字,atoi()函数返回一个0值。但ANSI标准规定,上述情况下的行为是未定义的。稍后我们将介绍strtol()函数可以提供更可靠的错误检测。
我们包含了stdlib.h头文件,这是因为在ANSI中这个文件包含了atoi()函数的声明。此外,这个头文件还包含了atof()和atol()函数的声明。atof()函数把一个字符串转换为double类型的值,atol()函数则把字符串转换为long类型的值。它们的作用和atoi()类似,因此分别为double和long类型。
ANSI C 提供了这些函数的更复杂版本:strtol()、strtoul()和strtod()。其中,strtol()函数把一个字符串转换为long值,strtoul()把一个字符串转换为unsigned long型值,strtod()函数把一个字符串转换为double型值。这些函数的复杂性在于它们还可以识别并报告字符串中非数字部分的第一个字符。strtol()和strtoul()函数还允许您指定数字的基数。
下面看一个涉及strtol()函数的例子。函数原型如下:
long strtol(const char *nptr, char **endptr, int base);
在这里,nptr是一个指向您希望转换的字符串的指针,endptr是指向标志输入数字的结束字符的指针的地址,base是数字的基数。
程序清单 11.29 strcnvt.c程序
/*strcnvt.c 尝试使用strtol()函数*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
char number[30];
char *end;
long value;
puts("Enter a number(empty line to quit): ");
while(gets(number) && number[0]!='\0')
{
value=strtol(number,&end,10);
printf("value:%ld, stopped at %s(%d) \n",
value,end,*end);
value=strtol(number,&end,16); /*基于16*/
printf("value:%ld, stopped at %s(%d) \n",
value,end,*end);
puts("Next number: ");
}
puts("Bye!\n");
return 0;
}
下面是一些输出示例:
Enter a number(empty line to quit):
10
value:10, stopped at (0)
value:16, stopped at (0)
Next number:
10atom
value:10, stopped at atom(97)
value:266, stopped at tom(116)
Next number:
Bye!
首先请注意:如果基数是10,字符串“10”就被转换为10;如果基数是16,字符串”10“就被转换为16。还要注意,如果end指向一个字符,那么*end就是一个字符。因此,第一次转换在遇到空字符时结束,这样end就指向空字符。如果输出end,会显示一个空字符,如果用%d格式输出*end,就会显示空字符的ASCII 码。
对于输入的第二个字符串(以10为基数进行解释),end是'a'字符的地址。因此,输出end显示的是字符串"atom",输出*end显示的则是'a'字符的ASCII码。但是,如果基数是16,'a'字符就会被识别为一个有效的十六进制数字,函数会把16进制10a转换为十进制的266。
strtol()函数最多可以有三十六进制,使用一直到'z'的字母作为数字。strtoul()函数也一样,但它转换的是无符号值。strtod()函数只按照十进制进行转换,因此它只使用两个参数。
很多实现中都使用itoa()和ftoa()函数把整点和浮点数转换为字符串。但是这两个函数并不是ANSI C库里的函数;如果要求兼容性更好,可以使用sprintf()函数来完成这些功能 。