鍵盤輸入與螢幕輸出

 

  實習內容



1. 變數定義, 變數型態, 與設定運算式 (assignment expression)

2. 由鍵盤讀入一些資料: 運用 stdio.h 裡的 scanf 函數

3. Miles-to-Kilometers 程式解說

4. 計算 平方和

5. 計算 直線和橢圓交點

1.

變數:

    int x;

x 是一個程式裡定義的變數, 存放的資料型態是 int, 也就是 32位元有正負號的整數

一旦在程式裡定義一個變數以後, 你可以運用 = 把指定型態的資料存放在變數裡面, 例如

    x = 123;

把整數 123 存放在變數 x 裡面, 存放在變數裡面的資料會一直保留在裡面不變, 直到另一個 = 把其它資料存放在這個變數裡, 才會覆蓋掉剛才存放的資料。下面這個例子就是解釋這個概念:

    x = 123;
    printf("x=%d\n", x);
    printf("doing something else\n");
    printf("doing something else\n");
    printf("doing something else\n");
    printf("doing something else\n");
    printf("x=%d\n", x);
    printf("the value stays unchanged in the variable x, until you change it explicitly\n");
    x = 321;
    printf("x=%d\n", x);
上面程式片段中, printf 是標準輸出入函數庫中所謂的 "格式化輸出函數", 我們會在第四章裡比較詳細地說明, 目前你只需要知道像 printf("x=%d\n", x) 函數呼叫敘述裡面, "x=%d\n" 和 x 是給函數的兩個參數, 其中第一個參數是一個字串常數, 第二個參數是一個整數資料, 第一個參數裡的 %d 是配合轉換第二個參數的指令, 將 123 轉換為十進位輸出在螢幕上

再試試下面的程式碼, 看看印出來的東西是什麼?

    x = 123.456;
    printf("x=%d\n", x);

編譯時有錯誤或是警告訊息嗎?

在 Dev C++ 中如果你用 C++ 的編譯器 (副檔名用 .cpp) 則你會得到以下的警告訊息

[Warning] converting to 'int' from 'double'

警告訊息是告訴你這個語法有可能有危險, 希望你多留意, 但是編譯器還是會翻譯成機器可以執行的 .exe 檔案, 以這個範例來說, 警告訊息是說當你要電腦把有小數點的資料 123.456 存放在整數型態的變數 x 裡時, 資料會有損失, 小數點以後的資料會損失掉... 這個訊息希望你重新檢視它, 如果你確定可以接受這樣子的處理方式, 你就直接執行剛才的 .exe 檔案, 否則就要修改程式了 (以後你會學到如何讓編譯器不要對一個你已經檢視過的敘述發出這樣的警告訊息)

為什麼一個程式需要定義一些變數? 你能夠想像如果你自己沒有任何記憶的話, 你能夠做的或是能夠計算的是不是大受限制呢? 實際上記憶體的數量是否有限制? 記憶體的存取方式是否有限制? 都會影響到一個程式的能力。

2.

在上面的程式範例中, 你可以在程式中撰寫一些固定的資料, 設定到變數裡面讓程式去計算, 不過這樣子做的話, 這個程式編譯完以後就只能處理固定的資料, 想要更改資料就要重新編譯過 ; 有沒有辦法讓程式由鍵盤讀取資料來運算呢? 試試下面的程式碼:

#include <stdio.h>
#include <stdlib.h>
int main(void)
{
    int x;
    printf("Please input an integer:");
    scanf("%d", &x);
    printf("square of %d = %d\n", x, x*x);
    system("pause");
    return 0;
}

請編譯 (Ctrl-F9), 執行 (Ctrl-F10) 測試一下; 如果你不修改程式而重新執行, 你只需要按 Ctrl-F10 執行即可, 不需要重新編譯, 當程式很大的時候, 你不希望每次更改測試資料時就重新編輯程式、重新編譯程式, 事實上執行程式的人不見得會寫程式, 他只需要執行就好!

接下來你可以練習看看把變數 x 宣告為倍精準浮點型態 double (這是存放有小數點的實數資料的), 由鍵盤讀入一個實數, 然後顯示這個數的 3 次方

(請注意: 變數型態請使用 double, 呼叫 scanf 函數時 "%d" 請換成 "%lf", 呼叫 printf 函數時 " ... %d ... %d ..." 請換成 " ... %f ... %f ... "; 另一種單精準度浮點變數型態是 float, 呼叫 scanf 函數時 "%d" 請換成 "%f", 呼叫 printf 函數時 " ... %d ... %d ..." 請換成 " ... %f ... %f ... ")

