若要将字串转换为数字,则可以使用atof
、atoi
、atol
、atoll
等函式,这些函式都包括在stdlib.h 中:
double atof( const char* str );
int atoi( const char *str );
long atol( const char *str );
long long atoll( const char *str );
atof
、atoi
、atol
、atoll
等函式会搜寻字串中可以转换的部份,直到遇到无法转换的字元,字串开头可以使用正负号,例如"+100"
或"-100"
,atof
可以接受科学记号,例如"12.3e-5"
或"123E+4"
,这几个函式若没有可转换的字元则传回0,若是转换结果超出了传回型态的范围,传回值没有定义,也就是难以检查错误。
C99 有一系列转换字串的函式,使用起来比较麻烦一些:
long strtol( const char *restrict str, char **restrict str_end, int base );
long long strtoll( const char *restrict str, char **restrict 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 );
float strtof( const char *restrict str, char **restrict str_end );
double strtod( const char *restrict str, char **restrict str_end );
long double strtold( const char *restrict str, char **restrict str_end );
这几个函式的第一个参数都接受来源字串;第二个参数在函式执行过后,会用来储存字串中第一个无法剖析为数字的字元位址,如果设定为NULL
,会忽略这个参数;第三个参数用来指定基底,如果设定为0,从字串中自动侦测基底;函式若没有可转换的字串,会传回0。
因此最简单的转换情况就是当成atof
的替代品:
#include <stdio.h>
#include <stdlib.h>
int 主函数(无效){
printf("\"1010\"\t二进位:\t%ld\n", strtol("1010", NULL, 2));
printf("\"12\"\t八进位:\t%ld\n", strtol("12", NULL, 8));
printf("\"A\"\t十六进位:\t%ld\n", strtol("A", NULL, 16));
printf("\"012\"\t自动读取:\t%ld\n", strtol("012", NULL, 0));
printf("\"0xA\"\t自动定位:\t%ld\n", strtol("0xA", NULL, 0));
printf("\"junk\"\t自动读取:\t%ld\n", strtol("junk", NULL, 0));
返回0;
}
执行结果如下:
"1010" 二进位: 10
"12" 八进位: 10
"A" 十六进位: 10
"012" 自动基底: 10
"0xA" 自动基底: 10
"junk" 自动基底: 0
若是转换结果超出了传回型态的范围,会将定义在errno.h 的errno
设为ERANGE
,并传回各自传回型态的最大可容许数值(最大值或最小值),因此,可藉由检查errno
来看看转换是否有误:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main(void) {
long i = strtol("99999999999999999999999999999999999999999999999999", NULL, 10);
if(errno == ERANGE) {
printf("超出转换函式范围");
errno = 0;
}
else {
printf("%d", i);
}
return 0;
}
由于第二个参数在函式执行过后,会用来指向字串中第一个无法剖析为数字的字元,因此若想连续剖析一组数字,数字以某一标点符号区隔,可以如下,这需要认识更多指标的观念,你可以在后续学习过指标之后,再回头看看这个范例:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main(void) {
const char *p = "10,200,3000,-400000";
char *end;
for (long i = strtol(p, &end, 10); p != end; i = strtol(p, &end, 10)) {
printf("\"%.*s\":", (int)(end - p), p);
p = end + 1; // 新的字串起点
if (errno == ERANGE){
printf("转换超出范围");
errno = 0;
}
printf("%ld\n", i);
}
}
由于第二个参数在函式执行过后,会用来指向字串中第一个无法剖析为数字的字元,因此若想连续剖析一组数字,数字以某一标点符号区隔,可以如下,这需要认识更多指标的观念,你可以在后续学习过指标之后,再回头看看这个范例:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main(void) {
const char *p = "10,200,3000,-400000";
char *end;
for (long i = strtol(p, &end, 10); p != end; i = strtol(p, &end, 10)) {
printf("\"%.*s\":", (int)(end - p), p);
p = end + 1; // 新的字串起点
if (errno == ERANGE){
printf("转换超出范围");
errno = 0;
}
printf("%ld\n", i);
}
}
执行结果如下:
"10":10
"200":200
"3000":3000
"-400000":-400000
若要测试字元为数字、字母、大写、小写等等
isalnum(int c):是否为字母或数字
isalpha(int c):是否为字母
iscntrl(int c):是否为控制字元
isdigit(int c):是否为数字
islower(int c):是否为小写字母
isprint(int c):是否为列印字元
ispunct(int c):是否为标点符号
isspace(int c):是否为空白
isupper(int c):是否为大写字母
isxdigit(int c):是否为16进位数字
...
这些函式事实上是巨集,可以查看ctype.h 得知更多的isxxxx
函式,ctype.h 中也包括了像是可以进行字母大小写转换的tolower
、toupper
等函式。