3. 数值字符串转换函数

  1. #include <stdlib.h>
  2.  
  3. int atoi(const char *nptr);
  4. double atof(const char *nptr);
  5. 返回值:转换结果

atoi把一个字符串开头可以识别成十进制整数的部分转换成int型,相当于下面要讲的strtol(nptr, (char **) NULL, 10);。例如atoi("123abc")的返回值是123,字符串开头可以有若干空格,例如atoi(" -90.6-")的返回值是-90。如果字符串开头没有可识别的整数,例如atoi("asdf"),则返回0,而atoi("0***")也返回0,根据返回值并不能区分这两种情况,所以使用atoi函数不能检查出错的情况。下面要讲的strtol函数可以设置errno,因此可以检查出错的情况,在严格的场合下应该用strtol,而atoi用起来更简便,所以也很常用。

atof把一个字符串开头可以识别成浮点数的部分转换成double型,相当于下面要讲的strtod(nptr, (char **) NULL);。字符串开头可以识别的浮点数格式和C语言的浮点数常量相同,例如atof("31.4 ")的返回值是31.4,atof("3.14e+1AB")的返回值也是31.4。atof也不能检查出错的情况,而strtod可以。

  1. #include <stdlib.h>
  2.  
  3. long int strtol(const char *nptr, char **endptr, int base);
  4. double strtod(const char *nptr, char **endptr);
  5. 返回值:转换结果,出错时设置errno

strtolatoi的增强版,主要体现在这几方面:

  • 不仅可以识别十进制整数,还可以识别其它进制的整数,取决于base参数,比如strtol("0XDEADbeE~~", NULL, 16)返回0xdeadbee的值,strtol("0777~~", NULL, 8)返回0777的值。

  • endptr是一个传出参数,函数返回时指向后面未被识别的第一个字符。例如char *pos; strtol("123abc", &pos, 10);strtol返回123,pos指向字符串中的字母a。如果字符串开头没有可识别的整数,例如char *pos; strtol("ABCabc", &pos, 10);,则strtol返回0,pos指向字符串开头,可以据此判断这种出错的情况,而这是atoi处理不了的。

  • 如果字符串中的整数值超出long int的表示范围(上溢或下溢),则strtol返回它所能表示的最大(或最小)整数,并设置errnoERANGE,例如strtol("0XDEADbeef~~", NULL, 16)返回0x7fffffff并设置errnoERANGE

回想一下使用fopen的套路if ( (fp = fopen(...)) == NULL) { 读取errno }fopen在出错时会返回NULL,因此我们知道需要读errno,但strtol在成功调用时也可能返回0x7fffffff,我们如何知道需要读errno呢?最严谨的做法是首先把errno置0,再调用strtol,再查看errno是否变成了错误码。Man Page上有一个很好的例子:

例 25.10. strtol的出错处理

  1. #include <stdlib.h>
  2. #include <limits.h>
  3. #include <stdio.h>
  4. #include <errno.h>
  5.  
  6. int main(int argc, char *argv[])
  7. {
  8. int base;
  9. char *endptr, *str;
  10. long val;
  11.  
  12. if (argc < 2) {
  13. fprintf(stderr, "Usage: %s str [base]\n", argv[0]);
  14. exit(EXIT_FAILURE);
  15. }
  16.  
  17. str = argv[1];
  18. base = (argc > 2) ? atoi(argv[2]) : 10;
  19.  
  20. errno = 0; /* To distinguish success/failure after call */
  21. val = strtol(str, &endptr, base);
  22.  
  23. /* Check for various possible errors */
  24.  
  25. if ((errno == ERANGE && (val == LONG_MAX || val == LONG_MIN))
  26. || (errno != 0 && val == 0)) {
  27. perror("strtol");
  28. exit(EXIT_FAILURE);
  29. }
  30.  
  31. if (endptr == str) {
  32. fprintf(stderr, "No digits were found\n");
  33. exit(EXIT_FAILURE);
  34. }
  35.  
  36. /* If we got here, strtol() successfully parsed a number */
  37.  
  38. printf("strtol() returned %ld\n", val);
  39.  
  40. if (*endptr != '\0') /* Not necessarily an error... */
  41. printf("Further characters after number: %s\n", endptr);
  42.  
  43. exit(EXIT_SUCCESS);
  44. }

strtodatof的增强版,增强的功能和strtol类似。