若要將字串轉換為數字,則可以使用 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 main(void) {
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));
return 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);
}
}
執行結果如下:
"10":10
"200":200
"3000":3000
"-400000":-400000
若要測試字元為數字、字母、大寫、小寫等等,可以使用 ctype.h 中的 isxxxx()
函式,例如:
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
等函式。