昨天翻炒一下C語言。
得到一個題目,我傻,調試一晚上,無解。
題目如下:
編寫函數strend(s,t)。如果字符串t出現在字符串s的尾部,該函數返回1;否則返回0。
我的想法是:
t和s同時從尾部自減,比較其值,遇到不等則立即跳出循環。
偽代碼應該如下(代碼清單-1)
char *s_end;// 假設已經獲得s的尾部
while( 1){
if(*t_end--!=*s_end--)
return 0;
看出來了,這里缺少終止條件,終止條件是:當t_end==t的時候,也要退出循環,表示是相等的
那么代碼應該如下(代碼清單-2)
while(!(t_end==t)){
if(*t_end--!=*s_end--)
return 0;
}
return 1;
不妨換一種想法:
在t的范圍內,如果遇到*t與*s的值不一樣的時候,立即返回。
那么代碼應該如下:(代碼清單-3)
char *s_end; // 假設已經獲得s的尾部
while(t_end-->=t){
if(*t_end!=*s_end--)
return 0;
}
熟悉自增自減操作的朋友,應該看出來,代碼清單-3是錯誤的。
修改后(代碼清單-4)
while(t_end-->=t){
if(*t_end!=*--s_end)//here!!
return 0;
}
return 1;
(*1其實代碼清單-4依然是錯的,文末再談)
這時,不妨看看代碼清單-2和代碼清單-4
代碼清單-2的條件是
代碼清單-5:
!(t_end==t)
描述為: 當t_end==t的時候,退出循環。
代碼清單-4的條件是
代碼清單-6:
t_end-->=t
描述為:若不在t的范圍內,則退出循環。
好,那么這文章到底要說什么?
其實,寫代碼和寫文章一樣。
代碼清單-5更加合適while思維。
代碼清單-6則更合適for的思維。
用for改寫代碼清單-6:
代碼清單-7:
for(;t_end>t;t_end--,s_end--){
if(*t_end!=*s_end)//here
return 0;
}
return 1;
為什么說對想法有干擾?
當需要重復做一件事的時候(比如查找),通常都會用循環。
而循環我認為是這樣的:
不停的查找,如果找到就不找了,找完也不找了。
而對於程序,我認為是這樣的:
while not found, then check the next one!
寫做代碼
while(!found) check;這樣表達很不好,因為沒有check next one的動作。
所以
for(;!found;next) check it!;
來看看while的語法和描述
while(表達式)
語句
描述:先求表達式的值。如果其為真非0,則執行語句,再次求該表達式值 ,直到表達式的值為假(0)為止。(C語言程序設計 第二版*新版 P49)
而人和代碼的差異就在於表達式的真假是如何描述的。
首先,查找這個問題,分為三個判斷
1、找到了。
2、還沒找到。
3、找完了。
不停的找可以表達為:while(1)
如果找到可以表達為:if(1) found
找完了可以表達為:while(false)
看,找完了的表達是while(false)
而我,常常會把不停的找放進去false里面,其實是不對的。
正確的解釋應該是:
while(!停) //如代碼清單-5,然而,不知道是腦袋容易忘還是什么的,我常常忘記了!。
寫到這,這文章算完了,感覺有點裹腳布。
補充:
(*1為什么代碼清單-4是錯的?)
原因是自減符號!
回憶:
a=i++;//先取值后自增(表達式后自增)
a=++i;//先自增后取值(表達式時自增)
那么考慮代碼清單-4的代碼
while(t_end-->=t){
if(*t_end!=*--s_end)//here!!
這個時候,t_end已經不是在尾部了,也就是說比較的時候,缺少了一個值。
