最近開始自學C語言,在看K&R的《C程序設計語言》。練習2-3要求寫一個函數,將輸入的十六進制數字字符串轉換成與之等價的整數值,配套答案沒有擴展程序的通用性,所以我就稍微改造改造。
配套的答案是這樣的(自己添加了注釋):
1 #define YES 1 2 #define NO 0 3 4 /* htoi:將十六進制數字字符串轉換成十進制數 5 * 如果發現'0x'或'0X'則跳過並設置十六進制數的起點 6 * 檢查后續字符是否是0-9,a-f或是A-F 7 * 如果是則將其轉換為整形 8 * 如果不是則停止檢查,數字結束 9 * 通過公式計算相應的十進制值並返回 10 */ 11 int htoi(char s[]) 12 { 13 int hexdigit,i,inhex,n; 14 15 if (s[i] == '0') { 16 ++i; 17 if (s[i] == 'x' || s[i] == 'X'){ 18 ++i; 19 } 20 } 21 n = 0; /* 初始化返回變量 */ 22 inhex = YES; /* 假設在合法字符中 */ 23 for ( ; inhex == YES; ++i) { 24 if (s[i] >= '0' && s[i] <= '9') 25 hexdigit = s[i] - '0'; 26 else if (s[i] >= 'a' && s[i] <= 'f') 27 hexdigit = s[i] - 'a' + 10; 28 else if (s[i] >= 'A' && s[i] <= 'F') 29 hexdigit = s[i] - 'A' + 10; 30 else 31 inhex = NO; 32 if (inhex == YES) 33 n = 16 * n + hexdigit; 34 } 35 return n; 36 }
該函數需要導入一個字符數組,我在 main() 函數中寫了獲取數組的代碼將獲取字符數組的代碼寫成(假設最多獲取10個長度的字符數組,因為數組以 '\0' 結尾,因此總共最多獲取9個有效字符):
1 int c,i; 2 char input[10]; 3 4 for ( i = 0; i < 10-1 && ((c = getchar()) != EOF); ++i) 5 input[i] = c; 6 input[i] = '\0';
將得到的字符數組傳入 htoi() 函數中即可計算出轉換后的值。
但是這樣有個缺陷:字符數組開頭必須是 “0x” 或 “0X” 或 數字0-9 或 字母a-f 或 A-F,否則 htoi() 函數只返回 0。這樣就降低了程序的通用性,那么如何才能當字符數組前頭包含無用字符時,只有檢測到 “0x” 或 “0X” 時才繼續檢測后續字符,並計算返回正確的結果?
我的做法是在 htoi() 函數中檢測是否為 “0x” 或 “0X” 的代碼上添加循環:
1 int htoi(char s[]) 2 { 3 int hexdigit,i,inhex,n; 4 5 i=0; 6 while (s[i] != '\0'){ 7 if (s[i] == '0') { 8 ++i; 9 if (s[i] == 'x' || s[i] == 'X'){ 10 ++i; 11 break; /* 如果是“0x”或“0X”就停止循環 */ 12 } 13 } 14 else 15 ++i; /* 如果不符合則循環到底,最后s[i]='\0' */ 16 } 17 n = 0; 18 inhex = YES; 19 for ( ; inhex == YES; ++i) { 20 ... ...
運行結果如下:

下面把完整代碼貼出來,若有幸讓高手看見還請指點指點:
1 #include <stdio.h> 2 3 #define YES 1 4 #define NO 0 5 6 int htoi(char s[]); 7 8 int main(void) 9 { 10 int c,i; 11 char input[10]; 12 13 for ( i = 0; i < 10-1 && ((c = getchar()) != EOF); ++i) 14 input[i] = c; 15 input[i] = '\0'; 16 printf("輸入的16進制數轉換十進制數:%d\n",htoi(input)); 17 return 0; 18 } 19 20 int htoi(char s[]) 21 { 22 int hexdigit,i,inhex,n; 23 24 i=0; 25 while (s[i] != '\0'){ 26 if (s[i] == '0') { 27 ++i; 28 if (s[i] == 'x' || s[i] == 'X'){ 29 ++i; 30 break; 31 } 32 } 33 else 34 ++i; 35 } 36 n = 0; 37 inhex = YES; 38 for ( ; inhex == YES; ++i) { 39 if (s[i] >= '0' && s[i] <= '9') 40 hexdigit = s[i] - '0'; 41 else if (s[i] >= 'a' && s[i] <= 'f') 42 hexdigit = s[i] - 'a' + 10; 43 else if (s[i] >= 'A' && s[i] <= 'F') 44 hexdigit = s[i] - 'A' + 10; 45 else 46 inhex = NO; 47 if (inhex == YES) 48 n = 16 * n + hexdigit; 49 } 50 return n; 51 }
2015.06.16更新
根據 @garbageMan 的建議:
1.將獲取字符數組的代碼封裝為函數 getstring()
2.修改 htoi() 函數的判斷語句,當字符數組不以 “0x” 或 “0X” 開頭時也能進行計算
3.簡化 htoi() 函數結束循環的標記,去除 inhex 變量
另:
1.將能夠獲取的字符數組的最大長度定義為常量 MAXC
2.將 htoi() 函數的返回值修改為 double 以容納更大的結果
完整程序代碼如下:
1 #include <stdio.h> 2 3 #define MAXC 100 /* 字符數組的最大長度 */ 4 5 double htoi(char s[]); 6 void getstring(char s[]); 7 8 int main(void) 9 { 10 char input[MAXC]; 11 12 getstring(input); 13 printf("輸入的16進制數轉換十進制數:%.0f\n",htoi(input)); 14 return 0; 15 } 16 17 double htoi(char s[]) 18 { 19 int hexdigit,i; 20 double n; 21 22 i=0; 23 while (s[i] != '\0'){ 24 if (s[i] == '0') { 25 ++i; 26 if (s[i] == 'x' || s[i] == 'X'){ 27 ++i; 28 break; 29 } 30 else 31 break; /* 0之后不是x或X的話則從0開始計算 */ 32 } 33 /* 是以下符合十六進制的字符則從其開始計算 */ 34 else if((s[i] >= '0' && s[i] <= '9') 35 || (s[i] >= 'a' && s[i] <= 'f') 36 || (s[i] >= 'A' && s[i] <= 'F')) 37 break; 38 else /* 非十六進制字符,跳過 */ 39 i++; 40 } 41 n = 0.0; 42 for ( ; ; ++i) { 43 if (s[i] >= '0' && s[i] <= '9') 44 hexdigit = s[i] - '0'; 45 else if (s[i] >= 'a' && s[i] <= 'f') 46 hexdigit = s[i] - 'a' + 10; 47 else if (s[i] >= 'A' && s[i] <= 'F') 48 hexdigit = s[i] - 'A' + 10; 49 else 50 break; 51 n = 16 * n + hexdigit; 52 } 53 return n; 54 } 55 56 /* 獲取字符數組 */ 57 void getstring(char s[]) 58 { 59 int c,i; 60 61 for ( i = 0; i < MAXC-1 && ((c = getchar()) != EOF); ++i) 62 s[i] = c; 63 s[i] = '\0'; 64 }
