從鍵盤讀入實數,鍵盤讀入實數
編製一個從鍵盤讀入實數的函數readreal(double *rp)。函數將讀入的實數字元列換成實數後,利用指標參數rp,將實數存於指標所指向的變數*rp。
解析:
函數在返回之前,將最後讀入的結束實數字元列的字元返還給系統,以便隨後讀字元時能再次讀入該字元。函數若能正常讀入實數,函數返回整數1,如果函數在讀入過程中,未遇到數字元之前,遇到不能構成數位情況,函數返回-1,表示為讀到實數。
在輸入實數時,在實數之前可以有一個數不定的空白類字元,組成實數的字元列有數的符號字元,實數的整數部分,小數點和實數的小數部分,其中,某些部分可以預設。設實數字元列有以下幾種可能形式:
數符 整數部分
數符 整數部分
數符 整數部分.小數部分
數符 .小數部分
其中數符或為空白,或為’+’,或為’-‘,分別代表不帶符號,帶正號,帶負號。整數部分和小數部分至少要有一個數字元組成。
上述實數形式說明,在實數轉換過程中,同一字元在不同情況下會有不同的意義。為標記當前實數轉換的不同情況,程式引入狀態變數,有狀態變數的不同值代表當前實數轉換過程中的不同情況。
共有以下多種不同的情況:正準備開始轉換,轉換了數的符號字元,正在轉換實數的整數部分,正在轉換實數的小數部分,發現輸入錯誤,轉換正常結束。設狀態變數為0表示正準備開始轉換,還未遇到任何與實數有關的字元;1表示已經遇到數的符號字元;2表示正在轉換實數的整數部分,3表示在未遇到數字字元之前先遇到小數點;4表示在轉換整數部分之後遇到小數點;5表示轉換髮現錯誤,6表示轉換正常結束。
讀函數另外有兩張表,一張是轉換函式表,一張是狀態表。函數反覆讀入字元,將字元分類,根據目前狀態和當前字元類調用對應轉換函式。
下面是程式的實現部分:
#include <stdio.h>#define ERR 5#define OK 6int status;double result,sig,scale;/* * 處理數的符號函數 */int sign(int c){ if(c = '-') /* 若為負號,取負 */ sig=-sig;}/** * @brief integer 轉換整數部分 * @param c 要被轉換的整數位 * @return 返回成功與否 */int integer(int c){ result = result * 10.0 + c - '0';}/** * @brief decimal 轉換小數部分 * @param c 要被轉換的小數位 * @return 返回成功與否 */int decimal(int c){ result += (c -'0') * scale; scale /= 10;}/* 狀態表 *//* * 0 - 正準備開始轉換,還未遇到任何與實數有關的字元 * 1 - 已遇數的符號字元 * 2 - 正在轉換實數的整數部分 * 3 - 在未遇數字字元之前先遇到小數點 * 4 - 在轉換整數部分之後先遇到小數點 * 5 - 表示轉換髮現錯誤 * 6 - 轉換正常結束 */int statbl[][4]={ {1,2,3,ERR}, {ERR,2,3,ERR}, {OK,2,4,OK}, {ERR,4,ERR,ERR}, {OK,4,OK,OK}};/* 轉換函式表 */int (*funtbl[][4])() = { {sign,integer,NULL,NULL}, {NULL,integer,NULL,NULL}, {NULL,integer,NULL,NULL}, {NULL,decimal,NULL,NULL}, {NULL,decimal,NULL,NULL}};/** * @brief readreal 用於對輸入的字串轉換成浮點數 * @param dp 轉換後的浮點數 * @return 返回是否轉換成功 */int readreal(double *dp){ int c,ckind; sig = 1.0; result = 0.0; scale = 0.1; while((c=getchar()) == ' ' || c == '\n' || c == '\t'); //跳過這些字元 status = 0; //重設初始狀態 for(;;){ /* 分類當前字元 */ if(c == '+' || c== '-') ckind = 0; /* 數的符號字元 */ else if(c >= '0' && c <= '9') ckind = 1; /* 數字元 */ else if(c == '.') ckind = 2; /* 小數點 */ else ckind = 3; /* 其他字元 */ if(funtbl[status][ckind]){ (*funtbl[status][ckind])(c); /* 執行相應的轉換函式 */ } status = statbl[status][ckind]; /* 設定新的狀態 */ if(status == ERR || status == OK) break; /*結束,出錯或成功 */ c=getchar(); } ungetc(c,stdin); /* 歸還數的結束符*/ if(status == OK){ *dp = result * sig; return 1; } return -1;}int main(){ double x; printf("Please input real numbers:\n"); while(readreal(&x) == 1) printf("The real number is : %f\n",x); return 0;}
下面是我的程式的運行結果:
這個程式剛開始的時候,我的思路是,從第1個元素開始遍曆,遍曆過程中,在遇到”.”之前,類似於上面integer()函數的實現方式,當遇到點之後,就類似於上面decimal()函數的實現方式,但是看了作者的源碼之後,發現需要學習一個做著的思路,思路敏捷,代碼整潔,需要好好學習。