《C++ Primer》中提供了一個簡單的例子來教我們應該如何爲現有的程序打補丁。修改程序或許很容易,但是如果我們不注意一些細節上的處理可能會讓修改後的程序很難讀懂。
這是一個計算 C 風格字符串長度的實現。注意了,因爲我們是要爲程序打補丁,理所當然地,以下這個實現是有問題的:
using namespace std;
const char *st = "The expense of spirit ";
int main() {
int len = 0;
while( st++ ) { ++len; }
cout << len << ": " << st;
return 0;
}
在這 個實現中不難發現錯誤在於循環 while( st++ ),我們是要利用 C 風格字符串以 '/0' 字符結束的特性來計算其長度。st++ 表示的不是字符串中的字符數值,而是字符的地址。因此,while( st++ ) 應該改爲 while( *st++ )。
這時候,len 的值是計算正確了,但是必須注意,在 cout << st 中, st 已經前進到終止空字符之後的字符上去了。往往,有些人會這樣處理:在 cout 前加入一條語句 st = st - len - 1;
using namespace std;
const char *st = "The expense of spirit ";
int main() {
int len = 0;
while( *st++ ) { ++len; }
st = st - len - 1;
cout << len << ": " << st;
return 0;
}
經過修改,此時程序是正確了。可是任何看了修改後的程序也會覺得彆扭。確實 st = st - len -1; 如此賦值並不符合程序的原始邏輯,而且修改後的程序並不容易理解。
如此翻來覆去的修改,已經使得代碼不太雅緻了。
在打補丁的時候,必須考慮修改後的程序邏輯是不是明瞭,對問題是否考慮周全了。
《C++ Primer》提示了一個方法來處理這個實現的 bug,這也是我平時最喜歡使用的,對於在一個作用域中需要重複使用的變量,我會另外定義的一個同類變量來做變化參數。
在這個例子中,我定義了另一個指針 p,並用 st 對它初始化。
const char *p = st;
用 p 來計算長度,st 就不用改變了。
while( *p++ )
修改後的代碼如下:
using namespace std;
const char *st = "The expense of spirit ";
int main() {
const char *p = st;
int len = 0;
while( *p++ ) { ++len; }
cout << len << ": " << st;
return 0;
}