C语言字符串与数字转换
C语言字符串与数字转换

C语言字符串与数字转换

C语言字符串与数字转换

参考:
http://www.verydoc.net/c/00000777.html

1. 前言

在开发中常常遇到字符串与数字的相互转换,在这里列一下常用的函数,以备不时之需。

2. 字符串转数字

ANSI C 规范定义了 atof()、atoi()、atol()、strtod()、strtol()、strtoul() 共6个可以将字符串转换为数字的函数。
在 C99 / C++11 规范中又新增了5个函数,分别是 atoll()、strtof()、strtold()、strtoll()、strtoull()。

2.1. 有符号数转换

2.1.1. atoi/atol/atoll

int atoi(con​​st char * str);
long atol(const char * str);
long long atoll(const char * str); (自C99以来)

【 头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的整数值。
放弃任何空格字符,直到找到第一个非空白字符,然后采用尽可能多的字符以形成有效的整数表示并将它们转换为整数值。有效的整数值由以下部分组成:

  • (可选)加号或减号
  • 数字
  • 【返回值】
    整数值对应str成功的内容。 如果转换后的值超出了相应返回类型的范围,则返回值未定义。 如果不能执行转换,则返回0。

2.1.2. strtol/strtoll

long strtol(const char * str,char ** str_end,int base);(直到C99)
long strtol(const char * restrict str,char ** restrict str_end,int base);(自C99以来)
long long strtoll(const char * restrict str,char ** restrict str_end,int base);(自C99以来)

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的整数值。
放弃任何空格字符(通过调用标识isspace()),直到找到第一个非空白字符,然后接收尽可能多的字符以形成有效的base-n(其中n = base)整数表示并将它们转换为整数值。有效的整数值由以下部分组成:

  • (可选)加号或减号
  • (可选)prefix(0)指示八进制基数(只适用于基数为8或​0​)
  • (可选)前缀(0x或0X)表示十六进制基数(仅适用于基数为16或​0​)
  • 数字序列

base的有效值集合是{0,2,3,...,36}。base-2整数的有效数字集合是{0,1},对于base-3整数是{0,1,2},依此类推。对于大于等于的基数10,有效数字包含字母字符,从Aa基数为11的整数开始,到Zz基数为36的整数。字符的情况被忽略。

其他数字格式可以被当前安装的C语言环境接受。

如果基数的值是​0​,数字基地是自动检测:如果前缀是0,基地是八进制的,如果前缀是0x或0X,基地是十六进制,否则基数是十进制。

如果减号是输入序列的一部分,则根据数字序列计算的数值将被否定,如同在结果类型中使用一元减号一样。

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

如果str为空或者没有预期的形式,则不执行转换,并且(如果str_end不是NULL),则str的值将存储在str_end指向的对象中。

【返回值】

  • 如果成功,则返回与内容相对应的整数值str。
  • 如果转换后的值脱离的相应返回类型的范围时,发生错误的范围(设定errno到ERANGE)和LONG_MAX,LONG_MIN,LLONG_MAX或LLONG_MIN返回。
  • 如果不能执行转换,​0​则被返回。
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    // parsing with error handling
    const char *p = "10 200000000000000000000000000000 30 -40 junk";
    printf("Parsing '%s':\n", p);
    char *end;
    for (long i = strtol(p, &end, 10);
         p != end;
         i = strtol(p, &end, 10))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%ld\n", i);
    }

    // parsing without error handling
    printf("\"1010\" in binary  --> %ld\n", strtol("1010",NULL,2));
    printf("\"12\" in octal     --> %ld\n", strtol("12",NULL,8));
    printf("\"A\"  in hex       --> %ld\n", strtol("A",NULL,16));
    printf("\"junk\" in base-36 --> %ld\n", strtol("junk",NULL,36));
    printf("\"012\" in auto-detected base  --> %ld\n", strtol("012",NULL,0));
    printf("\"0xA\" in auto-detected base  --> %ld\n", strtol("0xA",NULL,0));
    printf("\"junk\" in auto-detected base -->  %ld\n", strtol("junk",NULL,0));
}

输出:

Parsing '10 200000000000000000000000000000 30 -40 junk':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 9223372036854775807
' 30' -> 30
' -40' -> -40
"1010" in binary  --> 10
"12" in octal     --> 10
"A"  in hex       --> 10
"junk" in base-36 --> 926192
"012" in auto-detected base  --> 10
"0xA" in auto-detected base  --> 10
"junk" in auto-detected base -->  0

2.2. 无符号数转换

2.2.1. strtoul/strtoull

