• 検索結果がありません。

繰り返し文

ドキュメント内 note.dvi (ページ 86-91)

第 6 章 C 言語入門

6.9 いくつかのプログラム

6.10.2 繰り返し文

Exercise 6.9.6 short,int,unsigned int,longのそれぞれの型の変数が何バイトの記憶領域をとるか を表示するプログラムを書け.

Exercise 6.9.7 int, longのそれぞれの型で表現される最大の数に1 を加えたらどうなるかを考察せよ.

Exercise 6.9.8 正の浮動小数点数の小数点以下を四捨五入した値を求めるプログラムを書け.

Exercise 6.9.9 AND, OR, NOTからXORを作れ.

Exercise 6.9.10 Example 6.8.6はどうしてかを考察せよ.

Exercise 6.9.11 intが16ビット,long が32ビットの時,-1L < 1U,-1L > 1ULとなる. 何故か?

6.10

#include <stdio.h>

int i ;

int main(int argc, char **argv) {

for(i=0;i<10;i++) { printf("%d\n",i) ; }

return 0 ; }

#include <stdio.h>

int i ;

int main(int argc, char **argv) {

for(i=0;i<10;i++) printf("%d\n",i) ; return 0 ;

}

この例では, はじめにi = 0が実行され, i < 10である間は, { }の部分が実行される. 各繰り返しが終 ると,i++が実行される. iが 9になると,繰り返しは実行されるが, それが終了した後,i++が実行され, iは10となる. したがって,i < 10が 1となり,繰り返しの文は実行されずに,forは終る.

Example 6.10.2 この例は,式1から式3が省かれたもので,無限ループを実現している.

#include <stdio.h>

int main(int argc, char **argv) {

for(;;) ; return 0 ; }

式2が省かれた場合は,常にその値が non-zeroと認識される.

Example 6.10.3 この例は, 1から10までの和を計算している.

#include <stdio.h>

int i, j ;

int main(int argc, char **argv) {

for(i=0,j=0;i<10;i++) j += i+1 ;

return 0 ; }

ここで,コンマ演算子が2個所に利用されている. 特に,for文の第1式のコンマ演算子の利用法に注意.

Exercise 6.10.1 for文を利用して, 2 から10までの偶数の和を計算して印字するプログラムを書け.

Remark 6.10.1 1から10までの和を計算するプログラムでは,for文を使ったものでも,いろいろな書 き方が可能である.

j = 0 ;

for(i=0;i<10;i++) j += i+1 ;

上の例の書き方よりも,この方が望ましい. なぜなら, j=0と初期化を行う部分が独立し, プログラムの 意図が明確になっている.

j = 0 ;

for(i=1;i<=10;i++) j += i ;

Id: C4.tex,v 1.6 2001-03-15 20:35:03+09 naito Exp

確かに問題なく動作するのだが, Cでは境界判定条件(この例ではi <= 10)では,i <= 10と書くよ

りもi < 10と書く方が(すなわち, 直前の例の方が)標準的である. 可能な限り標準的なCの書き方を

身につける方が良い.

j = 0 ;

for(i=10;i>0;i--) j += i ;

普通に考えれば iの値をインクリメントするに決まっている. 間違いなく動くのだが,このような無理 な書き方はやめた方が良い. バグの元となる.

j = 0 ;

for(i=11;--i>0;j+=i) ;

もうここまでいくと,何をやっているのかわからない. 絶対ダメ!

6.10.2.2 while文

while 文は以下のような構文を持つ.

while(式) 文

ここで,式は省くことはできない. ここで,式は算術型もしくはポインタでなくてはならない.

このようなwhile 文は,次のように制御される.

1. 式が最初に評価される.

2. 式が0でない限り,繰り返しの文が実行される.

ここで,式の副作用は,繰り返しのはじまる前に完了する.

Example 6.10.4 この例は, 0から9 までの整数を順に印字するものである.

#include <stdio.h>

int i=0;

int main(int argc, char **argv) {

while (i < 10) { printf("%d\n",i++) ; }

return 0 ; }

#include <stdio.h>

int i=0;

int main(int argc, char **argv) {

while (i < 10)

printf("%d\n",i++) ; return 0 ;

}

この例では, はじめにi = 0が実行され, i < 10である間は, { }の部分が実行される. 各繰り返し中で は,i++が実行されているので,繰り返し毎にiは1だけ増加する. iが9になると,繰り返しは実行され るが,繰り返しの文中で,i++が実行され,iは10となる. したがって,i < 10が1となり,繰り返しの文 は実行されずに,whileは終る.

Example 6.10.5 この例は,無限ループ25を実現している.

25無限ループはウインドウシステムでのアプリケーションの作成に利用される.前に述べたforを使った無限ループか,こちらの 例かどちらかの利用にとどめておいた方が良い.無限ループの実現方法はいくらでも考え付くが,これら2つのどちらかであれば, C を少しでも知っているプログラマなら,見ただけで無限ループと理解可能である.

Id: C4.tex,v 1.6 2001-03-15 20:35:03+09 naito Exp

#include <stdio.h>

int i ;

int main(int argc, char **argv) {

while(1) ; return 0 ; }

