字符串转数字:三大库函数

次元: 365bet娱乐注册 时间戳: 2025-12-08 11:30:28 观察者: admin 访问量: 8443 能量值: 908
字符串转数字:三大库函数

一、字符串转为整数(int)

1.基础版:atoi

最简单的方法就是使用atoi函数,它是"ASCII to integer"的缩写,定义在stdlib.h中。

示例:

#include

#include

int main() {

const char *str1 = "9527";

const char *str2 = "-9527";

const char *str3 = "95-27";

printf("%d\n", atoi(str1));

printf("%d\n", atoi(str2));

printf("%d\n", atoi(str3));

return 0;

}

运行结果:

9527

-9527

95

可见:

①参数第一位可以有“+-”号(plus or minus sign)。

②遇到非法输入时,截取前面合法部分进行转换。

官方文档明确要求函数参数应为字符串,老金实际测试,用字符数组作参数也能输出正确结果,比如:

char str[] = {'9', '5', '2', '7'};

printf("%d\n", atoi(str));

不过,既然文档有明确要求,最好还是不要这样弄。

2.升级版:strtol

有一个更复杂的函数strtol(定义在stdlib.h中),可将字符串转换为长整数(long)。上面的示例代码用strol可写成:

#include

#include

int main() {

const char *str1 = "9527";

const char *str2 = "-9527";

const char *str3 = "95-27";

printf("%d\n", strtol(str1, NULL, 0));

printf("%d\n", strtol(str2, NULL, 0));

printf("%d\n", strtol(str3, NULL, 0));

return 0;

}

参数比之前多了,但功能也更强大了,主要体现在:

①可以将一串由空格隔开的字符串转换为多个整数。

②参数可以是不同的进制。二进制、八进制、十六进制都可以,最高可以干到三十六进制。

③具备错误处理功能。

函数原型:

long strtol( const char *restrict str, char **restrict str_end, int base );

参数说明:

① str:指向要转换的字符串的指针。

② str_end:指向字符指针的指什。这个玩艺比较复杂,它是指针的指针。它的值是函数给我们返回的,返回的值是str中一个字符的地址。是哪个字符的地址可有讲究了。如果你完成了一次转换,实际上可能只把str前面n个字符转换为数字(比如95-27,只转换了95),那这个已转换的字符里的最后一个字符的下一个字符的地址(也就是“95-27”中的“-”的地址),就是要赋给str_end的东东。说的更简明一点,就是让str_end指向尚未转换的字符部分的首地址,其目的无非是方便继续转换后面还没转换的字符。

如果将这个参数设为NULL(空指针),则忽略此参数。

③ base:指定要转换的字符是几进制的。注意是要转换的字符的进制,而不是转换后的整数的进制。比如指定8,那么字符串前面的0就会被识别为八进制的前缀,后面的字符也会按八进制转换为十进制的整数;如果指定为16,那么字符串前面的0x或0X就会被识别为十六进制的前缀,后面的字符也会按十六进制转换为十进制的整数。

如果base的值指定0呢?就会自动识别字符是什么进制,遇到前面有0就按八进制处理,遇到前面有0x或0X就按十六进制处理。

返回值说明:

①如果成功,返回str对应的整数值。

②如果转换后的值超出返回类型的范围,则会发生范围错误(将errno设置为ERANGE),并返回LONG_MAX、LONG_MIN、LLONG_MAX或LLONG_MIN。

③若无法进行转换,则返回 ​0​。

下面是官方文档的示例代码:

#include

#include

#include

#include

#include

int main(void)