unsigned long strtoul(const char * str,char ** str_end,int base);
unsigned long strtoul(const char * restrict str,char ** restrict str_end,int base);
unsigned long long strtoull(const char * restrict str,char ** restrict str_end,int base);

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节字符串中的无符号整数值。
放弃任何空白字符(通过调用标识isspace()),直到找到第一个非空白字符,然后接收尽可能多的字符以形成有效的base-n(其中n = base)无符号整数表示并将它们转换为整数值。有效的无符号整数值由以下部分组成:

  • (可选)加号或减号
  • (可选)prefix(0)指示八进制基数(只适用于基数为8或​0​)
  • (可选)前缀(0x或0X)表示十六进制基数(仅适用于基数为16或​0​)
  • 数字序列

base的有效值集合是{0,1,2,3,...,36}。base-2整数的有效数字集合是{0,1},对于base-3整数是{0,1,2},依此类推。对于大于等于的基数10,有效数字包含字母字符,从Aa基数为11的整数开始,到Zz基数为36的整数。字符的情况被忽略。

其他数字格式可以被当前安装的C语言环境接受。

如果基数的值是​0​,数字基地是自动检测:如果前缀是0,基地是八进制的,如果前缀是0x或0X,基地是十六进制,否则基数是十进制。

如果减号是输入序列的一部分,则根据数字序列计算的数值将被否定,如同使用无符号整数环绕规则的结果类型中的一元减号一样。

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
整数值对应str成功的内容。 如果转换后的值超出了相应返回类型的范围,则会发生范围错误(errno设置为ERANGE),并返回ULONG_MAX或ULLONG_MAX。 如果不能执行转换,则返回0。

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    const char *p = "10 200000000000000000000000000000 30 -40";
    printf("Parsing '%s':\n", p);
    char *end;
    for (unsigned long i = strtoul(p, &end, 10);
         p != end;
         i = strtoul(p, &end, 10))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%lu\n", i);
    }
}
Parsing '10 200000000000000000000000000000 30 -40':
'10' -> 10
' 200000000000000000000000000000' -> range error, got 18446744073709551615
' 30' -> 30
' -40' -> 18446744073709551576

2.3. 浮点数据转换

2.3.1. atof

【头文件】
#include <stdlib.h>

【原型】
double atof(const char *nptr);

【函数说明】
解释str指向的字节串中的浮点值。
函数丢弃任何空格字符(由std :: isspace()确定),直到找到第一个非空白字符。 然后,它需要尽可能多的字符来形成有效的浮点表示并将它们转换为浮点值。 有效的浮点值可以是以下值之一:
有效的浮点值可以是以下值之一:

  • 进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 非空十进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),e或者E跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 二进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 0x 或 0X
    • 非空的十六进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),p或者P跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 无限表达。它由以下部分组成:
    • (可选)加号或减号
    • INF或者INFINITY无视事件
  • 非数字表达式。它由以下部分组成:
    • (可选)加号或减号
    • NAN或NAN(char_sequence)忽略该NAN部分的情况。char_sequence只能包含字母数字字符。结果是静态的NaN浮点值。
  • 任何其他可能被当前安装的C接受的表达式 locale

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
若成功,则返回double值对应str的内容。 如果转换后的值超出了返回类型的范围,则返回值未定义。 如果不能执行转换,则返回0.0。

2.3.2. strtof/strtod/strtold

float strtof(const char * restrict str,char ** restrict str_end);
double strtod(const char * str,char ** str_end);
double strtod(const char * restrict str,char ** restrict str_end);
long double strtold(const char * restrict str,char ** restrict str_end);

【头文件】
#include <stdlib.h>

【函数说明】
解释str指向的字节串中的浮点值。
函数丢弃任何空格字符(由std :: isspace()确定),直到找到第一个非空白字符。 然后,它需要尽可能多的字符来形成有效的浮点表示并将它们转换为浮点值。 有效的浮点值可以是以下值之一:

  • 进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 非空十进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),e或者E跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 二进制浮点表达式。它由以下部分组成:
    • (可选)加号或减号
    • 0x 或 0X
    • 非空的十六进制数字序列可选地包含小数点字符(由当前C确定locale)(定义有效数字)
    • (可选),p或者P跟随可选的负号或加号和非空序列的十进制数字(定义指数)
  • 无限表达。它由以下部分组成:
    • (可选)加号或减号
    • INF或者INFINITY无视事件
  • 非数字表达式。它由以下部分组成:
    • (可选)加号或减号
    • NAN或NAN(char_sequence)忽略该NAN部分的情况。char_sequence只能包含字母数字字符。结果是静态的NaN浮点值。
  • 任何其他可能被当前安装的C接受的表达式 locale

这些函数将str_end指向的指针设置为指向经过最后解释的字符的字符。 如果str_end是NULL,它将被忽略。

【返回值】
浮点值对应str的成功内容。 如果转换后的值超出相应返回类型的范围,则会发生范围错误,并返回HUGE_VAL,HUGE_VALF或HUGE_VALL。 如果不能执行转换,则返回0。

#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