Example 6.10.6 この例は, 1から10までの整数の和を計算するプログラムである.

#include <stdio.h>

int i=0,j=0;

int main(int argc, char **argv) {

while (i < 10) j += ++i ; return 0 ; }

ここでは和をとる直前に前置インクリメント演算子を利用していることに注意.

Exercise 6.10.2 while文を利用して, 2から10までの偶数の和を計算して印字するプログラムを書け.

Remark 6.10.2 1から10までの和を計算するプログラムでは,while 文を使ったものでも,いろいろな 書き方が可能である.

i = j = 0 ; while(i < 10) {

i += 1 ; j += i ; }

上の例の書き方よりも,この方が望ましいかもしれない. なぜなら,jにiの値をインクリメントする際 に, iがインクリメントされているというプログラムの意図が明確になっている.

j = 0 ; i = 1 ; while(i <= 10)

j += i ;

確かに問題なく動作するのだが, Cでは境界判定条件(この例ではi <= 10)では,i <= 10と書くよ りもi < 10と書く方が(すなわち, 直前の例の方が)標準的26 である. 可能な限り標準的なCの書き方 を身につける方が良い.

j = 0 ; i = 10 ; while(i > 0)

j += i ;

普通に考えれば iの値をインクリメントするに決まっている. 間違いなく動くのだが,このような無理 な書き方はやめた方が良い. バグの元となる27 .

結局, 1から10までの和をとるプログラムはfor文を用いた方が自然であることがわかる. じゃあ,while 文はどんな時に使うかって?それは,境界条件があらかじめ決まっていないときにはfor文よりもきれい になります.

26でも,この辺は難しいところかもしれない.

27でも,前のfor文を使ってデクリメントする例よりはよほどマシ.

Id: C4.tex,v 1.6 2001-03-15 20:35:03+09 naito Exp

Example 6.10.7 この例は,標準入力からEOF(ファイル終端)が検出されるまで,1文字づつをよみ,そ れを標準出力に書き出す.

#include <stdio.h>

int c ;

int main(int argc, char **argv) {

while((c = getchar())!= EOF) printf("%c",c) ;

return 0 ; }

このプログラムでは, c = getchar()により,標準入力から1文字を読み, 読んだ文字がEOFでない間 は, その文字を標準出力に1文字づつ書き出している28 .

このプログラムをgetchar.cとし,これを実行形式にコンパイルしたコマンドをa.out としたとき, ./a.out < getchar.c

を実行してみよ.

Remark 6.10.3 上の例で while(c = getchar() != EOF)

とすると,正しく動作しない. 代入演算子と等値演算子の優先順位は,等値演算子の方が上である.

6.10.2.3 do文

do文は以下のような構文を持つ.

do 文

while(式) ;

ここで,式は省くことはできない. ここで,式は算術型もしくはポインタでなくてはならない.

このようなdo文は,次のように制御される.

1. はじめに繰り返しの文が実行される.

2. それが終るたびに式が評価される.

3. 式が0でない限り,繰り返しの文が実行される.

ここで,式の副作用は,各繰り返しの後に完了する.

Example 6.10.8 この例は, 0から9 までの整数を順に印字するものである.

#include <stdio.h>

int i=0;

int main(int argc, char **argv) {

do {

printf("%d\n",i++) ; } while (i < 10) ; }

#include <stdio.h>

int i=0;

int main(int argc, char **argv) {

do

printf("%d\n",i++) ; while (i < 10) ; }

28char cではなく,int cとしている理由は, Section 6.19を参照.

Id: C4.tex,v 1.6 2001-03-15 20:35:03+09 naito Exp

この例では,はじめにi = 0が実行される. 繰り返しの部分は,1回目は無条件に実行され,その後にi<10 が評価される. 各繰り返し中では,i++が実行されているので,繰り返し毎にiは1 だけ増加する. iが9 になると,繰り返しは実行されるが,繰り返しの文中で,i++が実行され,繰り返しが終ると,iは 10とな る. したがって,i < 10が 1となり,繰り返しの文は実行されずに, doは終る.

doはwhileとは異なり,少なくとも1回は繰り返しの文が実行される.

Example 6.10.9 この例は, 1から10までの整数の和を計算するプログラムである.

#include <stdio.h>

int i=0,j=0;

int main(int argc, char **argv) {

do

j += ++i ; while(i < 10) ; }

ここでは和をとる直前に前置インクリメント演算子を利用していることに注意.

Exercise 6.10.3 do文を利用して, 2から10までの偶数の和を計算して印字するプログラムを書け.

やはり1 から10までの和を計算するプログラムを, do文を使っていろいろな書き方が可能である. しか し, これまでに見てきたように,わざわざプログラムを難しく書く必要はない.

do文はCでは余り多用される構造ではない. なぜなら,ループ終了条件が一番最後にあり, ひとめでは ループの構造がわかりにくいからである. 一般には,「必ず一度はループに入る」ということを明示的に示 したいときに用いるのだが, ループ全体が短く, ひとめでループの構造がわかるときだけに使うのが良い.

do文は,while文とbreak 文の組合わせで同等なものを実現することが出来る.

ドキュメント内 note.dvi (ページ 86-91)