這是一個(gè)很有意思的問題。請不要把這個(gè)問題想的太簡單了,考慮問題時(shí)應(yīng)該盡可能的全面一些。請先思考并且實(shí)現(xiàn)這個(gè)函數(shù),再來看講解。
分析一下:函數(shù)名是StrToInt,那么可以這么調(diào)用:
int ret = StrToInt("1234");
printf("%d\n", ret);
如果你寫的程序能夠正確輸出1234,然后就覺得這道題就這樣了,那么考慮的就不夠全面。有沒有一種可能:
- 傳參時(shí)傳了NULL指針。
- 傳入空字符串。
- 字符串前面有空格,如:" 1234"。
- 有正負(fù)號(hào),如:“-1234”。
- 有非法字符,如:“1234abcd”。
- 數(shù)字太大了,超出了int的存儲(chǔ)范圍,如:“1111111111111111111111111111111111111”。
下面我們一個(gè)一個(gè)解決。
準(zhǔn)備工作
由于有可能出現(xiàn)非法字符,或者空字符串等,會(huì)有一些情況的轉(zhuǎn)換是非法的。所以,定義一個(gè)全局性質(zhì)的枚舉類型來檢驗(yàn)轉(zhuǎn)換是否合法:
enum State
{
VALID,
INVALID
}s = INVALID;
默認(rèn)的情況是非法的,只有轉(zhuǎn)換成功才會(huì)把s的值置為VALID。
先把函數(shù)的框架撘出來:
int StrToInt(const char* str)
{
}
接下來開始解決以下問題:
1.NULL指針
NULL指針是不能解引用的!所以最好斷言一下。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
return ret;
}
2.空字符串
如果一上來就遇到了’\0’,那么就是空字符串。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
if (*str == '\0')
{
return 0;
}
}
3.空格
接下來,有可能會(huì)遇到空格,使用isspace函數(shù)來判斷,把空格跳過去。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
if (*str == '\0')
{
return 0;
}
// 空格
while (isspace(*str))
{
++str;
}
}
4.正負(fù)號(hào)
接下來有可能遇到正負(fù)號(hào),用一個(gè)flag來保存。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
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.非法字符
下面開始處理數(shù)字。但是,有可能會(huì)遇到非法字符,所以要先判斷一下。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
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 != '\0')
{
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è)字符相減就是對應(yīng)的ASCII碼相減。不過,拿到的數(shù)字得乘上flag再加上去,因?yàn)橛锌赡苁秦?fù)數(shù)。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
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 != '\0')
{
if (isdigit(*str))
{
ret = ret * 10 + flag * (*str - '0');
++str;
}
else
{
return ret;
}
}
s = VALID;
return ret;
}
6.越界
這就完了嗎?還有一種情況,假設(shè)傳入的數(shù)字過大或過小,導(dǎo)致超出了int的存儲(chǔ)范圍,此時(shí)的轉(zhuǎn)換也是非法的。判斷方法,就是用更大的類型,如long long來存儲(chǔ),如果超出了int的存儲(chǔ)范圍(ret>INT_MAX || ret<INT_MIN
),但是不會(huì)超出long long的存儲(chǔ)范圍,就能夠識(shí)別什么時(shí)候越界了。
int StrToInt(const char* str)
{
// 如果str是NULL,不能對其解引用
assert(str != NULL);
// 空字符串
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 != '\0')
{
if (isdigit(*str))
{
ret = ret * 10 + flag * (*str - '0');
// 判斷有沒有超過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)換。
測試
完整的測試代碼如下:
#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,不能對其解引用
assert(str != NULL);
// 空字符串
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 != '\0')
{
if (isdigit(*str))
{
ret = ret * 10 + flag * (*str - '0');
// 判斷有沒有超過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é)果:文章來源:http://www.zghlxwxcb.cn/news/detail-408664.html
總結(jié)
- 每次把舊的數(shù)乘10再加上一個(gè)數(shù)字,就能在這個(gè)數(shù)后面續(xù)上這個(gè)數(shù)字。如
123*10+4=1234
,就在123后面續(xù)上了4。 - 字符相減,本質(zhì)是ASCII碼相減。
- 考慮問題時(shí),應(yīng)該全面考慮,不要漏掉一些情況。
感謝大家的閱讀!文章來源地址http://www.zghlxwxcb.cn/news/detail-408664.html
到了這里,關(guān)于用C語言寫一個(gè)函數(shù),把字符串轉(zhuǎn)換成整數(shù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!