キャッシュ

IT関連教材の cache です。旧 URL のまま随時変更しています。

繰り返し

2013-12-08 14:39:17 | 教材

 


問: 与えられた整数の配列 a[4] の要素の値の総和を表示するプログラムを示せ。ただし、初期値は適当に設定してよい。

考え方: sum = a[0] + a[1] + a[2] + a[3];のような式では大きい配列に使いづらいので {sum = sum + a[i];}の繰り返しで計算する。 

#include stdio.h>
int main( ){
    int a[4]={3, 7, -2, 5};
    int i, sum;
    sum = a[0];
    <* i=1 to 3 *>{
        sum = sum + a[i];
    }
    printf("総和は %f\n", S);
    return 0;
}

 

#include stdio.h>
int main( ){
    int a[4]={3, 7, -2, 5};
    int i, sum;
    sum = a[0];
    for(i = 1; i < 4; i = i+1){
        sum = sum + a[i];
    }
    printf("総和は %f\n", S);
    return 0;
}

<* i=1 to 3 *>{sum = sum + a[i];}
     <* 順に実行 *>{
        sum = sum + a[1];
        sum = sum + a[2];
        sum = sum + a[3];
   }
  の意味。書きかえると
     <* 順に実行 *>{
        i = 1; sum = sum + a[i];
        i = 2; sum = sum + a[i];
        i = 3; sum = sum + a[i];
   }
  。すなわち 1 ≦ i ≦ 3  の範囲で
sum = sum + a[i];を繰り返す。
i = i+1よりi++を使うことが多い。
for(i = 1; i < 4; i = i+1){sum = sum + a[i];}
   i = 1;
   while(i < 4){
       sum = sum + a[i];
       i = i+1;
   }
 
 と同じ。したがって for(i = 1; i = 3; i = i+1)等でもよい。  


擬似コード<* i=m to n *>に関する補足:

<* i=m to n *> は Algol の for i := m step 1 until n do に対応する基本的な繰り返し構造で、BASIC ではFOR I = 1 TO 3 と書く(末尾にNEXT)。 K&R2, p.74 でも for(i = 0; i < n; i++) を “これは Fortran の DO ループや、Pascal の for と同様な、配列の最初の n 要素を処理するための C の慣用句である” と書かれている。 しかし、一般形 for(式1; 式2; 式3){文}
    式1; while(式2){文 式3;}
すなわち

    (1) 「式1;」を実行。
    (2) 「式2」 でなければ (5) へジャンプ。
    (3) 「文」「式3;」 を実行。
    (4) (2) へジャンプ。
    (5) 次へ進む。

と等価であり、処理の流れを見にくい。 for(i = 0; i < n; i++) を使うときは初期化 「i = 0;」 が終了した直後は 「i < n」 であるから、このような場合は
    式1; do{文 式3;}while(式2);
すなわち

    (1) 「式1;」を実行。
    (2) 「文」「式3;」 を実行。
    (3) 「式2」 でなければ (2) へジャンプ。

に対応させると分かり易くなる。例えば <* i=1 to 3 *>{sum = sum + a[i];}
    i = 1; do{sum = sum + a[i]; i++;}while(++i = 3);

★ コンマ演算子を使えば 式1; do{文}while(式3,式2); (K&R2, p.258)。
★ 一般形の別表現は 式1; if(式2)do{文 式3;}while(式2);
   break 文を使えば  式1; while(1){if(式2) break; 文 式3;} 


問: 与えられた文字の配列 s[80] に書かれている文字列の長さを表示するプログラムを示せ。ただし、初期値は適当に設定してよい。

考え方: 文字列の最後に '\0' があるから、これを s[0]、s[1]、・・・を順に調べ、s[k] == '\0'となる k が見つかれば長さは k 。

#include stdio.h>
int main( ){
    char s[80]="Hello!";
    int k=0;
    <*s[k] != '\0'の間 *>{
        k = k+1;
    }
    printf("長さは %d\n", k);
    return 0;
}

 

#include stdio.h>
int main( ){
    char s[80]="Hello!";
    int k=0;
    while(s[k] != '\0'){
        k = k+1;
    }
    printf("長さは %d\n", k);
    return 0;
}

<*s[k] != '\0'の間 *>{k = k+1;}<*
      (1) s[k] != '\0'でなければ(3)にジャンプ。
      (2) k = k+1;を実行して(1)に戻る。
      (3) 次へ進む。
   *> を意味する。この場合の“次”は「printf("長さは %d\n", k);
while(s[k] != '\0')for(;s[k] != '\0';)と同じ。
while(s[k] != '\0'){k = k+1;}は「while(s[k++]);」と同じ。


問: 整数の配列 m[100] にテストの点数をキー入力して、平均点を表示するプログラムを示せ。ただし、テストの答案数は100以下で、答案がなくなったときは -1 をキー入力することを前提にする。

考え方: キー入力の値が繰り返しの有無を定めるので do-while 文が適している。

#include stdio.h>
int main( ){
    int m[100], k;
    double x;
    printf("データ:\n");
    k = 0; x = 0;
    {
        scanf("%d", &m[k]);
        x = x + m[k]; k++;
    }<*m[k] >= 0の間 *>;
    k--; if(k == 0){return 0;}
    printf("平均値は %f\n", x/k);
    return 0;
}

 

#include stdio.h>
int main( ){
    int m[100], k;
    double x;
    printf("データ:\n");
    k = 0; x = 0;
    do{
        scanf("%d", &m[k]);
        x = x + m[k]; k++;
    }while(m[k] >= 0);
    k--; if(k == 0){return 0;}
    printf("平均値は %f\n", x/k);
    return 0;
}
 

{・・・}<*m[k] >= 0の間 *>;m[k] >= 0である間は{・・・}を繰り返す。
k++;k = k + 1;と、k--;k = k - 1;と同じ。
if(k == 0){return 0;}は(データ 0 個の)例外処理。
x = 0; k = 0;x = k = 0;でもよい。
do{scanf("%d", &m[k]); x = x + m[k]; k++;}while(m[k] >= 0);
    scanf("%d", &m[k]);
    while(m[k] >= 0){x = x + m[k]; k++; scanf("%d", &m[k]);}
  や、break 文を用いた
    while(1){
        scanf("%d", &m[k]); x = x + m[k]; k++;
        if(m[k] < 0){break;
    }
  と同じ。


 



コメントを投稿