2016年5月3日 星期二

給新手的C++教學 (上冊) - 5. 迴圈 (Loop)

回到「給新手的C++教學 (上冊)」

上一章

有時候,你希望某部分的程式碼重複執行3次
利用前四章所學,你可能會選擇把程式碼複製成3倍

但是,如果你希望這部分的程式碼執行500次呢?
如果你可以很有有耐心的進行「複製、貼上」的動作,這可能還不成問題
如果你希望這部分的程式碼是永遠的重複執行下去,直到我們手動把程式關掉呢?
亦或者你可以做到「輸入一個數字,這個數字是多少,程式就會重複執行多少次」嗎?

別擔心,以上的問題可以用一個很輕鬆的方法一次搞定!
換句話說,我們又有新朋友要認識啦~

它就是「while (當......的時候)」
用法如下:

while(繼續重複執行的條件)
{
    需要被重複執行的程式碼
}

因此,就算你不是高斯,你也可以輕鬆地寫出一個程式來計算「1+2+3+......+100」的結果!

#include<cstdio>
int main()
{
    int answer=0;
    int a=1;
    while(a<=100)
    {
        answer=answer+a;
        a=a+1;
    }
    printf("%d\n",answer);
    return 0;
}

程式輸出「5050」了!
你可能會對「=」的用途感到陌生 (雖然說之前有用過「int a=1;」之類的東西)
千萬別和「==」搞混了
「=」的作用是把左邊變數的值「設定成」右邊的數字
「==」是「判斷」左邊的數字和右邊的數字有沒有相等
雖然奇怪,但是習慣了就好,以後會很常用到的 ^_^

這種會被重複執行的程式碼,我們稱作「迴圈 (loop)」
還有另一種迴圈叫做「for」,雖然說「while」迴圈已經可以實現「for」迴圈的所有功能
但是「for」迴圈的獨特寫法,讓我們能夠更容易了解這個迴圈執行的事情
之後的進階章節將介紹這種神奇迴圈的用法 (但還是建議先照著順序讀完本教學)

當while中「繼續重複執行的條件」永遠成立時,程式就會永遠的重複執行下去直到天荒地老
這種情況我們稱之為「無窮迴圈 (infinite loop)」
當然,這不會太常用到,畢竟我們通常會希望程式會自己判斷甚麼時候要自己結束,而不是依賴使用者自己去按右上角的「X」按鈕來關閉程式
當你學會了怎麼製作「表單 (Form)」後,你可能會發現,當你的程式進入「無窮迴圈」時,有時候會導致程式「停止回應」(雖然說導致程式「停止回應」的原因不一定是如此)
因為這時程式已經不會再理會使用者的操作,而是專注於重複執行某一段程式碼
使用「多線程 (multithreading)」技術可以避免程式因此停止回應,但這已經遠遠超出本教學的範圍
「表單就是外觀有設計過的程式,而不是單純的「輸入和輸出文字」
相對於「表單」,這種看起來只有黑色背景、上面只會顯示文字的程式,我們稱作「終端機 (Terminal)」
這種程式比較容易製作,也就是我們現在使用C++寫的程式
當然,用C++也可以寫出「表單」

以下程式碼可以讓你體驗一下「無窮迴圈」:


#include<cstdio>
int main()
{
    int a=1,b=1;
    while(a==b)
    {
        printf("永遠的執行下去\n");
    }
    return 0;
}

程式會永遠的執行下去,永不停止
當while中「繼續重複執行的條件」一開始就不成立時,迴圈內的程式碼就不會被執行 (這樣也是一種迴圈)
這種事是有可能發生的,因為有時候我們會希望在某個條件下,程式碼會被執行0次
例如以下題目中「n=0」時的情況:
輸入一個整數n (不能是負數),請輸出「1+2+3+......+(n-2)+(n-1)+n」的結果
也就是輸出$\sum_{k=1}^{n}k$

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    int answer=0;
    int a=1;
    while(a<=n)
    {
        answer=answer+a;
        a=a+1;
    }
    printf("%d\n",answer);
    return 0;
}

現在,綜合五章所有知識,該來點有挑戰性的了
請你利用程式實現:輸入一個整數n,請找出n的所有因數,並把所有因數輸出,一個因數輸出一行
趕快動手試試看吧!

你挑戰成功了嗎?

參考解答:

