第26回 for

一定回数の処理をwhileとは別の方法で実現します。「一定回数処理を繰り返す」一般的な方法です。

目次

一定回数処理を繰り返すスケッチ

前回の記事では、一定回数処理をするスケッチを、whileと変数を組み合わせて実現しました。

ただ、whileと変数を組み合わせてスケッチを作成すると、ちょっと読みづらいところがあります。

C++言語に限らず「一定回数処理をする」という場面はたくさん出てきます。どのようなプログラミング言語でも、繰り返し処理をスッキリ書ける仕組みが用意されています。

今回の記事ではその書き方を習得します。

while処理のちょっと読みづらいところ

whileを使用した一定回数繰り返し処理のスケッチはのような特徴があります。

繰り返し回数を数えるために使用しているuint8_t型のcountという変数に注目すると、使用されいる場所が離れています。そのため、どのような処理をしているか、パッと見把握しづらい状況になっています。

このスケッチでは、whilecountという変数を組み合わせて、

「最初にcountを0にして」「そのcountが一定値以下の場合」
「処理を行うたびにcountをプラス1する」

ということをしています。

このように文章でまとめて説明されれば、なるほど、という感じになります。でもスケッチでは上の文章のそれぞれの処理や条件が離れいてるので、count? どこにあるの? あ、ここにあったよ! 繰り返し処理ね! と理解する必要があります。

そこでC++言語では、次の処理を1行にまとめて書ける仕組みが用意されています。

「最初に〇〇をして」「◻︎◻︎の場合」「処理を行うたびに△△する」

先ほどのcountの説明と対応していますよね。

これは一定回数繰り返し処理をするときの定番の表現になっていますので、スケッチでもこのように1行で書ければ、繰り返し処理だ! とすぐにわかるわけです。

それでは、この1行で書ける仕組みを確認していきましょう!

for

最初に、一定回数繰り返し処理をする書き方を確認しましょう。

forの書式

C++言語では、次のforという仕組みが用意されています。

正直、この説明だけではさっぱりわかりません。

でも、forは、whileを使った一定回数繰り返す処理の書き方と対応関係がありますので、対応させながら確認していきましょう。

forとwhileの対応関係

左側は、前回のキッチンタイマーのスケッチで、whilecountを使った繰り返し処理の部分を抜き出したものです(条件部分は具体的な数値にしています)。

右側は、同じ処理をforで書いたスケッチです。

前回の記事で、変数とwhileをうまく使って一定回数処理を繰り返す処理を書きました。その処理をよくよく分析すると、以下のようになっていたんです。

forの基本は以上ですが、何点か補足がありますので確認していきましょう!

補足

実際のforの書き方には注意点や慣習があります。

指示の部分

forで処理をする「指示」は1つのみです。

そこで、forで処理をする「指示」が複数ある場合は、{}で囲むようにします。

次のスケッチは3回LEDを点滅する処理です。

for(uint8_t count=0; count<3; count++) {
  digitalWrite(12, HIGH);
  delay(50);
  digitalWrite(12, LOW);
  delay(950);
}

変数名

キッチンタイマーでは、LEDの点滅回数をカウントする目的で変数名をcountにしました。

でもfor文で繰り返し処理をする場合、次のように書いたところで、プログラミングに慣れている人からすると、countはカウントするための変数というのはすぐにわかります。また、countはforの括弧の中にしかなく、記述も長くなってしまいます。

for(uint8_t count=0; count<10; count++) {
  // 指示
}

そこで、forで繰り返し処理をするときの変数は、次のように一文字のijを使うケースが多く見られます。

for(uint8_t i=0; i<10; i++) { // 状況によってjが使われることもある
  // 指示
}

なぜ一文字の変数名がijなのか謎ですよね。

これはかなり昔のプログラミング言語(FORTRAN)で使用されていた変数名に由来しているようです。当時はメモリ容量が少なかったので変数名が1文字は当たり前、という感じでした。iは「index」の頭文字からきているようです。また他にも変数が必要な場合、iの次ということでjが使われていたようです。さらに必要な場合はその次のkが使われていましたが、現在でもi, j, kは繰り返し処理するときによく使われている変数名です。

変数型

キッチンタイマーのスケッチでは、変数の扱いに慣れるという目的もありますので、わざわざ「uint8_t」型で変数宣言しています。

でも実際に繰り返し処理をする場合、数えられれば良いわけで、変数型は適当、と言ってはなんですが、あまり意識されることはありません。

そこで、forの繰り返し処理で使われる変数型は「int」型がよく使われています。

変数名、変数型を合わせると、次のようなパターンがよく見られます。

for(int i=0; i<10; i++) {
  // 指示
}

「◯回繰り返し処理をする」プログラミングパターン

whileにしてもforにしても、ちょっとややこしいところがありますよね。

