C語(yǔ)言實(shí)現(xiàn)將字符串轉(zhuǎn)換成整數(shù)
這是一個(gè)很有意思的問(wèn)題。請(qǐng)不要把這個(gè)問(wèn)題想的太簡(jiǎn)單了,考慮問(wèn)題時(shí)應(yīng)該盡可能的全面一些。請(qǐng)先思考并且實(shí)現(xiàn)這個(gè)函數(shù),再來(lái)看講解。
分析一下:函數(shù)名是StrToInt,那么可以這么調(diào)用:
int ret = StrToInt("1234"); printf("%d\n", ret);
如果你寫(xiě)的程序能夠正確輸出1234,然后就覺(jué)得這道題就這樣了,那么考慮的就不夠全面。有沒(méi)有一種可能:
1.傳參時(shí)傳了NULL指針。
2.傳入空字符串。
3.字符串前面有空格,如:" 1234"。
4.有正負(fù)號(hào),如:“-1234”。
5.有非法字符,如:“1234abcd”。
6.數(shù)字太大了,超出了int的存儲(chǔ)范圍,如:“1111111111111111111111111111111111111”。
下面我們一個(gè)一個(gè)解決。
準(zhǔn)備工作
由于有可能出現(xiàn)非法字符,或者空字符串等,會(huì)有一些情況的轉(zhuǎn)換是非法的。所以,定義一個(gè)全局性質(zhì)的枚舉類型來(lái)檢驗(yàn)轉(zhuǎn)換是否合法:
enum State { VALID, INVALID }s = INVALID;
默認(rèn)的情況是非法的,只有轉(zhuǎn)換成功才會(huì)把s的值置為VALID。
先把函數(shù)的框架撘出來(lái):
int StrToInt(const char* str) { ???????}
接下來(lái)開(kāi)始解決以下問(wèn)題:
1.NULL指針
NULL指針是不能解引用的!所以最好斷言一下。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); return ret; }
2.空字符串
如果一上來(lái)就遇到了’\0’,那么就是空字符串。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } }
3.空格
接下來(lái),有可能會(huì)遇到空格,使用isspace函數(shù)來(lái)判斷,把空格跳過(guò)去。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } }
4.正負(fù)號(hào)
接下來(lái)有可能遇到正負(fù)號(hào),用一個(gè)flag來(lái)保存。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } // 正負(fù)號(hào) int flag = 1; if (*str == '+') { flag = 1; ++str; } else if (*str == '-') { flag = -1; ++str; } }
5.非法字符
下面開(kāi)始處理數(shù)字。但是,有可能會(huì)遇到非法字符,所以要先判斷一下。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } // 正負(fù)號(hào) int flag = 1; if (*str == '+') { flag = 1; ++str; } else if (*str == '-') { flag = -1; ++str; } // 處理數(shù)字 while (*str) { if (isdigit(*str)) { } else { return ret; } } }
如何處理合法的數(shù)字呢?假設(shè)是1234,我們可以先定義一個(gè)ret,初始化成0。先拿到1,0*10+1,就得到了1。接著拿到2,1*10+2,就得到了12。再拿到3,12*10+3,就得到了123。最后拿到4,123*10+4,就得到了1234。以此類推。
每次ret = ret*10 + 拿到的數(shù)字就行了。但是“拿到的數(shù)字”是什么呢?就是*str-'0'。想象一下,'1'-'0'就是數(shù)字1,'6'-'0'就是數(shù)字6。兩個(gè)字符相減就是對(duì)應(yīng)的ASCII碼相減。不過(guò),拿到的數(shù)字得乘上flag再加上去,因?yàn)橛锌赡苁秦?fù)數(shù)。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } // 正負(fù)號(hào) int flag = 1; if (*str == '+') { flag = 1; ++str; } else if (*str == '-') { flag = -1; ++str; } // 處理數(shù)字 int ret = 0; while (*str) { if (isdigit(*str)) { ret = ret * 10 + flag * (*str - '0'); ++str; } else { return ret; } } s = VALID; return (int)ret; }
6.越界
這就完了嗎?還有一種情況,假設(shè)傳入的數(shù)字過(guò)大或過(guò)小,導(dǎo)致超出了int的存儲(chǔ)范圍,此時(shí)的轉(zhuǎn)換也是非法的。判斷方法,就是用更大的類型,如long long來(lái)存儲(chǔ),如果超出了int的存儲(chǔ)范圍(ret>INT_MAX || ret<INT_MIN),但是不會(huì)超出long long的存儲(chǔ)范圍,就能夠識(shí)別什么時(shí)候越界了。
int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } // 正負(fù)號(hào) int flag = 1; if (*str == '+') { flag = 1; ++str; } else if (*str == '-') { flag = -1; ++str; } // 處理數(shù)字 long long ret = 0; while (*str) { if (isdigit(*str)) { ret = ret * 10 + flag * (*str - '0'); // 判斷有沒(méi)有超過(guò)int的存儲(chǔ)范圍 if (ret > INT_MAX || ret < INT_MIN) { return (int)ret; } else { ++str; } } else { return (int)ret; } } // end of while s = VALID; return (int)ret; }
最后如果轉(zhuǎn)換成功,就把s置成VALID,再返回ret即可。注意ret是long long類型,但是返回類型是int,所以需要強(qiáng)制類型轉(zhuǎn)換。
測(cè)試
完整的測(cè)試代碼如下:
#include <stdio.h> #include <assert.h> #include <ctype.h> #include <limits.h> enum State { VALID, INVALID }s = INVALID; int StrToInt(const char* str) { // 如果str是NULL,不能對(duì)其解引用 assert(str); // 空字符串 if (*str == '\0') { return 0; } // 空格 while (isspace(*str)) { ++str; } // 正負(fù)號(hào) int flag = 1; if (*str == '+') { flag = 1; ++str; } else if (*str == '-') { flag = -1; ++str; } // 處理數(shù)字 long long ret = 0; while (*str) { if (isdigit(*str)) { ret = ret * 10 + flag * (*str - '0'); // 判斷有沒(méi)有超過(guò)int的存儲(chǔ)范圍 if (ret > INT_MAX || ret < INT_MIN) { return (int)ret; } else { ++str; } } else { return (int)ret; } } // end of while s = VALID; return (int)ret; } int main() { int ret = StrToInt(" -1234"); if (s == VALID) { printf("轉(zhuǎn)換成功:%d\n", ret); } else { printf("轉(zhuǎn)換失?。?d\n", ret); } return 0; }
輸出結(jié)果:
總結(jié)
1.每次把舊的數(shù)乘10再加上一個(gè)數(shù)字,就能在這個(gè)數(shù)后面續(xù)上這個(gè)數(shù)字。如123*10+4=1234,就在123后面續(xù)上了4。
2.字符相減,本質(zhì)是ASCII碼相減。
3.考慮問(wèn)題時(shí),應(yīng)該全面考慮,不要漏掉一些情況。
到此這篇關(guān)于C語(yǔ)言實(shí)現(xiàn)將字符串轉(zhuǎn)換成整數(shù)的文章就介紹到這了,更多相關(guān)C語(yǔ)言字符串轉(zhuǎn)整數(shù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
OpenCV實(shí)現(xiàn)二值圖像的邊緣光滑處理
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)二值圖像的邊緣光滑處理,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-07-07C++二維數(shù)組中數(shù)組元素存儲(chǔ)地址的計(jì)算疑問(wèn)講解
今天小編就為大家分享一篇關(guān)于C++二維數(shù)組中數(shù)組元素存儲(chǔ)地址的計(jì)算疑問(wèn)講解,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧2019-02-02C語(yǔ)言中QString與QByteArray互相轉(zhuǎn)換的方法
本文主要介紹了C語(yǔ)言中QString與QByteArray互相轉(zhuǎn)換的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-05-05詳解c++優(yōu)先隊(duì)列priority_queue的用法
本文詳細(xì)講解了c++優(yōu)先隊(duì)列priority_queue的用法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-12-12C語(yǔ)言中關(guān)于動(dòng)態(tài)內(nèi)存分配的詳解
動(dòng)態(tài)內(nèi)存是指在堆上分配的內(nèi)存,而靜態(tài)內(nèi)存是指在棧上分配的內(nèi)存。棧上分配的內(nèi)存是由系統(tǒng)分配和釋放的,空間有限,在復(fù)合語(yǔ)句或函數(shù)運(yùn)行結(jié)束后就會(huì)被系統(tǒng)自動(dòng)釋放而堆上分配的內(nèi)存則不會(huì)有這個(gè)問(wèn)題。2021-09-09C語(yǔ)言實(shí)現(xiàn)在windows服務(wù)中新建進(jìn)程的方法
這篇文章主要介紹了C語(yǔ)言實(shí)現(xiàn)在windows服務(wù)中新建進(jìn)程的方法,涉及C語(yǔ)言進(jìn)程操作的相關(guān)技巧,需要的朋友可以參考下2015-06-06C++非遞歸隊(duì)列實(shí)現(xiàn)二叉樹(shù)的廣度優(yōu)先遍歷
這篇文章主要介紹了C++非遞歸隊(duì)列實(shí)現(xiàn)二叉樹(shù)的廣度優(yōu)先遍歷,實(shí)例分析了遍歷二叉樹(shù)相關(guān)算法技巧,并附帶了兩個(gè)相關(guān)算法實(shí)例,需要的朋友可以參考下2015-07-07