賀老師:
老師,m_szDepartment=new char[strlen(department)+1];為何需要+1呢?在測試裡去掉+1後和這個效果一樣啊,不太明白……求指教……
學生,楊騰飛
我回答:
要給'\0'占個座。是用別人的地盤(越界的部分)保存了自己的信息了吧,不定哪次人家要用,運行結果就不一樣了。這恰是最危險的問題。
他繼續追問:
可是在定義字符數組時,比如a[4]時,可以輸入5個字符,那麼這個數組的'\0'的位置是不是也占用了別人的?
我為這個機靈的同學的問題感到激動,讀程序,切忌只是讀,要會提問題。能自己提出問題,就一定能學好。老師給出解答,接著再提出新問題,自己解答,或再問老師,這就是交流。為著學生提出了好問題,作為老師,我驕傲。我的回答是:
你提的問題不是一般的好,見我新發表的博文談這個問題。
下面就是我對這個問題的解答。不妨針對問題設計一個程序試一試。程序是:
[cpp]
#include <iostream>
using namespace std;
int main()
{
char a[4];
cin>>a;
cout<<a<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
char a[4];
cin>>a;
cout<<a<<endl;
return 0;
} 親愛的讀者,讀這篇文章時,請不要只“讀”,打開你熟悉的編程環境,邊讀邊運行。你會發現什麼?
輸入abcd然後回車,輸出是abcd。cout<<a是將字符數組當字符串輸出的,顯然abcd已經占滿了自己的地盤a[0]到a[3],能夠“如願”輸出,實際上已經侵占了不該占的內存a[4]單元。當然,恰好a[4]處給臉,就是'\0'。如果”燙燙燙燙燙燙“不必意外。
再運行,輸入abcde。我運行的結果是,在VC++6.0中,輸出abcde,並彈出了我們熟悉的內存越界錯誤提示。在codeBlocks下,輸出abcde,什麼也沒提示。
請讀者想想,這是一個多麼凶險的Bug。
下面再給出一個程序:
[cpp]
#include <iostream>
using namespace std;
int main()
{
char a[4],b[4];
cin>>a;
cin>>b;
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
char a[4],b[4];
cin>>a;
cin>>b;
cout<<a<<endl;
cout<<b<<endl;
return 0;
} 運行的任務交給讀者了,觀察輸入3個字符、4個字符、5個字符的情形,也可以在多個平台上試試,針對結果想想為什麼。用單步執行的手段跟蹤一下內存中的數據存儲,是個強烈建議的辦法。
下面是為a和b數組輸入3個字符後(分別是abc和hij),利用單步執行看到的結果:
下面是為a和b數組輸入5個字符後(分別是abcef和hijkl),利用單步執行看到的結果:
從中看出,VC++6.0中,先定義的a數組的地址大於後定義的數組b的地址,本來為a中輸入了abcde,侵占了別人的地盤,隨後為b輸入hijkl,侵占的就是a的地盤,b[4]即a[0]為l,b[5]即a[1],存儲的是'\0'!
下圖是在codeBlocks下,用同樣的輸入調試截出的結果,結果一樣:
接下來,再給一個程序,其實就是將輸入a和b的順序換了一下:
[cpp]
#include <iostream>
using namespace std;
int main()
{
char a[4],b[4];
cin>>b;
cin>>a;
cout<<a<<endl;
cout<<b<<endl;
return 0;
}
#include <iostream>
using namespace std;
int main()
{
char a[4],b[4];
cin>>b;
cin>>a;
cout<<a<<endl;
cout<<b<<endl;
return 0;
} 運行結果會是怎樣?讀者你自己說吧。不要忘了,用調試工具這個法寶解除你的疑惑。