そこで、最初は「◯回繰り返し処理をする」というプログラミングのパターンは覚えてしまいましょう!

次のスケッチは、REPEATに定義してある回数分、指示を繰り返す、というスケッチです。

// REPEAT回数繰り返し処理をするお決まりパターン

#define REPEAT 10

for(int i=0; i<REPEAT; i++) {
  // ここに指示を書く
}

forを使ったキッチンタイマーのスケッチ

それでは、前回whileを使って作成した「3回LEDを点滅する」スケッチを、forを使って書き直してみます。

難しいところはないと思いますが、わからないところがありましたらコメント欄でご質問いただければと思います。

/*
  キッチンタイマー
  
  内容: スイッチ、LED、スピーカーを使ったキッチンタイマー
  変更履歴:
    2024.11.25: 新規作成
    2024.12.01: スイッチが押されたらLED点滅開始
    2024.12.02: スイッチ関連の#define追加
    2024.12.05: 点滅回数カウント追加
    2024.12.06: 繰り返し処理をforに変更
*/

// 秒を表現するLED関連の定義
#define BYOU_LED 12  // 秒を表現するLEDの接続端子
#define BYOU_ON  50 // 秒を表現するLEDを点灯している時間(単位:ミリ秒)
#define BYOU_OFF (1000 - BYOU_ON) // 秒を表現するLEDを消している時間(単位:ミリ秒)

// タイマースタートスイッチ関連の定義
#define SWITCH A5 // スイッチを接続している端子名
#define SWITCH_OFF 1 // スイッチOFFの時のdigitalReadの値
#define SWITCH_ON  0 // スイッチONの時のdigitalReadの値

// タイマー時間設定(LEDの点滅回数)
#define TIMER_JIKAN 3

void setup() {
  // 端子の設定
  pinMode(BYOU_LED, OUTPUT);     // 秒表現のLED接続端子の出力設定
  pinMode(SWITCH, INPUT_PULLUP); // スイッチ接続端子をプルアップ設定

  // スイッチが押されるまで何もしないで待つ
  while( digitalRead(SWITCH) == SWITCH_OFF ) {
  }
}

void loop() {
  // TIMER_JIKAN分の回数を数える
  for(uint8_t count=0;  count<TIMER_JIKAN; count++) {
    // 1秒に1回青色LEDを点滅する
    digitalWrite(BYOU_LED, HIGH);
    delay(BYOU_ON);
    digitalWrite(BYOU_LED, LOW);
    delay(BYOU_OFF);
  }

  // 何もしないで待つ
  while( true ) {
  }

}

補足

forに関する発展的な内容の補足です。

2点ありますので、お時間があればお読みいただければと思います。

1)for( ; ; )

他の人がスケッチを調べていると、不思議なforの書き方が出てくることがあります。その書き方も覚えておきましょう。

その不思議かな書き方とは以下のようなスケッチです。

for(;;) {
  // 指示
}

forの「初期化」、「継続条件」、「式」に何も書かれていない書き方です。

このようにforの中に何も書かないと「終了する条件がない」ということで、ずっと処理を続けることになります。

上のfor文の例では、「指示」をずっと繰り返します。

ずっと繰り返す場合、以下のように書けますが、

while(true) {
  // 指示
}

forとwhileを比べると、forの方が4文字!少なくなるので、for(;;)という書き方を好む方もいるようです。

皆さんはどちらが好みでしょうか?

2)forとwhileの違い

これまで、繰り返し処理が実現できる「while」と「for」を習得してきました。

この記事の最初の方では、以下のようにwhileとforは同じ意味、と説明しました。

実は、whileの処理内容の書き方によっては意味が異なってくるケースがあります。

そこでこの記事の最後に、whileとforの関係をさらに深掘りしたいと思います。


上の図のwhileでは、処理の最後で変数countの値をプラス1しています。ところが、次のように最初にcountの値をブラス1すると、処理内容が異なることがあります。

この処理では、whileやforの処理の中でcountの値を使う処理が入っています。このような場合、次のように処理ごとのcountの値が異なってしいます。

whileの処理では、countは「1, 2, 3」ですが、forの処理では「0, 1, 2」になります。

forでは、「初期化」「継続条件」「式」を指定しますが、「式」は毎回の処理の最後に実行される、という点に注意してください。

whileでは「処理」は自分で書く位置を決めるため、他の人のスケッチを参考にするときなど、注意してみてください。

更新履歴

日付内容
2019.9.8新規投稿
2021.8.24新サイトデザイン対応
2022.2.11説明補足
2022.2.14forとwhileの違い説明補足
2024.12.6forの初期式を変数宣言に変更
forの補足説明追加
Arduino IDE2対応
通知の設定
通知タイミング
guest
0 コメント
新しい準
古い順 一番投票が多い
本文中にフィードバック
全てのコメントを見る
目次