上一章
不知你是否嘗試過讓程式做到以下事情:
輸入一個名字 (大小寫字母組成),輸出「Hello, 名字!」
1. 土法煉鋼法
我們已經學過怎麼輸入一個字元 (甚麼是字元?),也知道怎麼用直接的方式 (用兩個「'」框起來) 表示一個字元
所以,我們可以一個一個的輸入字元,然後一一判斷是不是大小寫字母,當輸入的字元不是大小寫字母時,我們就知道一個「名字」已經輸入完了 (因為名字只能由大小寫字母組成)
套用上一章所學的簡化方式,我們就可以實現這個輸入名字的功能 (以下程式碼已經假設名字的長度$\leq$一百萬):
#include<cstdio> int main() { char name[1000001]; int i=0; while(1==1) { scanf("%c",&name[i]); char c=name[i]; if(c!='a'&&c!='b'&&c!='c'&&c!='d'&&c!='e'&&c!='f'&&c!='g'&&c!='h'&&c!='i'&&c!='j'&&c!='k'&&c!='l'&&c!='m'&&c!='n'&&c!='o'&&c!='p'&&c!='q'&&c!='r'&&c!='s'&&c!='t'&&c!='u'&&c!='v'&&c!='w'&&c!='x'&&c!='y'&&c!='z'&&c!='A'&&c!='B'&&c!='C'&&c!='D'&&c!='E'&&c!='F'&&c!='G'&&c!='H'&&c!='I'&&c!='J'&&c!='K'&&c!='L'&&c!='M'&&c!='N'&&c!='O'&&c!='P'&&c!='Q'&&c!='R'&&c!='S'&&c!='T'&&c!='U'&&c!='V'&&c!='W'&&c!='X'&&c!='Y'&&c!='Z')break; i=i+1; } printf("Hello, "); int j=0; while(j<i) { printf("%c",name[j]); j=j+1; } printf("!\n"); return 0; }
我才不信你會想這樣搞咧,對吧?
52個字母一一判斷實在是太累了,而且容易打錯
很幸運地,對電腦來說,「一個字元」其實就是「一個數字」
例如:「M」對應到「77」、「o」對應到「111」
如果你硬要把這些字元用整數的「%d」輸出 (而不是字元的「%c」),你看到的就是這些字元所對應到的數字
我用以下程式碼做示範:
#include<cstdio> int main() { printf("%d %d\n",'M','o'); }
沒意外的話,程式會輸出「77 111」
程式輸出「77 111」了! |
因此,你甚至可以把每個直接表示的字元用數字來取代
把上面輸入一個名字的程式改寫成這樣:
#include<cstdio> int main() { char name[1000001]; int i=0; while(1==1) { scanf("%c",&name[i]); char c=name[i]; if(c!=97&&c!=98&&c!=99&&c!=100&&c!=101&&c!=102&&c!=103&&c!=104&&c!=105&&c!=106&&c!=107&&c!=108&&c!=109&&c!=110&&c!=111&&c!=112&&c!=113&&c!=114&&c!=115&&c!=116&&c!=117&&c!=118&&c!=119&&c!=120&&c!=121&&c!=122&&c!=65&&c!=66&&c!=67&&c!=68&&c!=69&&c!=70&&c!=71&&c!=72&&c!=73&&c!=74&&c!=75&&c!=76&&c!=77&&c!=78&&c!=79&&c!=80&&c!=81&&c!=82&&c!=83&&c!=84&&c!=85&&c!=86&&c!=87&&c!=88&&c!=89&&c!=90)break; i=i+1; } printf("Hello, "); int j=0; while(j<i) { printf("%c",name[j]); j=j+1; } printf("!\n"); return 0; }
測試看看,程式依然是同樣的邏輯!
輸入「Mobius」,程式依然是輸出「Hello, Mobius!」 (順帶一提,「Mobius」是我們「105級高雄中學科學班成果發表會」的名稱,歡迎大家前去看看~~~) |
2. 邏輯判斷法
聰明的你一定發現了
「'a'~'z'」對應到數字「97~122」
「'A'~'Z'」對應到數字「65~90」
那麼,我們只要和這些數字比大小,判斷有沒有在區間「97~122」或區間「65~90」就好啦!
所以我們輸入名字的程式碼就可以大幅精簡一個量級:
#include<cstdio> int main() { char name[1000001]; int i=0; while(1==1) { scanf("%c",&name[i]); char c=name[i]; if((97<=c&&c<=122)||(65<=c&&c<=90)); else break; i=i+1; } printf("Hello, "); int j=0; while(j<i) { printf("%c",name[j]); j=j+1; } printf("!\n"); return 0; }
注意到程式碼中的「c」這個變數
「判斷c是字母」比「判斷c不是字母」還要來得容易
因此先判斷「判斷c是字母」
條件成立時代表甚麼事都不用做
條件不成立時就執行「else」裡面的程式碼 (break;) 跳出迴圈
此外,要判斷一個邏輯是不是「不成立」,有個簡單的方法
在前面加一個「!」:
#include<cstdio> int main() { char name[1000001]; int i=0; while(1==1) { scanf("%c",&name[i]); char c=name[i]; if(!((97<=c&&c<=122)||(65<=c&&c<=90))) break; i=i+1; } printf("Hello, "); int j=0; while(j<i) { printf("%c",name[j]); j=j+1; } printf("!\n"); return 0; }
注意到,我們要的是「判斷『(97<=c&&c<=122)||(65<=c&&c<=90)』是不是『不成立』」,而不是「判斷『(97<=c&&c<=122)』是不是『不成立』」
因此,我們需要用小括號將「(97<=c&&c<=122)||(65<=c&&c<=90)」包起來變成一體,才能放心的在前面加上「!」
此外,如果你不想記住「『a』對應到哪個數字」之類的
你大可直接把程式碼寫成這樣:
#include<cstdio> int main() { char name[1000001]; int i=0; while(1==1) { scanf("%c",&name[i]); char c=name[i]; if(!(('a'<=c&&c<='z')||('A'<=c&&c<='Z'))) break; i=i+1; } printf("Hello, "); int j=0; while(j<i) { printf("%c",name[j]); j=j+1; } printf("!\n"); return 0; }
趕快驗證一下,程式還是在做同樣一件事情,對吧? |
3. 投機取巧法
咦?其實我們剛剛在做的事可以直接用兩行程式碼解決哦~ (遭踢飛)
在第二章時我們學過:「int」要用「%d」,「char」要用「%c」,「float」要用「%f」
而在這一章,我們會學到:「字串」要用「%s」
甚麼是「字串」?就是一串字元
比較標準的說法,只要是一個或多個字元 (不一定要大小寫字母,甚至「' '」、「'\n'」也是可以接受的) 連在一起,我們就稱之為「字串」
當你用「scanf」來輸入一個「%s」時,程式得到的輸入會是一個「不含隱藏字元的字串」
「隱藏字元」泛指「無法直接顯示出來」的字元,例如:空白「' '」、Tab「'\t'」、換行「'\n'」
剛好,「大小寫字母」都不是隱藏字元 (大小寫字母顯示出來時你是看得到黑色部分的)
因此,不妨直接使用「%s」來輸入一個名字
剛剛說到,「%s」代表「不含隱藏字元的字串」,也就是「一串字元」,因此要用「char陣列」來儲存這「一串字元」
用法請參考以下程式碼:
#include<cstdio> int main() { char name[1000001]; scanf("%s",name); printf("Hello, "); printf("%s",name); printf("!\n"); return 0; }
注意,用「scanf」輸入「%s」時,不需要在「char陣列名稱」前面加「&」
然後,如果你想要達到「兩行程式碼」的目標,把三個「printf」寫成一個也無妨:
#include<cstdio> int main() { char name[1000001]; scanf("%s",name); printf("Hello, %s!\n",name); return 0; }
趕快驗證一下,程式還是在做同樣一件事情,對吧? |
希望你程式的功能可以越來越強!
題外話:原本「土法煉鋼法」的程式碼裡面的那個「i」怎麼可以省略?(註4)
下一章
感謝:
(版權所有 All copyright reserved)
好像有bug啊啊
回覆刪除您好,請問bug是什麼呢?
刪除小莫很樂意修正!
感謝~
那一整串的運算元都超出螢幕拉
刪除當然如果那是故意的就沒差就是了
刪除這個嘛...
刪除用Google Chrome的確會有這個問題 (如果用Edge瀏覽就沒事)
剛剛針對這個問題上網研究了一下,還是找不到有用的解決方法
抱歉哦...QQ
嗨 百五的雄中學長,其實上面顯型字元,有包括數字
回覆刪除,所以應該還是有差啦 ,XD ~
恩對呀XD
刪除那您有建議要怎麼修改嗎?
想問一下 我在程式上開設一個 char name[10] 長度為10的char
回覆刪除接著用cin附值給他(我故意將附值內容多於10個字)
接著用cout來print name時可以完全輸出我剛剛打的名字
但用sizeof(name)時name的byte還是為10,這是什麼原因呢?