提问:将一个字符串转换成一个整型数有多少种方式?
在C语言的课堂上,可能会采取以下算法:
将字符串中的每一个字符提取出来,然后进行计算,然后将会得到你所想要的整型数。当然在这个函数中还要考虑字符串中的数字的进制问题,例如将字符串“0x1234abcd”转换成整型数则首先还要考虑它是十六进制的数。当然也还要考虑其他的问题,一共有一下几类:
1. 非法字符问题
2. 进制问题,用户可以指定任何进制
3. 整型数的越界问题
其他类型之间的转换需要注意的问题更多。
其实在C的标准库中已经给出了用于数据类型转换的函数,如下所示:
atof(将字符串转换成浮点型数)
atoi(将字符串转换成整型数)
atol(将字符串转换成长整型数)
gcvt(将浮点型数转换为字符串,取四舍五入)
strtod(将字符串转换成浮点数)
strtol(将字符串转换成长整型数)
strtoul(将字符串转换成无符号长整型数)
toascii(将整型数转换成合法的ASCII 码字符)
tolower(将大写字母转换成小写字母)
toupper(将小写字母转换成大写字母)
sscanf (将字符串转换成任何类型)
sprintf (将任意类型转换成字符串)
函数说明:
1. 字符串转换成整型或者浮点数atof、atoi、atol、strtod 、strtol、strtoul
这六个函数是将字符串转换成整型或者浮点数的函数。
前三个只是简单的转换,扫描参数中的字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,而再遇到非数字或字符串结束时('')才结束转换,并将结果返回。并不区分进制,也不返回错误。当遇到非法字符后函数返回因此无法判断是否含有非法字符,也无法判断是否越界。因此用户调用这三个函数之前需要自己去解决这些问题。
后三个函数会帮我们解决这些问题,以strtol为例:
long int strtol(const char *nptr,char **endptr,int base);
a. 在该函数中nptr为待转换的字符串,endptr保存字符串中的第一个非法字符,base则决定进制。如 base值为10则采用10进制,若base值为16则采用16进制等。当base值为0时则是采用10进制做转换,但遇到如'0x'前置字符则会使用 16进制做转换。
b. 一开始strtol()会扫描参数nptr字符串,跳过前面的空格字符,直到遇上数字或正负符号才开始做转换,再遇到非数字或字符串结束时('')结束转换,并将结果返回。
c. 如果字符串中有非法字符则endptr指向第一个非法字符,如果没有非法字符则endptr指向字符串的结尾’/0’。判断**endptr的值可以判断是否有非法字符。
d. 如果该字符串所表示的数据上越界则返回LONG_MAX,下越界则返回LONG_MIN,并返回这两个值。鉴于无论正常结束转换还是越界都有可能返回这两个临界值,当越界时该函数会设置errno为ERANGE。所以通过判断errno可以判断是否越界。(在调用前需要将errno设置为0)
e. 当字符串中没有任何字符时将会返回0,鉴于无论正常结束转换还是没有任何数字都有可能返回0,当返回0时该函数会设置errno为EINVAL。所以通过判断errno可以判断是否真的是0
strtod、strtoul和strtol的用法类似。
例子:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int arg_strtol(char *arg, long int *arg_long);
int main(int argc, char **argv)
{
char *arg = "0x1234";
long arg_long;
int ret = arg_strtol(argv[1], &arg_long);
if (ret == -1)
printf("%s bad arg/n", argv[1]);
else if (ret == -2)
printf("out of range/n");
else
printf("%d/n", arg_long);
return 1;
}
int arg_strtol(char *arg, long int *arg_long)
{
char *endarg = 0;// = malloc(sizeof(char) * (strlen(arg) + 1));
errno = 0;
*arg_long = strtol(arg, &endarg, 0);
if (*endarg != '/0')
return -1;
if (errno == 0)
return 0;
else
return -2;
}
2. 另一种将字符串转换成任意类型的函数:sscanf的妙用
sscanf() - 从一个字符串中读进与指定格式相符的数据.通过它可以得到任何你想要的数据类型。举一个最简单的例子
int main(int argc, char **argv)
{
long arg_long;
int ret = sscanf(argv[1], "%d", &arg_long);
printf("%d/n", arg_long);
return 1;
}
当运行时输入1234时,argv[1]即为字符串”1234”。Sscanf将从这个字符串中读取一个格式为%d的数据,保存在arg_long中,即arg_long=1234;但是当运行输入123456789时明显越界,此时arg_long的值未定义即随机。
因此sscanf可以转换字符串为任意格式的数据,但是却不保证判断越界、以及进制的问题。
3. 其他类型的数据转换成字符串----gcvt、ecvt,fcvt
将其他类型的数据转换成字符串相对而言比字符串转换成其他类型数据简单,因为不需要考虑到进制、越界等问题。用法如下
char *gcvt(double number,size_t ndigits,char *buf);
函数说明:gcvt()用来将参数number转换成ASCII码字符串,参数ndigits表示显示的位数。gcvt()与ecvt()和fcvt()不同的地方在于,gcvt()所转换后的字符串包含小数点或正负符号。若转换成功,转换后的字符串会放在参数buf指针所指的空间。
返回值 :返回一字符串指针,此地址即为buf指针。
4. 另一种将其他类型的数据转换成字符串的方法----sprintf函数的妙用
sprintf 是个变参函数,定义如下:
int sprintf( char *buffer, const char *format [, argument] ... );
除了前两个参数类型固定外,后面可以接任意多个参数。而它的精华,显然就在第二个参数:格式化字符串上。
使用方法:
//把整数123 打印成一个字符串保存在s 中。
sprintf(s, "%d", 123); //产生"123"。即将整数123转换成了”123”
可以指定宽度,不足的左边补空格:
sprintf(s, "%8d%8d", 123, 4567); //产生:" 123 4567"
当然也可以左对齐:
sprintf(s, "%-8d%8d", 123, 4567); //产生:"123 4567"
它的所有的格式和printf相同。