標籤:pre span 狀態 lag 字串轉換 ace std turn 類比
atoi(表示 ascii to integer)是把字串轉換成整型數的一個函數.
atoi()函數會掃描參數 nptr字串,跳過前面的空白字元(例如空格,tab縮排等,可以通過isspace( )函數來檢測),直到遇上數字或正負符號才開始做轉換,而再遇到非數字或字串結束時(‘\0‘)才結束轉換,並將結果返回。如果 nptr不能轉換成 int 或者 nptr為空白字串,那麼將返回0
我們在類比實現atoi函數時,要注意以下幾點:
1.字串之前的空白問題
2.加號或減號
3.字串為空白時
4.被轉換的數字過於大(正溢出、負溢出)
5.其他,無法轉換的情況(全是字母....之類的)
我們瞭解atoi函數功能和一些注意事項之後,開始類比實現它,代碼如下:
#include<stdio.h>#include<assert.h>#include<stdlib.h>enum{vaild = 0,invaild = 1};int flag = vaild;int my_atoi(const char *str){long long ret = 0;int symbol = 1;//斷言str!=NULLassert(str);//判斷Null 字元if( ‘\0‘ == *str ){flag = invaild;return 0;}//去掉空格、定位字元while(isspace(*str)){str++;}//符號位判斷if(‘-‘==*str){symbol = -1;str++;}else if(‘+‘==*str){str++;}else if(((*str<=‘0‘)&&(*str>=‘9‘))){flag = invaild;return 0;}//其他異常情況處理完畢,開始轉換while((*str!=‘\0‘)&&(*str>=‘0‘)&&(*str<=‘9‘)){ret = (ret*10 + *str-‘0‘);str++;}//帶上符號位ret *= symbol;//檢測溢出//int 0111 1111 1111 1111 1111 1111 1111 1111 正溢出// 7 f f f f f f f// 1000 0000 0000 0000 0000 0000 0000 0000 負溢出// 8 0 0 0 0 0 0 0if(((ret>0x7fffffff)&&(1==symbol)) ||(ret<(signed int)0x80000000)&&(-1==symbol)){flag = invaild;return 0;}//ret合法flag = vaild;return ret;}//列印atoi函數狀態+\nvoid PrintState(){if(flag){printf("異常\n");}else{printf("正常\n");}}//測試函數void FunTest(){printf("value=%d,state=",my_atoi("123456789"));PrintState();//正常printf("value=%d,state=",my_atoi("-123456789"));PrintState();//正常printf("value=%d,state=",my_atoi("-123456789sassa"));PrintState();//正常,遇到字母終止printf("value=%d,state=",my_atoi(" -123456789sassa"));PrintState();//正常,前面帶空格printf("value=%d,state=",my_atoi(""));//////////////異常情況/////////printf("\n\n");PrintState();//異常:Null 字元串printf("value=%d,state=",my_atoi("123456789123456789"),flag);PrintState();//異常:正溢出printf("value=%d,state=",my_atoi("-123456789123456789"),flag);PrintState();//異常:負溢出printf("value=%d,state=",my_atoi("dasdsa"),flag);PrintState();//異常:無法轉換}int main(){FunTest();return 0;}
彩蛋:在寫測試函數時,有一件事,始終不得其解,一開始我將測試代碼寫成了這樣:
void FunTest(){printf("value=%d,state=%d\n",my_atoi("123456789"),flag);//正常printf("value=%d,state=%d\n",my_atoi("-123456789"),flag);//正常printf("value=%d,state=%d\n",my_atoi("-123456789sassa"),flag);//正常,遇到字母終止printf("value=%d,state=%d\n",my_atoi(" -123456789sassa"),flag);//正常,前面帶空格printf("\n\n\n");printf("value=%d,state=%d\n",my_atoi(""),flag);//異常:Null 字元串printf("value=%d,state=%d\n",my_atoi("123456789123456789"),flag);//異常:正溢出printf("value=%d,state=%d\n",my_atoi("-123456789123456789"),flag);//異常:負溢出printf("value=%d,state=%d\n",my_atoi("dasdsa"),flag);//異常:無法轉換}
測試時,發現一件詭異的事情!!!!!!!
結果輸出是這樣:
value=123456789,state=0value=-123456789,state=0value=-123456789,state=0value=-123456789,state=0value=0,state=0 //臥槽!!!為什麼是0?value=0,state=1value=0,state=1value=0,state=1
我還特意跟進函數體內看,發現全域變數flag確實被改為了1,但為什麼輸出的是0呢???
正當我百思不得其解時,突然想到printf函數的呼叫慣例是_cdel!!!!
因此,_cdel呼叫慣例,是將參數由右向左壓棧,因此它先將flag壓棧,然後再執行my_atoi函數,在my_atoi函數體內修改了全域變數flag.....
所以,最終輸出了0!
因此,才有了最終代碼!
【C語言】類比實現atoi函數