{

// parsing with error handling

const char *p = "10 200000000000000000000000000000 30 -40 junk";

printf("Parsing '%s':\n", p);

for (;;)

{

// errno can be set to any non-zero value by a library function call

// regardless of whether there was an error, so it needs to be cleared

// in order to check the error set by strtol

errno = 0;

char *end;

const long i = strtol(p, &end, 10);

if (p == end)

break;

const bool range_error = errno == ERANGE;

printf("Extracted '%.*s', strtol returned %ld.", (int)(end-p), p, i);

p = end;

if (range_error)

printf("\n --> Range error occurred.");

putchar('\n');

}

printf("Unextracted leftover: '%s'\n\n", p);

// 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':

Extracted '10', strtol returned 10.

Extracted ' 200000000000000000000000000000', strtol returned 9223372036854775807.

--> Range error occurred.

Extracted ' 30', strtol returned 30.

Extracted ' -40', strtol returned -40.

Unextracted leftover: ' junk'

"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

代码说明:

1.整体说明

代码整体分两部分,“// parsing with error handling”下面的是带有错误处理功能的代码,“// parsing without error handling”下面的是不带错误处理功能的代码(咱们最开始给出的例子就是这种方式)。

2.将字符串转成多个整数的原理

这个原理其实很简单,就是通过循环不断地将指向字符串的指针p后移(对应示例代码p = end;),这样再使用strtol函数时就从新的位置转换字符串。

注意代表不同数字的字符串要用空格隔开,否则会被识别为一个数字。空格只起到分隔数字的作用,不会影响转换,因为转换时函数会自动舍弃数字前面的空格。

3.错误变量errno

errno是一个用于错误报告的全局变量,它是在头文件定义好的。咱们需要记住这个名字,就像关键字一样,直接拿来用就行。

当某些库函数执行失败时,它们会将errno设置为一个特定的非零值,以指示发生了哪种类型的错误。

在使用errno前,要注意先将其手动清0。原因在示例代码for语句的前三行注释中已明确给出:

只要有库函数调用就可能会将errno设置为任何非零值,甚至没有发生错误也可能将其置为非零值。也就是说,在调用strtol函数前,其它库函数可能已经将errno设为非0值了。所以为了确保捕捉的是strtol产生的错误,需要提前将errno设为0。

4.str的第2个参数:输出参数str_end

前面已经讲了str_end的作用,它是函数输出给我们的。

一般来讲,函数输出的都是返回值。如果还想多输出一些东西怎么办呢?一种方法就像前面讲的errno那,设置为全局变量。但全局变量设置太多了肯定不是件好事情,所以更通用的做法是通过参数返回给我们,str_end这个参数起的就是这个作用。

要想将值通过参数返回给我们,就需要做到两点:

①这个函数参数必须为指针。这很好理解,如果设置为变量,函数内的变量我们在函数外是看不可见的(想想那个经典的交换两个变量值的代码),所以必须设成指针。

②在函数外我们要定义一个变量,然后把变量的地址传给strtol的参数str_end。示例代码中“char *end;”就是在定义这样一个变量,只不过它定义的是一个指针类型的变量。这时赋给str_end自然也就是指针的地址,所以str_end就变成了指向指针的指针。

这种通过函数参数输出返回值的方式是一种经典的做法,咱们平时自己写函数时也可以尝试用一用。

5.转换停止条件

当str为空或遇到一个无效字符时,也就没得可转了,这时函数会自动把str的首地址赋给str_end。所以此时:p == end。

6.判断加赋值

const bool range_error = errno == ERANGE;

这行代码实际上是判断加赋值的一种简写,它实际上是这样的:

if(errno == ERANGE)

const bool range_error = errno;

errno与ERANGE相等时,表示转换过程中发生了范围错误(即转换后的值超出了long类型能表示的范围),此时将range_error设为true。

7.占位符*

printf("Extracted '%.*s', strtol returned %ld.", (int)(end-p), p, i);

这行代码有2个%号,但却输出了3个参数。这是因为*是一个占位符,表示输出字符的宽度(即输出几个字符),它是由(int)(end-p)给出的。

二、字符串转为浮点数(double)

可以用 strtod 函数(同样定义在 stdlib.h 中)来将字符串转换为双精度浮点数(double)。

示例:

#include

#include

int main() {

const char *str = "95.27";

printf("%f\n", strtod(str, NULL));

return 0;

}

strtod的使用和strtol差不多,老金就不再详述了,参见官方示例代码:

#include

#include

#include

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 nan(2) 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

相关维度

刘銮雄34年后公开处刑谈李嘉欣,眼睛里写满了讨厌:李嘉欣根本不是我的最爱,这就是个疯婆子

刘銮雄34年后公开处刑谈李嘉欣,眼睛里写满了讨厌:李嘉欣根本不是我的最爱,这就是个疯婆子

12.项目重构演进之路

12.项目重构演进之路

为什么要加入工会?因为好!处!太!多!了!

为什么要加入工会?因为好!处!太!多!了!

如何监控共享文档?5个简单步骤保护你的敏感信息

如何监控共享文档?5个简单步骤保护你的敏感信息