《捉蟲歷險記—C++ bug大圍剿》讀書筆記
1. 你會用C++寫正確Hello World 程序嗎?
你認爲你能嗎?我寫了一年多的程序,最初我認爲我是可以的,但是當我看到錯誤的程序的時候,我卻沒發現那是個錯誤,原因只有一個,我對C++的函數的瞭解太膚淺了。
示例程序如下:
#include <iostream>
void main(void)
{
std::cout<<"Hello World/n";
}
你認爲上面的程序是對的嗎?至少我把它卸載IDE中,編譯運行的時候,出現了正確的的輸出結果,所以我認爲是對的,其實不然。
原因:函數main()不是一個void型函數,而是一個int型函數。
正確的程序如下:
#include <iostream>
int main()
{
std::cout<<"Hello World/n";
return (0);
}
2. 靜態變量和自動變量的區別
靜態變量的生存期就是整個程序的運行期。在程序開始運行前就爲其分配相應的存儲空間,在程序的整個運行期間一直佔用,直到結束。
自動變量的生存期是說明了自動變量的函數或分程序。它對存儲空間的利用是動態的。其初值在每次爲自動變量分配存儲後都要重新設置。
示例程序:
#include <stdio.h>
//first--Demonstration of automatic variable.
int first(void)
{
int i = 0; //Demonstration variable
return (++i);
}
//second--Demonstration of static variable
int second(void)
{
static int i = 0; //Demonstration variable
return (++i);
}
int main()
{
int counter; //Call counter
for(counter=0; counter<3; counter++)
{
printf("First %d/n",first());
}
for(counter=0; counter<3; counter++)
{
printf("Second %d/n",second());
}
return (0);
}
結果輸出:
3. return (++i) 和return (i++)
return (i++)
(1) 保存i的值
(2) 遞增i
(3) 返回已保存的值
return (++i)
(1) 遞增i
(2) 保存i的值
(3) 返回保存的值
4. 典型的初始化問題
#include <iostream>
int main()
{
int sum; //the running sum
int count; //the current number
for(count=1; count<=100; count++)
{
sum += count;
}
std::cout<<"The sum of numbers"<<"between 1 and 100 is "<<sum<<'/n';
return (0);
}
你認爲上面的程序輸出會是你想要的結果嗎?也許吧,但機會太小了,由於初始化過程中對變量sum 沒有做初始化,因此您不能指望沒有初始化的變量,它可能包含任何值,所以輸出結果也就可能是任何的值,正確的做法就是int sum = 0;
5. 行結束符對程序的影響
#include <iostream>
int main()
{
int result; //result of the addition
result = 2 + 2;
std::cout<<"the answer is "<<result;
std::cout<<"the answer is "<<result<<'/n'; //建議的寫法
return (0);
}
作者對程序給出了這樣的解釋
在MS-DOS中,您會得到如下結果:
The answer is 4C:>#
(#是光標)
在UNIX系統中,您可能得到如下結果:
The answer is 4$ #
問題在程序員沒有在std::cout語句的結束處加上行結束標誌。結果就是:程序運行,輸出一個語句,然後退出,而讓光標停留在輸出行的末尾位置。命令行處理器接着就繼續運行,並在程序的輸出內容之後輸出其系統命令提示符(MS-DOS是C:>,UNIX是$)。
但我在自己機器上的執行並沒有出現這樣的結果,C:>始終也沒有出現,我想惟一的解釋就是後來的C++IDE做了改進 當你的輸出結尾沒有行結束符的時候自動加上。
6. 第一個內存泄露問題
這是我第一次接觸到內存泄露的問題,以前只知道有這麼回事,而且程序最要命的錯誤就是內存泄露,調試起來會很費勁,今天也算是初見端倪,看來以後真的防着這個傢伙了,哈哈。
程序是這樣的,輸出1—5之間數字的平方僅此而已,看看下面的程序,是否滿足你的要求呢?
#include <iostream>
int main()
{
int array[5]; //an array for the squares
int i; //index into the array
for(i=1; i<=5; i++)
{
array[i] = i * i;
}
for(i=1; i<=5; i++)
{
std::cout<<i<<" squared is "<<array[i]<<'/n';
}
return (0);
}
程序結果輸出正確,但是會報要命的系統錯誤,如下圖示:
其實原因很簡單:
C++數值下標的基值是0。因此,數組array[5]的有效元素是:
array[0], array[1], array[2], array[3], array[4]
然而,程序員使用的元素是1-5。不存在元素array[5],因此,程序就修改了隨機內存,導致內存泄漏。
這也是爲什麼C++程序不使用這樣語句的原因:
for (i = 1; i <= 5; ++i) {
而是使用:
for (i = 0; i < 5; ++i) {
修改後的程序如下:
#include <iostream>
int main()
{
int array[5]; //an array for the squares
int i; //index into the array
for(i=0; i<5; i++)
{
array[i] = (i+1) * (i+1);
}
for(i=0; i<5; i++)
{
std::cout<<i+1<<" squared is "<<array[i]<<'/n';
}
return (0);
}
7. 用字符變量表示數字的時候要多加小心。它們可能達不到您想要的結果。
比如如下程序,你認爲輸出是什麼呢?
#include <iostream>
int main()
{
char ch; //the flag
ch = 0xFF; //set the flag
//check the flag
if(ch == 0xFF)
{
std::cout<<"Sucessed/n";
}
else
{
std::cout<<"Fails/n";
}
return (0);
}
或許你認爲肯定是Sucessed,但輸出的缺失Fails,原因是這樣的:ch可能是一個有符號的字符。這意味着,如果ch是0xFF,則當它爲了比較而轉換爲有符號整數的時候,您會得到int(ch)=-1(0xFFFFFFF)。這不是0xFF,導致比較失敗。