3.

接下來請一步一步完成 "miles to kilometers" 這個程式. 一次加進去一部份的程式碼, 然後編譯測試, 不要急著一下子把程式都打完然後才測試, 這樣子發生錯誤時你會更清楚知道是哪些動作造成的錯誤. 等到你對於程式語法掌握更清楚了, 你就能夠一次多寫一些東西而不會一下子產生太多錯誤了:

下面這段程式打算由鍵盤讀入 英里 數, 單位轉換成公里以後印出來, 首先先運用 /* ... */ 的註解敘述很快地把程式該做的事情輸入在編輯器裡 (註解是編譯器不看的東西, 純粹是給寫程式的人看的):

/*
 * Converts distance in miles to kilometers.
 */
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    double miles,  /* input - distance in miles.       */
           kms;    /* output - distance in kilometers  */

    /* Get the distance in miles from user. */

    /* Convert the distance to kilometers. */

    /* Display the distance in kilometers. */

    system("pause");
    return 0;
}

編譯, 執行, 雖然沒有印出什麼有意義的東西, 但是至少剛才輸入的這段東西是合乎 C 語法的

接下來在 int main(void) 之前加入下面的轉換常數定義:

#define KMS_PER_MILE 1.609

編譯, 執行

在 /* Get the distance in miles from user. */ 下面加入

printf("Enter the distance in miles> ");
scanf("%lf", &miles); 

編譯, 執行

在 /* Convert the distance to kilometers. */ 下面加入

kms = KMS_PER_MILE * miles;

編譯, 執行

在 /* Display the distance in kilometers. */ 下面加入

printf("That equals %f kilometers.\n", kms);

編譯, 執行

測試一些可能的輸入數據 (比方說 1, 1.0, 121.7, 0.0, -15.2, ...)

注意: 計算的時候除了乘法用 * 符號之外, 除法用 / 號, 加法用 + 號, 減法用 - 號, 如果要計算開根號的話, 你可以像下面這樣子用 math.h 函數庫裡面的 sqrt 函數來計算

#include <math.h>
...
double a, b;
b = 3.5;
a = sqrt(b);

除了上面的說明之外, 你還可以參考我另外撰寫的 mils2kms程式設計說明

4.

再試一個類似的例子:

請寫一個程式由鍵盤輸入一個整數 n, 計算 12 + 22 + 32 + ... + n2 的數值, 並且輸出在螢幕上

寫這個程式的時候, 請先找出計算的公式, 然後把公式轉換為 C 的程式 (給電腦詳細的指令, 電腦就可以根據你教它的方法一步一步執行)

注意:
1.
  
n
∑ 
r=1
r3–(r–1)3  =  n3–(n–1)3 + (n –1)3–(n–2)3 + ... + 33–23 + 23–13 + 13–03  = n3
 = 
n
r=1
r3 – (r3–3r2+3r–1)
 = 
n
r=1
3r2–3r+1
 = 
n
r=1
3 r2– 3 n (n+1) / 2 + n
因此
12 + 22 +... + n2  = 
n
∑ 
r=1
r2 =  n (n+1) (2n+1) / 6

2. 如果你已經會用 "迴圈" 的話, 你曉得可以直接寫一個迴圈讓電腦把這 n 個平方數加總起來, 例如:

int sum = 0;
for (i=0; i<n; i++)
    sum = sum + i * i;

但是這樣子程式的執行效率並不好, 不要以為計算機反正速度很快, 就讓它笨笨的一個一個加就好了, 假設我們想要計算 212345678901234567890 mod 12345, 如果你用一個迴圈慢慢乘, 可能需要執行一年的時間, 實際上指數運算有很簡單又很快的方法, 所以在這個例子裡希望你用比較快速的公式來教電腦計算

3. 這個例子需要注意整數變數所能記錄的數值的大小

5.

現在你有足夠多的工具來完成下面這個簡單的應用程式了:

線上繳交

程式由鍵盤輸入 a, b 兩個實數, 代表平面上一條直線方程式 a (x-1) - b y = 0
程式輸出這條直線和橢圓 x2 + 4 y2 = 3 的兩個交點

