Copyright(C) 13Jan2003 coskx
このページでは「処理の繰り返し」の記述方法を解説する。
ここで修得して欲しい内容は次の通りである。
1.forループの基本的な制御構造がわかりプログラムを追跡できる。
2.forループにおけるカウンタ変数の役割が理解できる。(ループを抜け出したときのカウンタ変数の値もわかる)
3.2重のforループを追跡できる。
4.forループを用いた連続加算プログラムが書ける。
5.whileループを追跡できる。
6.do-whileループを追跡できる
7.ループ中の合計計算,変数順送り操作が追跡できる。
8.ループのプログラムが書ける。
9.定回数二重ループプログラムが書ける。
10.内側ループ回数が外側ループ回に応じて変わる二重ループプログラムが書ける
2.1 forループ
同じような処理を何度も繰り返す場合には繰り返しの記述が使われる。
特にプログラミング時に何回繰り返すのかわかっている場合にはforループで記述されることが多い。
まずは復習から。
次のプログラムでは,1行の英文メッセージを表示している。
List 2.1.1 1行の英文メッセージの表示 |
#include <stdio.h> int main() { printf("A child says, "); printf("\"The king is naked.\"\n"); return 0; } |
実行結果 |
A child says, "The king is naked." |
次のプログラムでは,同じ英文メッセージを5回表示している。
List 2.1.2 1行の英文メッセージの5回表示 |
#include <stdio.h> int main() { printf("A child says, "); printf("\"The king is naked.\"\n"); printf("A child says, "); printf("\"The king is naked.\"\n"); printf("A child says, "); printf("\"The king is naked.\"\n"); printf("A child says, "); printf("\"The king is naked.\"\n"); printf("A child says, "); printf("\"The king is naked.\"\n"); return 0; } |
実行結果 |
A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." |
List 2.1.2と同じことをforループを使って表してみよう。
通常の日本語表現では,
「~~~~」を5回表示しなさい。
となるが,プログラムでは,次のような表現になる。
次のことを5回行いなさい。{
「~~~~」を1回表示しなさい。
}
この表現に変換してから,プログラムを作成することになる。
次のプログラムはList 2.1.2をforループを用いて書き直したものである。
List 2.1.3 forループ |
#include <stdio.h> |
実行結果 |
A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." A child says, "The king is naked." |
補足 |
for (i=0; i<5
;i++) |
通常の日本語とC言語の表現との対応は次のように考えられる。
日本語での表現の例 | C言語風表現の例 | C言語のキーワードを用いた表現の例 |
運動場を5周廻りなさい。 |
次のことを5回行ないなさい{ |
int i; |
「王様は裸だ」と5回表示しなさい。 |
次のことを5回行ないなさい{ |
int i; |
練習2.1 |
次の「List 2.1.4」は繰り返し処理中で繰り返しを制御する変数「i」の値を表示させたものである。
字下げの深さ(8スペース)が,これまでと違うことに気を付けよう。
List 2.1.4 forループ |
#include <stdio.h> |
実行結果 |
(0) A child says, "The king is naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." |
補足 |
1.「i++」の意味 2.繰り返し処理の仕組み
3.繰り返し処理のイメージ 4.記述上の注意
|
補足その2 |
ループ回数を数えるカウンタの役割を果たす変数名はなんでも良い。 #include <stdio.h> int main() { int arere; for (arere=0; arere<5; arere++) { printf("(%d) ", arere); printf("A child says, "); printf("\"The king is naked.\"\n"); } return 0; } |
for文を導入する考え方
(この考え方は,自分でプログラムを書く際に大事)
ループ回数の指定の仕方 どのような指示方法でも困らないようにしよう。
次の3つのプログラムとその実行結果から,ループの制御範囲とプログラムの関係を確認しよう。
printfがループ内に書かれているのか,ループ外に書かれているのかで,実行結果は異なる。
#include <stdio.h> int main() { int i; printf("Hello.\n"); for (i=0; i<5; i++) { printf("(%d) ", i); printf("A child says, "); printf("\"The king is naked.\"\n"); } printf("That's all.\n"); return 0; } |
Hello. (0) A child says, "The king is naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." That's all. |
#include <stdio.h> int main() { int i; for (i=0; i<5; i++) { printf("Hello.\n"); printf("(%d) ", i); printf("A child says, "); printf("\"The king is naked.\"\n"); } printf("That's all.\n"); return 0; } |
Hello. (0) A child says, "The king is naked." Hello. (1) A child says, "The king is naked." Hello. (2) A child says, "The king is naked." Hello. (3) A child says, "The king is naked." Hello. (4) A child says, "The king is naked." That's all. |
#include <stdio.h> int main() { int i; for (i=0; i<5; i++) { printf("Hello.\n"); printf("(%d) ", i); printf("A child says, "); printf("\"The king is naked.\"\n"); printf("That's all.\n"); } return 0; } |
Hello. (0) A child says, "The king is naked." That's all. Hello. (1) A child says, "The king is naked." That's all. Hello. (2) A child says, "The king is naked." That's all. Hello. (3) A child says, "The king is naked." That's all. Hello. (4) A child says, "The king is naked." That's all. |
Cプログラミングスタイル (字下げ,インデント) |
![]() |
字下げ(インデント)のルール |
(1) 中かっこ始まり「{」があったら次の行から字下げする。 (2) 中かっこ終わり「}」があったら次の行から字下げを戻す。 (3) 中かっこ終わり「}」の字下げ高さは,対応する中かっこ始まり「{」のあった行の字下げ高さと等しい。 |
練習2.2 |
次のプログラムの実行結果を予想しなさい。
List 2.1.5 forループのプログラム | ||
#include <stdio.h> | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
(0) A child says, "The king is
naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." |
(0) A child says, "The king is
naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." (5) A child says, "The king is naked." |
0 A child says, "The king
is naked." 1 A child says, "The king is naked." 2 A child says, "The king is naked." 3 A child says, "The king is naked." 4 A child says, "The king is naked." 5 A child says, "The king is naked." |
追加説明 「i<=5」は数学では「i≦5」である。「i=<5」の表現は許されない。 |
練習2.3 |
List 2.1.6 forループのプログラム | ||
#include <stdio.h> | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
(0) A child says, "The king is
naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." just after the loop i=4 |
(0) A child says, "The king is
naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." just after the loop i=5 |
(0) A child says, "The king is
naked." (1) A child says, "The king is naked." (2) A child says, "The king is naked." (3) A child says, "The king is naked." (4) A child says, "The king is naked." just after the loop i=0 |
コンピュータは,プログラム全体の意味を理解して動いているわけではなく,現在実行しているプログラム行の命令と,変数に格納された値しか理解していない。 直前の命令が何だったのか,次の命令は何なのかは知らずに現在実行しているプログラム行の命令を行っている。 ループ中の命令を実行しているのか,ループの外の命令を実行しているのかも知らずに現在実行しているプログラム行の命令を行っている。 |
(1)以下に示すx,x2,x3の表を1≦x≦100で出力するプログラムを作りなさい。 (p02ex01.c)
変数xをカウンタとするforを使ったプログラムとし,変数はx,x2(x2の格納用),x3(x3の格納用)の3つだけを用いなさい。x2,x3はxをもとにして作りなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d
%5d %7d\n", x, x2, x3);」にすること。
x x^2 x^3 |
(2)以下に示すx,y(y= 5x),y2,y3,y4の表を1≦x≦100で出力するプログラムを作りなさい。(p02ex02.c)
変数xをカウンタとするforを使ったプログラムとし,変数はx,y,y2(y2の格納用),y3(y3の格納用),y4(y4の格納用)の5つだけを用いなさい。yはxから算出し,y2,y3,y4はyをもとにして算出しなさい。
またprintf文はforループの前に1つ,forループの中に1つだけ使いなさい。
forループ中のprintf文は「printf("%3d
%3d %6d %9d
%12d\n", x, y, y2, y3, y4);」にすること。
実行結果をよく見ると変なことに気づくかもしれない。
どうして変になるのか友人と話し合い考察しなさい。
(ヒント int型整数で扱うことのできる値には限りがある)
x
y y^2 y^3 y^4 |
(3)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをもとにして,y1,y2,y3,y4を計算し,以
下に示す表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。forループ中のprintf文は
「printf("%4d
%4d %4d %4d
%6d\n", x, y1, y2, y3, y4);」にすること。
(p02ex03.c)
ただし,xの範囲は1≦x≦100としなさい。
ヒント y4の計算ではxの値を1,2,3,4・・・と変化させると5*x*xの値はどのように変化するか考えなさい。
x
y1 y2 y3 y4 |
(4)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中でxをもとにして,y1,y2,y3を計算し,以下の表を作りなさい。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。(p02ex04.c)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x%3」と「x%4」の値はどのように変化するか考えなさい。
x y1 y2 y3
0 0 0 0
1 1 1 1
2 0 2 2
3 1 0 3
4 0 1 0
5 1 2 1
6 0 0 2
7 1 1 3
8 0 2 0
9 1 0 1
:
(5)int型変数xをループカウンタとしてforを使ったプログラムで,ループ中にy1,y2,y3を作り,以下の表を作りなさい。y1は2回,y2
は3回,y3は4回同じ値を繰り返している。printf文はforループの前に1つ,forループの中に1つだけ使いなさい。(p02ex05.c)
ただし,xの範囲は0≦x≦100としなさい。
ヒント xの値を1,2,3,4・・・と変化させると「x/3」と「x/4」の値はどのように変化するか考えなさい。
x y1 y2 y3
0 0 0 0
1 0 0 0
2 1 0 0
3 1 1 0
4 2 1 1
5 2 1 1
6 3 2 1
7 3 2 1
8 4 2 2
9 4 3 2
:
まずは,画面上に
**********
**********
**********
**********
**********
を表示してみよう。
「**********(改行)」を5回書くのだから,
printf("**********\n"); ←「**********」を表示して改行しなさい
printf("**********\n"); ←「**********」を表示して改行しなさい
printf("**********\n"); ←「**********」を表示して改行しなさい
printf("**********\n"); ←「**********」を表示して改行しなさい
printf("**********\n"); ←「**********」を表示して改行しなさい
とすれば,良いのだが,行数をあとで変更できるように,for文に書き直してみよう。
for (i=0; i<5; i++) { ← 次のことを5回繰り返しなさい
printf("**********\n"); ←「**********」を表示して改行しなさい .....(A)
}
のようになる。5行のプログラムが3行になった。
ここで,1行に表示する「*」の個数をあとで変更できるように,
printf("**********\n"); ←「**********」を表示して改行しなさい .....(A)
をfor文で書き直してみよう。
1行だった命令が4行になったが,プログラムの柔軟性(あとで変更することができる)のため,必要なことである。for (j=0; j<10; j++) { ← 次のことを10回繰り返しなさい
printf("*"); ←「*」を(1つ)表示しなさい
}
printf("\n"); ← 改行しなさい
次の青字の部分を5回繰り返しなさい {上記の言葉でまとめたプログラムは,ループの中にループを持っている。
次のことを10回繰り返しなさい {
「*」を(1つ)表示しなさい
}
改行しなさい
}
List 2.2.1 「10この「*」を書いて改行する」という作業を5回行うプログラム | |
#include <stdio.h> | |
実行結果 | |
********** ********** ********** ********** ********** | |
カッコの対応を確認しよう。 各行の先頭がどこから始まっているのか,その規則をみつけなさい。 「字下げ,インデント(行の先頭に空白を挿入して,行の記述を右にずらすこと)」の規則 | |
#include
<stdio.h>
} |
二重ループの通常の言葉による言い回しとの変換は次のように考えられる。
言葉による言い回しでの表現の例 | C言語風表現の例 | C言語のキーワードを用いた表現の例 |
運動場を5周廻りなさい。 その際,運動場を1周廻るたびに 「私は無敵だ」と3回唱えなさい。 (結局「私は無敵だ」は15回唱え ることになる) |
次のことを5回行ないなさい{ |
int i,j; |
『「*」を10個書き,改行する』 という作業を5回行ないなさい。 (結局,*を50個書くことになる) |
次のことを5回行ないなさい{ |
int i,j; |
練習2.4 |
List 2.2.2 | ||
#include <stdio.h> | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
* ** *** **** ***** |
** *** **** ***** ****** |
********** ********** ********** ********** ********** |
練習2.5 |
List 2.2.3 | ||
#include <stdio.h> | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
/**** //*** ///** ////* ///// |
***** / **** // *** /// ** //// * |
***** /**** //*** ///** ////* |
上の2つのプログラムはどのようにして出来たのか考えてみよう。
自分でこれらのプログラムを考えるときに必要となる考え方である。
自分で二重ループのプログラムを作る時の考え方 26May2003,23May2016追加
Cプログラミングスタイル 字下げ(インデント) |
![]() |
字下げ(インデント)のルール |
(1) 中かっこ始まり「{」があったら次の行から字下げする。 (2) 中かっこ終わり「}」があったら次の行から字下げを戻す。 (3) 中かっこ終わり「}」の字下げ高さは,対応する中かっこ始まり「{」のあった行の字下げ高さと等しい。 |
(6)正整数nをキーボードから入力し,nに応じて「*」で以下の模様を描くプログラムを作成しなさい。nは少なくとも79まで対応しなさい。(p02ex06.c)
検証はn=1,2,3,4,5,79で行ないなさい。
n=1
n=2
n=3
n=4
n=5
*
**
*****
***
*******
****
****
*********
*****
*****
*****
*****
ヒント プログラム側からすると,「人間から正整数値をもらって,整数型変数nに保存する」というのが最初に行うべき作業となる。
模様を書き始めてからnの値を確定するということはありえない。
「人間から正整数値をもらって,整数型変数nに保存する」はscanfを使う。
(7)正整数nを入力し,nに応じて「*」で以下の模様を描くプログラムを作成しなさい。nは79まで対応しなさい。(p02ex07.c)
検証はn=1,2,3,4,5,79で行ないなさい。 ヒント
n=1
n=2
n=3
n=4
n=5
*
**
****
**
*****
***
**
******
****
***
**
*
(8)2つの正整数rowとcolumnをキーボードから読み込み,「*」を用いて縦row個,横column個の長方形を描くプログラムを作りなさい。(p02ex08.c)
検証は以下の2例を行ないなさい。キーボードから読み込む2つの数は,実行例のようにスペースで区切って入力すること。 ヒント
<<実行例1>>
row,column= 3 5
*****
*****
*****<<実行例2>>
row,column= 6 7
*******
*******
*******
*******
*******
*******
(9)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。
nは79まで対応しなさい。(p02ex09.c)
検証はn=1,3,5,7,9,79で行ないなさい。
ヒント
n=1 |
n=3 |
n=5 |
n=7 |
n=9 |
* |
-*- |
--*-- |
---*--- |
----*---- |
(10)奇数(正整数で2で割ったあまりが1のもの)nを入力し,nに応じて「*」「-」で以下の模様を描くプログラムを作りなさい。nは79まで対応しなさい。
(p02ex10.c)
検証はn=1,3,5,7,9,79で行ないなさい。
n=1 |
n=3 |
n=5 |
n=7 |
n=9 |
* |
-*- |
--*-- |
---*--- |
----*---- |
(11)二重ループを用いて,九九の表を作りなさい。適当に空白を入れて乱れ(ずれ)がないようにして見やすくしなさい。
ただし,1行目と1列目はかける数,かけられる数を表示する。二重ループを用いること。
(p02ex11.c)
1 2 3 4 ..
1 1 2 3 4 ..
2
2 4 6 8 ..
3 3 6 9 12 ..
4
4 8 12 16 ..
: : : : :
(12)英国には12進法の影響で九・九ではなく十二・十二までの掛算表がある。(11)を改造して,これを作りなさい。
適当に空白を入れて表示に乱れがないようにして見やすくしなさい。二重ループを用いること。(p02ex12.c)
2.3 forループを用いた連続加算 |
---|
「List
2.3.1」は1+2+3+...+100と12+22+32+...+1002を求める計算である。
List 2.3.1 |
/*1から100までの単純和と1から100までの平方和*/ |
実行結果 |
i,sum,sum2=1 1 1 |
変数の初期化を忘れた失敗の例 27June2003追加
forループに関する補足(疑問点と誤りの例) 14May2003追加
(13)キーボードから10この正整数値をscanfで読み込み,合計値を表示するプログラムを作りなさい。
ただし,キーボードから読み込んだ値はint型変数xにしまわれるものとし,変数はこのxと回数を数えるint型変数countと合計値をしまうint型変数
sumのみを用いることとする。(p02ex13.c)
レポートの実行結果には次の3つの例を示しなさい。
(1)1,2,3,4,..
..8,9,10を入力して合計値55になるかどうか検証しなさい。
(2)11,12,13,14,..
..18,19,20を入力して合計値155になるかどうか検証しなさい。。
(3)123,321,234,432,345,543,456,654,567,765を入力して合計値4440になるかどうか検証しなさい。
(14)キーボードから10この正整数値をscanfで読み込み,合計値と平均値(小数第1位まで)を表示するプログラムを作りなさい。(p02ex14.c)
レポートの実行結果には次の3つの例を示しなさい。
(1)1,2,3,4,..
..,8,9,10を入力して合計値55,平均値5.5になるかどうか検証しなさい。
(2)11,12,13,14,..
..,18,19,20を入力して合計値155,平均値15.5になるかどうか検証しなさい。
(3)123,321,234,432,345,543,456,654,567,765を入力して合計値4440,平均値444.0になるかどうか検証しなさい。
キーボードから読み込んだ正整数値を2で繰り返し割って,割り切れる回数を求めるプログラムを考えよう。
例えば正整数値12は(12→6→3)2回,2で割り切ることが出来る。16は(16→8→4→2→1)4回,9は0回である。
2で割る動作は繰り返されるが,何回繰り返されるかは,プログラミング時には決めることが出来ないため,for文では
書くことができない。
ある条件が満たされている間,特定の処理を繰り返すという表現は,次のようなwhile文になる。
while (継続条件) {
繰り返し処理ブロック
}
人間なら,2通りのやり方があるだろう。
(1)1つは2での割り算を紙に書いていき,割り切れなくなったときに,それまで何回割り算を行なったかを数えればよい。
(2)もう1つは割り算を行ないながら,現在何回目の割り算かを数え,覚えておく。割り切れなくなった時,覚えていた回数が答えである。
コンピュータでこの作業を行なうときは,(2)のやり方が適している。人間が割り算回数を覚えておくことに対応させて,現在何回目の割り算かを覚えておく変数を導入し,最初に0を与え,割り算が可能だった時に1を加えればよい。
回数を数える用途に使われる変数はカウンタと呼ばれ,プログラミングでは大変重要な役割を果たす。
割り切れたかどうかは,割り算のあまりを出す演算を用いて,あまりが0であるかどうかを確かめるとよい。
むずかしいと感じた時は自分がコンピュータになったつもりで1行1行実行し,
各変数がどうなったか,継続条件判断は真か偽かを絶えず,判断しながら読み
進むこと。
List 2.4.1 numberは2で割ることが何回出来るか | ||||||
/*numberは2で割ることが何回出来るか*/ | ||||||
実行結果 (実行例を3つ示している) | ||||||
正整数を入力してください 120 | ||||||
説明 | ||||||
1.「(n%2==0)」はnを2で割ったあまりが0だったらの意味 2.繰り返し処理の仕組み この部分の制御の流れは次の順番で行なわれる。
|
このプログラムはどのようにして出来たのか考えてみよう。自分でこのプログラムを考える時,
あるいは課題の作業中に行き詰まった時は ここ を見なさい。 26May2003追加
練習2.6 |
List 2.4.2 | ||
/*1000以下のフィボナッチ数列*/ | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
1:1 2:1 3:2 4:3 5:5 6:8 7:13 8:21 9:34 10:55 11:89 12:144 13:233 14:377 15:610 16:987 |
1:1 |
1:1 2:1 3:2 4:3 5:5 6:8 7:13 8:21 9:34 10:55 11:89 12:144 13:233 14:377 15:610 16:987 17:1597 |
フィボナッチ数列とは次のような数列のことです
第1項と第2項の値が1で,第3項以降の項がそれ以前の2つの項の和である数列
a1 = 1, a2 = 1, an = an-1 + an-2
練習2.7 |
List 2.4.3 | ||
#include <stdio.h> | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
x=19 y=39 |
x=16 y=39 |
x=16 y=23 |
Cプログラミング学習者の1/4が最初にハマるwhileループのトラップ |
次のプログラムの実行結果を予想しなさい。
「x=10 y=10」になると思ったら,1/4側である!
#include <stdio.h>
int main()
{
int x,y;
x=10;
y=0;
while(y<5) {
y=y+x;
x=x+10;
}
printf("x=%d y=%d\n",x,y);
return 0;
}
誤った解釈
正しい解釈
もう一度流れ図でwhileループの部分を見てみよう。
継続条件が真であったら必ず,「y=y+x;」「x=x+10;」は実行される。誤った解釈にはならないはずである。
どうして誤った解釈が生ずるのか?
人間は,脱出条件を覚えてしまう。「y=y+x;」のところで,yが10になった瞬間に覚えていた脱出条件を適用して脱出するといった誤った解釈が生ずる。
コンピュータは,現在行っている1行のことだけに専念している。自分が現在実行中の行が,ループ内であるとかループ外であるとかは考慮することはできない。継続判断する行に行ったときだけ,判断して脱出することが出来る。
ここで自分が1/4側だったと自覚できた学習者は,「2.1 forループ」の練習2.3に戻って,forループでも同じ誤解をしていないか確認しよう,
「2.4.1」の例で,「正整数を入力してください」としているが,人間が誤って負の整数を入力しても,再入力を強制するような仕組みを考えよう。
人間は再入力を強制されても,何回も負の整数を入力するかもしれないので,粘り強く再入力を強制する仕組みにしよう。
このように,何か作業があって,その結果もう一回繰り返すかどうか判断する形式の繰り返し構造ではdo-while文を使う。
List 2.5.1 |
/*numberは何回2で割ることが出来るか*/ |
実行結果 |
正整数を入力してください -120 |
説明 |
繰り返し処理の仕組み 注意 while(...)の直後に「;」が必要 |
************* 余談 ************* お酒の飲み方とdo-whileループ
お酒を飲む時はwhileループで飲みましょう。(成人に達してからです。) |
練習2.8 |
List 2.5.2 | ||
#include <stdio.h> int main() | ||
実行結果の予想1 | 実行結果の予想2 | 実行結果の予想3 |
x=6 y=15 | x=5 y=14 | x=15 y=24 |
2.6 「処理の繰り返し」のまとめ |
---|
各ループの記述の特徴は次のとおりである。
ループの記述の種類 | ループ回数 | 1回目の処理 |
forループ | プログラミングあるいはループ起動の時点で既知 | 1度も処理を行なわないこともある |
whileループ | プログラミングあるいはループ起動の時点では未定 | 1度も処理を行なわないこともある |
do-whileループ | プログラミングあるいはループ起動の時点では未定 | 少なくとも1回は処理を行なう |
特に,whileループとdo-whileループの違いを次の2つの例で示す。
例 List 2.5.1 より
do { printf("正整数を入力してください "); scanf("%d", &number); } while (number<=0); |
この例では,必ず1回は処理を行なうはずなのでdo-whileループが使われる |
例 List 2.4.1 より
while (n%2==0) { n=n/2; counter++; printf("n=%d counter=%d\n", n, counter); } |
この例では,1回も処理が行なわれない可能性があるのでwhileループが使われる (対象が奇数だと1度も2で割リきることが出来ない) |
繰返し処理記述の時の考え方 ここを読んでください
2.7 追加説明 |
---|
ループに関する内容で説明してなかった内容を追加説明する。
内容 | |
1.forループ |
次のようなfor文がある |
2.forループとwhileループ |
次の2つのループは同じ意味となるが,この場合は繰り返し回数指定ループなので,
|
3.whileループとforループ |
次の2つのループは同じ意味となるがこの場合は条件ループなので,
|
4.do-whileループとwhileループ |
次の2つのループは同じ意味となるがこの場合は後ろ判断ループなので,
|
5.無限ループ |
条件記述の部分で,C言語の文法では,
次の例も無限ループになるが,while利用の記述の方が明確と思われる
|
6.ループと緊急脱出 嫌われ者の「breakによる中途脱出」 |
繰り返し処理中に,ある条件が生じたら緊急に繰り返しから抜け出さなければならないことがある。
のように直感的に書くが,これは
と同じである。繰り返し処理の出口はループの先頭か最後であるスタイルが読みやすい。 どうしてもプログラムAの表現を使う場合には,コメントをつけて次のように目立たせるのがよい。
なお
ならば,ループに入った直後の脱出なので
と書くべきであるし,また
ならば,ループの終端における脱出なので
と書くべきである。 ループへの入口は上端一箇所,出口も上端または下端に一箇所にするとプログラムが読みやすくなる。 |
課題2 その4 |
---|
検証は1から10までの数字すべてを与え,合計値55,平均値5.5が表示されることを確かめること。
(「1,2,3,4,5,6,7,8,9,10,-1」(-1はデータ終わりの合図)を入力して確かめなさい。)
また,1から5までの数字すべてを与え,合計値15,平均値3が表示されることを確かめること。
(「1,2,3,4,5,-1」(-1はデータ終わりの合図)を入力して確かめなさい。)
レポートの実行結果には上記2つの例を示しなさい。
つぎの1~3のヒントは考え方は異なりますが,同じ結末にたどり着きます。
ヒント1 「2.7 追加説明」のすぐ上の行の「繰返し処理記述の時の考え方 ここを読んでください」の中の「例2」が簡潔な説明です。
ヒント2 ループを意識せず,やりたいことを羅列するところから考える。そしてループの考え方に到達する。拡張性が高く,自然な考え方である。
ヒント3 ループになることを意識して無限ループ+途中脱出型ループを作る。その後「同じ意味変換」して自然なループに変更していく。
ヒント4 整数型と実数型の変数の混合演算については
B.演算子 の「B.1 C言語における算術演算子」の「整数と実数の混合演算」を読むと良い。
(16)正整数を入力して,その正整数が何桁か求めるプログラムを作りなさい。ただし正整数は10億以下とする。また,プログラム1回の起動でこの
作業を何回も繰返し行なえるようにし,負の値が入力されたら直ちにプログラムが止まるようにしなさい。負の値入力後は直ちに繰り返し作業から抜け出すこと
(ループ回数はプログラミング時には決まっていないので,forループは使わない)(p02ex16.c)
(ヒント10で何回割れるか考える)
検証は,1桁の数,2桁の数,..,8桁の数で行ない,次のような結果になるようにしなさい。
key in an integer : 5
5 : 1 (digits)
key in an integer : 66
66 : 2 (digits)
key in an integer : 777
777 : 3 (digits)
key in an integer : 1111
1111 : 4 (digits)
key in an integer : 22334
22334 : 5 (digits)
key in an integer : 112233
112233 : 6 (digits)
key in an integer : 5556667
5556667 : 7 (digits)
key in an integer : 99990000
99990000 : 8 (digits)
key in an integer : -1
Pushing any key leads the exit.
(17)2つの正整数の最大公約数を求める算法(アルゴリズム)として有名なユークリッドの互除法により,最大公約数を求めるプログラムを作りなさい。プログラムでは2つの正整数はキーボードから入力するものとする。(p02ex17.c)
r=p%q 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) : |
r=p%q 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する rが0だったらqが最大公約数なので作業やめ pの値はもう使わないのでqの値をpに移動(p=q;) qの値はもう使わないのでrの値をqに移動(q=r;) r=p%q; 途中経過を表示するため,p,q,rを表示する : |
r=p%q; |
(文章課題b)次の内容をまとめてレポートにしなさい。
ただし,初めの2行(ファイル名,ID,出席番号,氏名)は,これまでのプログラムと同様な書式で書くこと。 (p02b.txt)
1)プログラム
int i;
for (i=0; i<20; i++) {
printf("Hello, No.%d san.\n",i);
}
printf("bye %d",i);
において,最後の表示は
bye 20
となる。forループから脱出するときの動作を示して,どうしてそうなるのか説明しなさい。
「Hello, No.19 san.」を表示したところ以降だけ,実行経過通りに説明しなさい。
説明文の最初は,
「Hello, No.19 san.」が表示された時点で変数iの値は19である。・・・・
で始めなさい。
また「i++」という表現を説明内に含むようにしなさい。
2)プログラム
int k=5;
int s=0;
while(s<10) {
s=s+k;
k++;
}
printf("k=%d s=%d\n",k,s);
において,最後の表示は
k=7 s=11
となる。プログラムの動作を1行ずつ実行経過通りに,プログラム起動時から順に説明しなさい。
同じ場所を何回か通過するが,その時変数に保持されている値が異なるので,実行経過通りに説明することが求められる。
説明文の最初は,
「kに5が代入され,次にsに0が代入された。
while(s<10) は条件が成立しているため,ループ内に入る。
s=s+kによってsは5になる。
k++によってkは6になる。・・・・ 」
で始めなさい。