#include<cstdio>
int main()
{
    int n;
    scanf("%d",&n);
    int factor=1;
    while(factor<=n)
    {
        if(n%factor==0)
        {
            printf("%d\n",factor);
        }
        factor=factor+1;
    }
    return 0;
}

另外,你有辦法自己寫一個程式,「找出1000以內的所有質數」嗎?

#include<cstdio>
int main()
{
    int n=2;
    while(n<=1000)
    {
        int is_prime_number=1;
        int a=2;
        while(a<n)
        {
            if(n%a==0)
            {
                is_prime_number=0;
                break;
            }
            a=a+1;
        }
        if(is_prime_number==1)
        {
            printf("%d\n",n);
        }
        n=n+1;
    }
    return 0;
}

好多質數XD

細心的讀者可能會注意到一個不尋常的地方:「break」是甚麼?
其實它的功用很簡單,就是「立即跳出迴圈」
你可能會懷疑:break明明就寫在if裡面啊,哪來的迴圈?
但是break很聰明,它會找到離自己最近的那個迴圈,並跳出那「一個」迴圈 (注意,一次只能跳出「一個」迴圈哦)
在找質數的這個例子,我們只要一確定n不是質數 (找到n的一個因數),迴圈就可以不用繼續執行了
因此可以直接使用「break」跳出迴圈
例如以下程式碼:

#include<cstdio>
int main()
{
    int a=0;
    while(a<=10)
    {
        if(a==4)
        {
            break;
        }
        a=a+1;
    }
    printf("%d\n",a);
    return 0;
}

是「4」耶!

會輸出「4」

是不是很想自己玩玩看呢?

下一章

感謝:
(版權所有 All copyright reserved)