範例執行程式 (e-Tutor 線上繳交的程式和左邊這個範例有點差異, 請根據 e-Tutor 上的描述來輸出, 並且去除提示使用者的所有文字)
完成以後, 請在 e-Tutor 線上繳交, 繳交截止時間 107/09/19 (三) 21:00

提示: 你要先研究一個方法自己手動把答案算出來, 然後再來寫程式教電腦去計算...

  1. 由鍵盤輸入兩個實數進到程式的 double 變數裡應該不是問題, 每個變數都有一個名字, 自己替這兩個變數取名字
  2. 接下來你一定要接受電腦很笨這個事實, 它完全不知道怎麼去解那兩個交點, 所以請你自己在紙上去算出那兩個交點, 例如你可能由一次式把 y = ??? x 代進二次式裡得到一個 x 的二次方程式, 然後解出兩個可能的 x, 再透過直線方程式計算對應的 y 值
  3. 有了上面的計算方法以後, 你再把它換成程式, 例如:
    你可能算出來 x 的二次方程式中 x2 項係數是 1 + 4 a2/b2
    如果 a, b 就是你讀入的係數, 那你應該要定義一個新的變數來存放二次項係數, 例如 c2, 然後把你的計算方法寫成程式的敘述如下:
    c2 = 1 + 4 * a * a / b / b;
    接下來就是教電腦計算 c1, c0, 然後再教電腦用解二次方程式的公式來解兩個根 x1 和 x2, 在過程裡你應該會根據需要來定義新的變數
    ...
  4. 列印的時候請運用 %.3f 格式命令要求 printf 在小數點後只列印三位數, 第四位以後四捨五入

注意: 雖然上面這個問題一定有兩個交點, 但是如果輸入的 b 是 0 的話, 上面範例程式執行的結果一定還是錯的, 你可以測試一下, 如果你希望程式自己避開這個問題, 你需要使用 if 條件判斷敘述, 基本語法如下:

if (b == 0) // 請注意要比較是不是相等需要用 == 而不是用 = 
{
    ...
}
else 
{
    ...
}

更進一步想一下如果上面的步驟裡你是把 x = ??? y 代進橢圓方程式裡, 這樣子導出的公式裡你會遇見對稱的另外一個狀況, 如果 a 是 0 就麻煩了, 也需要運用 if 的條件判斷敘述來處理

因為我們還沒有正式講這個語法, 而且就算你用上面這樣的測試, 你可能還可以發現有一些特別的數值還是會產生不太能接受的結果, 所以請你想一下為什麼會出錯, 然後暫時不要管這個錯誤吧! 等我們有更多工具時再來處理這種狀況

上面的範例執行程式最後會印出驗證的資料, 那是把算出來的 x, y 代回去橢圓方程式, 計算 x2 + 4 y2 是不是等於 3

接下來你可以再思考一件事: 上面方法裡用 a 和 b 計算出 c2, c1, c0, 也設計變數來存放這三個數值, 然後再用解二次方程式的公式來找答案 x1 和 x2, 如果我們手動推導的時候, 多做一點, 直接推出一個用 a 和 b 直接計算出 x1 和 x2 的公式, 會不會比較好呢? 機器執行起來比較有效率一點點吧, 不用先算出中間的係數: c2, c1, c0, 不過這裡節省的時間其實不太多, 反而是推導的時候很辛苦, 也很容易發生錯誤, 還是讓電腦去做吧!

實習有沒有繳交占學期成績固定比例, 需要繳交的實習請不要遲交(時間應該都還蠻充裕的, 有任何問題請在繳交時間之前告訴我), 繳交的程式需要通過預設的測試 (繳交無關或是完全不可能正確的程式不予計分), 透過這些實習題目?

  1. 你和同學,助教之間可以有明確需要討論的問題
  2. 可以替你自己設定一個學習的目標
  3. 可以記錄你自己學習的過程
  4. 老師和助教可以透過繳交的狀況瞭解同學學習的進度
  5. 我們盡量讓實習之間能夠延續, 所以你每一次繳交的東西, 可能後面還會用到
 

你需要很清楚 程式 是一步一步地操控電腦的指令, 寫程式 是你在一步一步教電腦執行你需要它完成的工作 (如果執行結果錯了, 是你沒有把它教好喔! 別踹它, 沒有用的)

程式設計課程 首頁

製作日期: 08/31/2012 by 丁培毅 (Pei-yih Ting)
E-mail: pyting@mail.ntou.edu.tw TEL: 02 24622192x6615
海洋大學 電機資訊學院 資訊工程學系 Lagoon