int main(void)
{
    // parsing with error handling
    const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
    printf("Parsing '%s':\n", p);
    char *end;
    for (double f = strtod(p, &end); p != end; f = strtod(p, &end))
    {
        printf("'%.*s' -> ", (int)(end-p), p);
        p = end;
        if (errno == ERANGE){
            printf("range error, got ");
            errno = 0;
        }
        printf("%f\n", f);
    }

    // parsing without error handling
    printf("\"  -0.0000000123junk\"  -->  %g\n", strtod("  -0.0000000123junk", NULL));
    printf("\"junk\"                 -->  %g\n", strtod("junk", NULL));
}
Parsing '111.11 -2.22 Nan inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz':
'111.11' -> 111.110000
' -2.22' -> -2.220000
' Nan' -> nan
' nan(2)' -> nan
' inF' -> inf
' 0X1.BC70A3D70A3D7P+6' -> 111.110000
'  1.18973e+4932' -> range error, got inf
"  -0.0000000123junk"  -->  -1.23e-08
"junk"                 -->  0

3. 数字转字符串

非标准实现,在window平台下可以使用,跨平台到linux不支持:

    itoa()                将整型值转换为字符串
    ltoa()                将长整型值转换为字符串
    ultoa()               将无符号长整型值转换为字符串
    ecvt()    将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点
    fcvt()    以指定位数为转换精度,余同ecvt()
    gcvt()    将双精度浮点型值转换为字符串,转换结果中包含十进制小数点    

更为通用的实现则是使用sprintf()函数

3.1. spintf

【头文件】
#include <stdio.h>
【原型】
int sprintf(char *str, const char *format, ...)

【函数说明】
str -- 这是指向一个字符数组的指针,该数组存储了 C 字符串。
format -- 这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length]specifier,具体讲解如下:

  • specifier(说明符)
    c   字符
    d 或 i   有符号十进制整数
    e   使用 e 字符的科学科学记数法(尾数和指数)
    E   使用 E 字符的科学科学记数法(尾数和指数)
    f   十进制浮点数
    g   自动选择 %e 或 %f 中合适的表示法
    G   自动选择 %E 或 %f 中合适的表示法
    o   有符号八进制
    s   字符的字符串
    u   无符号十进制整数
    x   无符号十六进制整数
    X   无符号十六进制整数(大写字母)
    p   指针地址
    n   无输出
    %   字符
  • flags(标识)
-
在给定的字段宽度内左对齐,默认是右对齐(参见 width 子说明符)。
+
强制在结果之前显示加号或减号(+ 或 -),即正数前面会显示 + 号。默认情况下,只有负数前面会显示一个 - 号。
(space) 
如果没有写入任何符号,则在该值前面插入一个空格。
#   
与 o、x 或 X 说明符一起使用时,非零值前面会分别显示 0、0x 或 0X。
与 e、E 和 f 一起使用时,会强制输出包含一个小数点,即使后边没有数字时也会显示小数点。默认情况下,如果后边没有数字时候,不会显示显示小数点。
与 g 或 G 一起使用时,结果与使用 e 或 E 时相同,但是尾部的零不会被移除。
0   
在指定填充 padding 的数字左边放置零(0),而不是空格(参见 width 子说明符)。
  • width(宽度)
(number)    要输出的字符的最小数目。如果输出的值短于该数,结果会用空格填充。如果输出的值长于该数,结果不会被截断。
*   宽度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
  • .precision(精度)
.number
对于整数说明符(d、i、o、u、x、X):precision 指定了要写入的数字的最小位数。如果写入的值短于该数,结果会用前导零来填充。如果写入的值长于该数,结果不会被截断。精度为 0 意味着不写入任何字符。
对于 e、E 和 f 说明符:要在小数点后输出的小数位数。
对于 g 和 G 说明符:要输出的最大有效位数。
对于 s: 要输出的最大字符数。默认情况下,所有字符都会被输出,直到遇到末尾的空字符。
对于 c 类型:没有任何影响。
当未指定任何精度时,默认为 1。如果指定时不带有一个显式值,则假定为 0。
.*  
精度在 format 字符串中未指定,但是会作为附加整数值参数放置于要被格式化的参数之前。
  • length(长度)
h   参数被解释为短整型或无符号短整型(仅适用于整数说明符:i、d、o、u、x 和 X)。
l   参数被解释为长整型或无符号长整型,适用于整数说明符(i、d、o、u、x 和 X)及说明符 c(表示一个宽字符)和 s(表示宽字符字符串)。
L   参数被解释为长双精度型(仅适用于浮点数说明符:e、E、f、g 和 G)。
  • 附加参数 -- 根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

【返回值】
如果成功,则返回写入的字符总数,不包括字符串追加在字符串末尾的空字符。如果失败,则返回一个负数。

#include <stdio.h>
#include <math.h>

int main()
{
   char str[80];

   sprintf(str, "Pi 的值 = %f", M_PI);
   puts(str);

   return(0);
}

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注