18 則留言:

  1. 請問找1000以內的質數我這樣寫對嗎

    #include <iostream>
    using namespace std;
    int main(int argc, char **argv)
    {
        int i, j, n;

        for (i = 1; i <= 1000; i++)
        {
            n = 0;
            for (j = 1; j <= i; j++)
            {
                if (i % j == 0)
                n++;
            }
        if (n == 2)
            cout << i << endl;
        }
    }

    回覆刪除
    回覆
    1. 哈囉~教學中已提供範例程式碼,可以比對看看您的程式碼和範例程式碼的輸出有沒有一樣哦
      如果前面幾十個都對了,後面應該也沒問題~
      如果真要檢查全部的數字,而不消耗眼力,是可以請電腦來幫忙的哦!
      Windows有提供一個方便的指令:FC,可以用來比較兩個檔案的內容是不是一模一樣,可以跟這篇「檔案處理」所傳授的技巧配合著使用哦~

      關於FC,網路上已經有諸多使用教學了,關鍵字:「windows FC 用法」

      By the way並不是小莫不想幫您檢查程式碼,請見諒~與其給魚吃,不如教如何釣魚,對吧?XD有問題歡迎再問哦~

      刪除
    2. 好喔謝謝~~

      可是FC不是用來比較兩個檔案的嗎?
      這樣程式碼執行要怎麼比較兩個執行檔呢??

      刪除
    3. 所以才說要搭配「檔案處理」的技巧呀XD
      把輸出變成一個檔案~~

      刪除
  2. 問了一個問題不見了QQ

    回覆刪除
  3. 想請問一下
    我要輸入一些數字找出最大的兩數
    若以三數為例
    為何我如果程式沒有加註解那段
    比如我依序輸入9、8、9
    最大跟第二大都會是9
    可是我while迴圈裡沒有判斷number=前兩項最大值的情況
    意思不是指如果當number=前兩項最大值時,不會執行任何動作嗎,應該結果會跟原本前兩項做完的結果一樣不是嗎?
    以下是我的code

    #include <iostream>
    #define N 3
    using namespace std;

    int main(int argc, char** argv)
    {
        int number;
        int largest;
        int secondlargest;
        int counter = 3;

        cout << "Please imput a number: ";
        cin >> number;
        largest = number;

        cout << "Please imput a number: ";
        cin >> number;
        if (number > largest)
        {
            secondlargest = largest;
            largest = number;
        }
        else
        {
            secondlargest = number;
        }

        while (counter <= N)
        {
            cout << "Please imput a number: ";
            cin >> number;

            if (number > largest)
            {
                secondlargest = largest;
                largest = number;
            }
            /*else if (number == largest)
            {
                largest = largest;
                secondlargest = secondlargest;
            }*/
            else if (number >= secondlargest)
                secondlargest = number;

            counter++;
        }

        cout << "\nThe largest number is: " << largest;
        cout << "\nThe second largest number is: " << secondlargest;

        return 0;
    }

    回覆刪除
    回覆
    1. 前面一開始第二個數似乎也是一樣
      若我依序輸入9、9、8
      最大跟第二大也都會是9
      應該也是沒有判斷輸入=最大值的情況
      所以像這種問題是都要判斷嗎??

      刪除
    2. 我最後把程式修改成這樣
      不知道有沒有比較正確呢?

      #include <iostream>
      #define N 10
      using namespace std;

      int main(int argc, char** argv) 
      {
          int number;
          int largest;
          int secondlargest;
          int counter = 3;
          
          cout << "Please imput a number: ";
          cin >> number;
          largest = number;
          
          cout << "Please imput a number: ";
          cin >> number;
          if (number > largest)
          {
              secondlargest = largest;
              largest = number;
          }
          else if (number == largest)
          {
              largest = largest;
              secondlargest = 0;
          }
          else
          {
              secondlargest = number;
          }
          
          while (counter <= N)
          {    
              cout << "Please imput a number: ";
              cin >> number;
          
              if (number > largest)
              {
                  secondlargest = largest;
                  largest = number;
              }
              else if (number == largest)
              {
                  largest = largest;
                  secondlargest = secondlargest;
              }
              else if (number >= secondlargest)
                  secondlargest = number;

              counter++;
          }
          
          cout << "\nThe largest number is: " << largest;
          cout << "\nThe second largest number is: " << secondlargest;
          
          return 0;
      }

      刪除
    3. 如果看純看程式碼,要判斷是否正確無誤是非常困難也極具挑戰的,即使對小莫來說也一樣XD
      建議想一些不同的輸入測試看看,或者在某個online judge找到對應的題目上傳您的程式碼看看有沒有AC (Accepted),這是最快也最準確的方法之一哦~
      目測您的程式碼應該是OK的,不過不保證XD

      刪除
    4. 恩恩好的~~
      那我的問題是想問說

      如果我沒有判斷 輸入是否=最大值
      那輸入剛好=最大值時
      不是應該會沒有執行任何動作嗎
      (也就是維持前一動作設定好的最大值與第二大值)
      還是我的理解錯誤了呢??

      刪除
    5. 看您的「第二大值」的定義囉~
      如果是指數值上第二大,那不用執行任何動作沒錯
      如果是指挑出第二大的數字,那就是最大值有兩個就會讓最大和第二大相同囉(雖然數值相同,但因為是兩個數字,所以兩個都要算)
      依您的字面意思+小莫的個人主觀認定,應該是前者,不過每個人的理解都會有落差,應該說清楚、講明白

      刪除
    6. 恩恩是的
      比如說輸入9、9、8
      我是要挑出最大=9,第二大=8
      但是我的問題是
      如果依照我最開始的程式(亦即沒有判斷輸入是否等於最大值時)
      最大跟第二大會變成都是9


      而我是想問
      如果我沒有判斷 輸入是否=最大值
      那輸入剛好=最大值時
      不是應該會沒有執行任何動作嗎
      (因為我程式沒有寫到這個條件)

      所以也就是維持前一動作設定好的最大值與第二大值
      (亦即輸入此數等同於沒輸入的意思)
      (舉例:輸入9、8、9、7,在第三次輸入第二個9時,因為沒有寫判斷輸入是否等於最大值,而剛好輸入等於最大值,因此不執行任何動作,維持第二大值為8)
      (亦即「不需」寫入判斷相等的code)

      但是事實是跑程式時
      若沒有寫判斷相等的code
      會錯誤

      這是為什麼呢?
      是我把C語言的邏輯理解錯誤了嗎?

      刪除
    7. 不知道您懂不懂我的意思呢QQ

      刪除
    8. 請問您有沒有嘗試過到處printf(或cout)看看哪一段程式碼被執行到呢?

      刪除
    9. 也許會試出意料之外的結果哦~(?)XD

      刪除
  4. 網誌管理員已經移除這則留言。

    回覆刪除

歡迎留言或問問題~
若您的留言中包含程式碼,請參考這篇
如果留言不見了請別慌,那是因為被google誤判成垃圾留言,小莫會盡快將其手動還原