当前位置:嗨网首页>书籍在线阅读

30-把字符串转换为数字

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

11.9 把字符串转换为数字

数字既能以字符串形式存储,也能以数值形式存储。把数字存储为字符串就是存储数字字符。例如,数字 213'2''1''3''\0' 的形式被存储在字符串数组中。以数值形式存储 213 ,存储的是 int 类型的值。

C要求用数值形式进行数值运算(如,加法和比较)。但是在屏幕上显示数字则要求字符串形式,因为屏幕显示的是字符。 printf()sprintf() 函数,通过 %d 和其他转换说明,把数字从数值形式转换为字符串形式, scanf() 可以把输入字符串转换为数值形式。C还有一些函数专门用于把字符串形式转换成数值形式。

假设你编写的程序需要使用数值命令形参,但是命令形参数被读取为字符串。因此,要使用数值必须先把字符串转换为数字。如果需要整数,可以使用 atoi() 函数(用于把字母数字转换成整数),该函数接受一个字符串作为参数,返回相应的整数值。程序清单11.32中的程序示例演示了该函数的用法。

程序清单11.32  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和Linux的提示符(一些UNIX系统使用 % )。命令行参数 3 被存储为字符串 3\0atoi() 函数把该字符串转换为整数值 3 ,然后该值被赋给 times 。该值确定了执行 for 循环的次数。

如果运行该程序时没有提供命令行参数,那么 argc < 2 为真,程序给出一条提示信息后结束。如果 times0 或负数,情况也是如此。 C 语言逻辑运算符的求值顺序保证了如果 argc < 2 ,就不会对 atoi(argv[1]) 求值。

如果字符串仅以整数开头, atoi() 函数也能处理,它只把开头的整数转换为字符。例如, atoi("42regular") 将返回整数 42 。如果在命令行输入 hello what 会怎样?在我们所用的C实现中,如果命令行参数不是数字, atoi() 函数返回 0 。然而C标准规定,这种情况下的行为是未定义的。因此,使用有错误检测功能的 strtol() 函数(马上介绍)会更安全。

该程序中包含了 stdlib.h 头文件,因为从ANSI C开始,该头文件中包含了 atoi() 函数的原型。除此之外,还包含了 atof()atol() 函数的原型。 atof() 函数把字符串转换成 double 类型的值, atol() 函数把字符串转换成 long 类型的值。 atof()atol() 的工作原理和 atoi() 类似,因此它们分别返回 double 类型和 long 类型。

ANSI C还提供一套更智能的函数: strtol() 把字符串转换成 long 类型的值, strtoul() 把字符串转换成 unsigned long 类型的值, strtod() 把字符串转换成 double 类型的值。这些函数的智能之处在于识别和报告字符串中的首字符是否是数字。而且, strtol()strtoul() 还可以指定数字的进制。

下面的程序示例中涉及 strtol() 函数,其原型如下:

long strtol(const char * restrict nptr, char ** restrict endptr, int base);

这里, nptr 是指向待转换字符串的指针, endptr 是一个指针的地址,该指针被设置为标识输入数字结束字符的地址, base 表示以什么进制写入数字。程序清单11.33演示了该函数的用法。

程序清单11.33  strcnvt.c 程序

/* strcnvt.c -- 使用 strtol()  */
#include <stdio.h>
#include <stdlib.h>
#define LIM 30
char * s_gets(char * st, int n);
int main()
{
     char number[LIM];
     char * end;
     long value;
     puts("Enter a number (empty line to quit):");
     while (s_gets(number, LIM) && number[0] != '\0')
     {
          value = strtol(number, &end, 10);  /* 十进制 */
          printf("base 10 input, base 10 output: %ld, stopped at %s (%d)\n",
                       value, end, *end);
          value = strtol(number, &end, 16);  /* 十六进制 */
          printf("base 16 input, base 10 output: %ld, stopped at %s (%d)\n",
                       value, end, *end);
          puts("Next number:");
     }
     puts("Bye!\n");
     return 0;
}
char * s_gets(char * st, int n)
{
     char * ret_val;
     int i = 0;
     ret_val = fgets(st, n, stdin);
     if (ret_val)
     {
          while (st[i] != '\n' && st[i] != '\0')
               i++;
          if (st[i] == '\n')
               st[i] = '\0';
          else
               while (getchar() != '\n')
                     continue;
     }
     return ret_val;
}

下面是该程序的输出示例:

Enter a number (empty line to quit):
10
base 10 input, base 10 output: 10, stopped at (0)
base 16 input, base 10 output: 16, stopped at (0)
Next number:
10atom
base 10 input, base 10 output: 10, stopped at atom (97)
base 16 input, base 10 output: 266, stopped at tom (116)
Next number:
Bye!

首先注意,当 base 分别为 1016 时,字符串 "10" 分别被转换成数字 1016 。还要注意,如果 end 指向一个字符, end 就是一个字符。因此,第1次转换在读到空字符时结束,此时 end 指向空字符。打印 end 会显示一个空字符串,以 %d 转换说明输出 end 显示的是空字符的ASCII码。

对于第2个输入的字符串,当 base10 时, end 的值是 'a' 字符的地址。所以打印 end 显示的是字符串 "atom" ,打印* end 显示的是 'a' 字符的ASCII码。然而,当 base16 时, 'a' 字符被识别为一个有效的十六进制数, strtol() 函数把十六进制数 10a 转换成十进制数 266

strtol() 函数最多可以转换三十六进制, 'a'~'z' 字符都可用作数字。 strtoul() 函数与该函数类似,但是它把字符串转换成无符号值。 strtod() 函数只以十进制转换,因此它只需要两个参数。

许多实现使用 itoa()ftoa() 函数分别把整数和浮点数转换成字符串。但是这两个函数并不是C标准库的成员,可以用 sprintf() 函数代替它们,因为 sprintf() 的兼容性更好。