# Ch6 for迴圈
> 搭配[green judge解題系統](http://www.tcgs.tc.edu.tw:1218/)
> Special thanks to [台中女中sagit老師](http://www.tcgs.tc.edu.tw/~sagit/index.htm) \<\(\_ \_\)\>
##
> 上一章:[while迴圈](https://hackmd.io/s/Sk3nDNsiZ)
> 下一章:[雜項:其他資料型態、函式庫、格式化輸出](https://hackmd.io/s/r1QbUam6b)
> 回目錄:[國立科學園區實驗中學C++程式語言自學講義](https://hackmd.io/s/B18yT_i5Z)
## <font color='darkblue'>For迴圈的用途</font>
在上一單元
我們學會了while迴圈
再次複習一次while迴圈的使用時機
1.某段程式要一直**重複執行**
2.預先不知道要重複幾次,而是藉由**判斷某個條件**來決定該結束了沒
for迴圈則跟while迴圈非常相似
它的使用時機為
1.某段程式要一直**重複執行**
2.一開始就已知要重複幾次,所以只要**判斷執行幾次了**就知道該結束了沒
例如:
印出100個"Hello"
算出某個數字的某次方
算出某個數字的階乘...等等
## <font color='darkblue'>For迴圈的寫法</font>
由於在使用for迴圈時需要計算「迴圈執行幾次了」
所以需要另外使用一個變數來作為「計數器」
通常我們習慣將這個計數器的名稱取作 i 或 j 或 k
而這個計數器主要有三件任務
1.一開始先設定一個起始值
2.設一個檢查條件,每執行一次迴圈就檢查它還符合條件嗎(還符合才能繼續跑迴圈)
3.每執行一次迴圈就將計數器變動一下,例如加一
舉例來說,想要一個迴圈總共執行10次(i從0跑到9)的話
1. i 的起始值是0
2. 檢查條件為 i<10 (或i<=9)
3. 每次迴圈都將i加一
而這三件任務就分別被寫在for迴圈的三個格子裡
像是
```cpp=
int i; //宣告一個計數器
for ( i=0 ; i<10 ; i=i+1 ) //i從0開始;檢查是否還<10;每次加1
{
//要重複執行的程式
}
```
for迴圈的架構如下:
先寫一個for,並且在後面接上一個小括弧()
小括弧內用分號分成3格,分別寫上(計數器=初始值;檢查計數器是否符合條件;改變計數器的值)
接著一個大括號
裡面放入的就是要重複執行的程式
註:`i=i+1`可以簡化成`i++`
`i=i-1`也可以簡化成`i--`
因為for迴圈實在是太常寫到`i=i+1`或`i=i-1`了
為了方便,以下的範例程式皆會將它寫成`i++`以及`i--`
<font color='darkorange'>【例題】</font>
>輸入一個n,輸出n個"Hello"
>例如n為3時,輸出
>Hello
>Hello
>Hello
本題的範例程式如下
```cpp=
int n, i;
cin>>n;
for(i=0;i<n;i++) //歸零;檢查到n次了沒;每次+1
{
cout<<"Hello"<<endl;
}
cout<<endl; //最後加個換行符號
```
這樣的程式其實等效於
```cpp=
int n, i;
cin>>n;
i=0; //歸零
while(i<n) //檢查到n次了沒
{
cout<<"Hello"<<endl;
i=i+1; //每次+1
}
cout<<endl;
```
for迴圈和while迴圈完全是可以等效轉換的
如果你忘記其中一種怎麼寫,改寫另一種也是可以的
但因為各自有適合的用途
所以還是建議在適合的情況下使用適合的迴圈
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a026: 一千遍我愛你 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a026)
## <font color='darkblue'>將計數器的值印出來</font>
當然,計數器本身的值也可以拿來用
<font color='darkorange'>【例題】</font>
>輸入一個n,輸出從1到n的數字
這題可以寫成
```cpp=
int n, i;
cin>>n;
for(i=1;i<=n;i++){
cout<<i<<endl;
}
```
計數器不只可以順著數,當然也可以倒著數
<font color='darkorange'>【例題】</font>
>輸入一個n,輸出從n到1的數字
這題可以寫成
```cpp=
int n, i;
cin>>n;
for(i=n;i>=1;i--){
cout<<i<<" ";
}
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a027: 倒數計時 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a027)
> 注意:它是要印完一個數字空一格,不是換行喔
## <font color='darkblue'>將計數器的值拿來加減乘除</font>
計數器的值除了可以被印出來
也可以拿來當成運算時的材料
例如每次都把答案加上或乘上目前計數器的值
注意:計數器的值可以拿來當成別的變數運算時的材料
但是最好不要在運算時改動到計數器的值
否則會造成邏輯混亂
<font color='darkorange'>【例題】</font>
>輸入一個n,輸出1至n的和
我們已經知道和的公式是 $\frac{n(n+1)}{2}$
那麼就來試試看用迴圈算平方和是不是和用公式算的一模一樣
既然要算"和"
可以用一個變數來代表目前的和是多少
每次都將目前的和去加上目前計數器平方的值
```cpp=
int n, i, answer;
cin>>n;
answer = 0; //和一開始為0
for(i=1;i<=n;i++)
{
answer = answer+i; //加上計數器的值
}
cout<<answer<<endl;
//可以檢查是不是跟用公式算的一樣
if(answer == n*(n+1)/2)
cout<<"YA!"<<endl;
```
<font color='darkorange'>【例題】</font>
>輸入一個n,輸出n的階乘
既然要算階乘
可以先用一個變數來當成目前的積
然後每次都將目前的積乘上目前計數器的值
```cpp=
int n, i, answer;
cin>>n;
answer = 1; //積一開始為1 (為什麼?)
for(i=1;i<=n;i++){
answer = answer*i;
}
cout<<answer<<endl;
```
## <font color='darkblue'>計數器從特定數字開始計</font>
在以上的例子中
我們所用到的計數器,要不就是先歸零,要不就是從1開始
但其實它不管想從幾開始計都是可以的
<font color='darkorange'>【例題】</font>
>輸入n和m,輸出從n至m的所有整數(包含n與m)
這題可以讓計數器從n開始,到m結束
範例程式如下
```cpp=
int n,m,i;
cin>>n;
cin>>m;
for(i=n;i<=m;i++) //i從n開始;檢查i超過m了沒;i每次都+1
{
cout<<i<<endl;
}
```
<font color='darkorange'>【例題】</font>
> 輸入兩個數字a, b
> 輸出$a*(a+1)*(a+2)*(a+3)*...*(b-2)*(b-1)*b$ 的值
```cpp=
int a, b, i, ans;
cin >> a >> b;
ans=1;
for(i=a;i<=b;i++){
ans = ans*i;
}
cout << ans;
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a028: P(N,R) ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a028)
<font color='darkorange'>【例題】</font>
>輸入n和m,輸出從n至m的所有整數,兩兩整數間請用\"\~\"來連接
>例如n為2,m為5時,即輸出2\~3\~4\~5
這個題目有一個小麻煩
就是每個數字前面都要加上一個飄號\~
但唯獨第一個數字前面不能加
這邊提供其中一種解決方法:把第一個數字(n)獨立出來,而迴圈的計數器則從n+1開始
```cpp=
int n, m, i;
cin>>n;
cin>>m;
cout<<n; //先單獨印出第一個數字n
for(i=n+1;i<=m;i++) //計數器從n+1開始
{
cout<<"~"<<i; //印出飄號跟i
}
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a029: 連續整數相加(一) ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a029)
## <font color='darkblue'>組合技:for與if搭配使用</font>
迴圈裡面還可以再做條件判斷
寫法就和一般的條件判斷相同
<font color='darkorange'>【例題】</font>
>輸入n,輸出n所有的因數
要判斷一個數字i是否為n的因數,可以判斷n除以i的餘數是否為零,即`n%i==0`
```cpp=
int n, i;
cin>>n;
for(i=1;i<=n;i++)
{
if(n%i==0)
cout<<i<<endl;
}
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a044: 盈數、虧數和完全數 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a044)
相同的程式也可以拿來判斷n是不是質數
可以再用一個變數來計算n有幾個因數
如果因數的數量為0,就可以確定n是質數 (1與n除外,因為一定有這兩個因數)
不過i的範圍要注意:
1.i要從2開始,因為1不用檢查
2.i超過根號n時就可以停了 <font color='red'>(為什麼?)</font>
不過根號n的寫法有點麻煩(下一章會教到)
因此你可以不要判斷 $i\le\sqrt n$
而是改成判斷 $i*i\le n$
```cpp=
int n, i, cnt;
cin>>n;
cnt=0;
for(i=2;i*i<=n;i++)
{
if(n%i==0)
cnt++;
}
if(cnt>0) cout<<"Not Prime"<<endl;
else cout<<"Prime"<<endl;
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a045: 質數判斷 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a045)
## <font color='darkblue'>組合技:迴圈裡面還有迴圈</font>
<font color='darkorange'>【例題】</font>
>輸入n和m,輸出n行的m個飄號
>例如n為3,m為5時,輸出
>\~~~~~
>\~~~~~
>\~~~~~
我們已經知道印出一行m個飄號可以這樣寫
```cpp=
for(i=0;i<m;i++)
{
cout<<"~";
}
cout<<endl;
```
而現在需要將這樣的飄號印出n行來
也就是上面那一段程式要被執行n次才夠
因此可以把上面那一整段程式
再包進一個會被執行n次的迴圈裡
由於i已經被拿去當成剛才的迴圈的計數器了
為了避免衝突
我們要再宣告一個新的計數器:j
因此程式可以寫成
```cpp=
for(j=1;j<=n;j++)
{
for(i=1;i<=m;i++)
{
cout<<"~";
}
cout<<endl;
}
```
(不過通常i會放在外圈,j會放在內圈,通用習慣問題而已)
請記得,像這樣的「迴圈包迴圈」,並不是一個新的語法概念
就只是單純把一個迴圈寫在另一個迴圈裡而已
寫法規則都沒什麼差別
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a046: 巧克力工廠 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a046)
<font color='darkorange'>【例題】</font>
>輸入n,輸出高和寬為n的等腰直角三角形
>例如n為4時,輸出
>\~
>\~~
>\~~~
>\~~~~
這題可以直接拿上一題的程式來用
唯一不一樣的地方是
內層迴圈的計數器,並非數到n,而是改成數到**外層計數器**的值
```cpp=
for(j=1;j<=n;j++)
{
for(i=1;i<=j;i++) //注意,這邊的檢查值改成i<=j囉
{
cout<<"~";
}
cout<<endl;
}
```
> <font color="darkgreen"> 【學生練習題】</font>
> - [ ] [Green Judge a047: 數字三角形 ](http://www.tcgs.tc.edu.tw:1218/ShowProblem?problemid=a047)
## <font color='darkblue'>補充語法</font>
### break
在迴圈內遇到`break`時,不管怎樣,直接離開迴圈
<font color='darkorange'>【例題】</font>
>輸入n,輸出大於等於n的第一個5的倍數
(這例子舉得不好,但為了淺顯易懂,還是用這個例子吧)
計數器從n開始數到n+5 (因為這之間一定有5的倍數)
一旦遇到5的倍數並輸出它之後
迴圈就可以直接結束,不用再繼續往下跑了
因此可以使用`break`
```cpp=
for(i=n;i<=n+5;i++)
{
if(i%5==0){
cout << i <<endl;
break;
}
}
```
雖然i不一定有超過n+5
不過一旦它遇到break,還是會直接結束迴圈
### continue
在迴圈內遇到`continue`時,不管怎樣,直接進入下一圈
<font color='darkorange'>【例題】</font>
>輸入n,輸出1至n之間所有5的倍數
這題你可以使用if來檢查i是否為5的倍數,如果是,則輸出
但你也可以不使用if,而利用continue來控制流程
比方說
在印出i之前,先檢查i是不是5的倍數
如果不是,那就直接continue進入下一輪迴圈
```cpp=
for(i=1;i<=n;i++)
{
if(i%5!=0)
continue;
cout<<i<<endl;
}
```
break和continue都不是絕對必要的語法
都可以用其他的寫法來代替
但是在適合的情況下若能善用break和continue
可以讓你寫程式更有效率、有邏輯
##
> 上一章:[while迴圈](https://hackmd.io/s/Sk3nDNsiZ)
> 下一章:[雜項:其他資料型態、函式庫、格式化輸出](https://hackmd.io/s/r1QbUam6b)
> 回目錄:[國立科學園區實驗中學C++程式語言自學講義](https://hackmd.io/s/B18yT_i5Z)