實 習 內 容 |
|||||||||||||||||||||||
實 習 目 標 |
1. 數值與邏輯值 2. 邏輯運算式 3. if 敘述 4. switch 敘述 |
||||||||||||||||||||||
1 |
邏輯值: C 程式中沒有設計特別的資料型態來表示邏輯的 "真"/"偽", 任何資料都可以解釋為邏輯的真或是偽: 資料中每一個位元都是 0 的解釋為
邏輯的 「偽 (false)」, 如果直接把那個資料的所有位元用二進位整數去解釋 數值 0 解釋為 邏輯的 「偽 (false)」, 所有非 0 的數值 解釋為 邏輯的 「真 true」 (在 C++ 語言中, 使用一個新增加的型態 bool 來表示邏輯值, 使用範例如 bool x; x = true; 或是 x = false;) 編譯並且輸入各種數值來測試下列程式:
上面的測試中, 你也可以用右邊括號裡面的敘述來取代左邊程式裡的 printf() 及 scanf()。 char 型態的變數裡面存放的是「那個字元的內碼」,在這裡是 ASCII 編碼 ,你也可以在 if 敘述前面加上 printf("x=%d", x); 來用十進位格式看看所存放的字元的編碼值 space 代表 "鍵盤上面的空格鍵" |
||||||||||||||||||||||
2 |
邏輯運算式: 在一個可以執行的程式中測試下列敘述:
==, !=, >, >=, <, <= 這些運算子叫做 "關係運算子 (relational operator)" &&, ||, ! 叫做 "邏輯運算子 (logical operator)" 接下來請測試下列程式 int x=0; if (x=0) printf("x is 0\n"); else printf("x is not 0\n"); 告訴我執行的結果是?? 為什麼有這種結果? 再試一下 int x=0; if (0=x) printf("x is 0\n"); else printf("x is not 0\n"); 你會發現上面這個 0=x 的寫法是編譯器不能接受的, 因為一個等號是資料的設定, 等號左手邊一定要是一個變數, 但是上面是 0, 所以編譯器不能接受, 當然如果你寫 0 == x, 這是完全合法的比對大小, 你就會發現如果你習慣打 0 == x, 當你不小心漏打一個等號的時候, 編譯器也會陰錯陽差地幫你找到問題... 另外有一個很邪惡的錯誤是這樣的,下面的條件看起來數學上是完全可以理解的,試試看,你會發現詭異的結果: int x=2; if (3<=x<10) printf("%d is inside the region [3, 10)\n", x); else printf("%d is outside the region [3, 10)\n", x);會印出 2 is inside the region [3,10),哇! 為什麼會這樣?怎麼可以這樣? 太邪惡啦! 其實沒有人很邪惡啦,學了十幾年的數學表示方法使得你很直覺地想要寫上面的敘述,但是當編譯器看到 3<=x<10 的邏輯運算式時,它會像在加減乘除的運算式中決定誰先加、誰先乘一樣來決定 <= 和 < 兩個運算的先後順序,會把 3<=x<10 看成 ((3<=x)<10),於是 (3<=2) 運算後會得到 0,(0<10) 運算後會得到 1,所以執行的時候就列印出 2 is inside the region [3,10) 的結果。 哈哈,所以編譯器很邪惡!! 機器也很邪惡!! 其實沒有啦,它只是笨而已,看你的程式時只有語法裡既定的一種解釋方法。 |
||||||||||||||||||||||
3 |
if 敘述練習 請根據下列流程圖撰寫 if 敘述來完成, 請特別注意 "大括號的使用"。 上述流程圖是用來輔助設計 "複雜" 的條件邏輯的, 並不是先寫完程式, 測試正確以後再畫出來欣賞的, 既然如此,你覺得上面這個流程有什麼不好的呢? 好像不太規律哦! 看起來沒有比直接看程式好到哪裡去! 畫流程圖也是有技巧的, 流程圖仔細設計出來以後, 很容易運用它檢查邏輯的完整性, 可是隨便畫的流程圖就不一定可以達成這個目的, 先寫出程式再根據它畫的就很容易是很不規律的。下面這張圖有稍微好一點嗎? (什麼地方不一樣了?) 範例程式碼你的程式應該要避免出現多層的
if 敘述 (巢狀的 if 敘述, nested-if) if ( ... ) { ... if ( ... ) { ... } else { ... if ( ... ) { ... } } } else { ... } 請在合適的地方使用 "多選項的 if (multiple alternative if)" 敘述實現扁平化的邏輯判斷來簡化程式 if ( ... ) { ... } else if ( ... ) { ... } else if ( ... ) { ... } else { ... } 只有一層的條件敘述是比較容易了解的, 請根據下圖重新設計這個條件測試!
請注意: 程式的最終目的是讓電腦執行你教它的演算法, 照理說讓編譯器看得懂, 執行結果對了就好, 可是請注意, 你的程式是需要修改, 需要新增功能, 需要維護的, 電腦不會做這些事, 是你需要做的, 你要進行這些事情之前, 你需要看懂程式碼在寫什麼, 你需要讀懂自己寫的程式 (也許是三個月後或是三年後), 你也需要讀懂別人寫的程式, 你才能夠正確地修改程式或是新增功能, 所以程式一定要寫成 "人很容易看懂" 的形式。根據統計(有人實驗把寫程式時操作編輯器的動作記錄下來, 分析他輸入程式和上移, 下移觀看程式的比例), 寫程式的人花在讀程式的時間和寫程式的時間的比例至少是 10 比 1 (你需要看懂程式的上下相關的部份才能夠寫出正確運作的程式)。所以請不要故意設計複雜的邏輯, 不要用不具意義或是容易誤導的變數名稱或是函數名稱, 讓同學, 助教, 或是我看不懂也許有一點厲害, 不過副作用是讓自己也看不懂或是很容易誤解, 當你需要花很多時間才能夠看懂自己寫的程式的時候, 等到看懂了你就已經沒力氣去加新的功能了, 常常寫這樣的程式, 習慣了以後就是在跟自己的時間與精力過不去, 你的工作效率會因此低落, 你的工作夥伴會很厭惡你 (當然不會直接跟你說啦! 但是會躲著你), 不是很聰明的一個作法。下面是幾段常常在資訊界被引用的話, 都跟上面講的東西有關係 Any fool can write code that a computer can understand. Good programmers write code that humans can understand. (Anonymous) Any code of your own that you haven't looked at for six or more months might as well have been written by someone else. (Eagleson's law) Programs must be written for people to read, and only incidentally for machines to execute. (Abelson / Sussman) Programming can be fun, so can cryptography; however
they should not be combined. (Kreitzberg and Shneiderman) |
||||||||||||||||||||||
4 |
switch 敘述練習 根據下表請運用 "switch" 敘述寫一小段程式, 根據變數 watts 裡面記錄的燈泡瓦數, 找到對應的燈泡亮度記錄在變數 lumens 裡面, 作一個很簡單的資訊轉換:
例如: int watts, lumens=-1; scanf("%d", &watts); switch (watts) { case 15: lumens = 125; break; case 25: lumens = 215; break; ... default: printf(":)\n"); } if (lumens>0) printf("%d\n", lumens); 很多時候因為轉換沒有很簡單的公式, 所以就一個一個地比對然後轉換, 以後如果你知道迴圈和陣列的語法, 就可以用更簡潔的方式來撰寫,也不怕表格內容太多了。 請注意:
|
||||||||||||||||||||||
5 |
浮點數的測試: 請不要使用 == 或是 != 來測試浮點數或是倍精準的浮點數 請編譯、執行、並且仔細觀察下列程式的執行結果: #include <stdio.h> int main(void) { double x = 3.13; printf("x = %20.16f, 3.13 is %20.16f\n", x, 3.13); if (x == 3.13) printf("x is 3.13\n"); else printf("x is not 3.13\n"); x = 3.09; x = x / 2.0 + 1.51; // 1.545 + 1.51 should be 3.055 printf("x = %20.16f, 3.055 is %20.16f\n", x, 3.055); if (x == 3.055) printf("x is 3.055\n"); else printf("x is not 3.055\n"); if ((x>3.055*(1-1e-10))&&(x<3.055*(1+1e-10))) printf("x is close to 3.055\n"); else printf("x is not close to 3.055\n"); return 0; } 測試程式 testDouble.exe 鍵盤輸入的情況和直接設定的情況接近 (例如: double x; scanf("%lf", &x); if (x!=0){ ... }) |
||||||||||||||||||||||
6 |
請寫一個程式, 由鍵盤輸入一個英文字母字元, 如果是小寫字元請轉換為大寫字元, 將轉換過的字元列印出來,
如果是大寫字元, 就直接印出。請注意這個轉換是不需要用表格的, 可以找到很簡單的轉換公式 範例執行結果 Please input a character (e.g. e): e input: e output: E Please input a character (e.g. e): A input: A output: A |
||||||||||||||||||||||
7 |
最直接的想法是看到一個阿拉伯數字立刻就輸出對應的中文數字: 請參考 arabic to chinese 不過我們要求你寫的程式不像上面這個那麼直接, 原因是如果你看到 11, 你不會直接翻譯唸成『一一』,也不是直接把『十』、『百』加進來唸 『一十一』, 而是唸成『十一』; 看到 20 不是唸成『二零』更不是『二十零』而是『二十』; 看到 105 不是唸成『一零五』更不是『一百零十五』而是『一百零五』; 這些例子告訴你的是這個轉換規則有點複雜, 不能用單一的轉換規則來做, 會和輸入數字的範圍有一些關係
|
回
程式設計課程 首頁 製作日期: 10/06/2012 by 丁培毅 (Pei-yih Ting) E-mail: [email protected] TEL: 02 24622192x6615 海洋大學 電機資訊學院 資訊工程學系 Lagoon |