104

重複の可能性:
While と Do While
ループの代わりに do-while を使用する必要があるのはいつですか?

私はしばらくの間プログラミングをしてきました (2 年間の仕事 + 4.5 年間の学位 + 1 年間の大学進学前)。これほど基本的なことに出くわすことがなければ、プログラミングが間違っているのではないかとますます感じています。

適切な状況に遭遇していないだけでしょうか?

while の代わりに do-while を使用する必要がある例にはどのようなものがありますか?

(私の教育はほぼすべて C/C++ で行われ、私の仕事は C# で行われました。したがって、do-while の動作が異なるために完全に意味のある言語が他にある場合、これらの質問は実際には当てはまりません。)

while明確にするために...私は aと aの違いを知っていdo-whileます。While は終了条件をチェックしてからタスクを実行します。do-whileタスクを実行し、終了条件をチェックします。

4

31 に答える 31

133

ループを常に少なくとも 1 回実行する場合。一般的ではありませんが、たまに利用します。再試行が必要な可能性のあるリソースにアクセスしようとする場合に、これを使用することがあります。

do
{
   try to access resource...
   put up message box with retry option

} while (user says retry);
于 2010-07-27T19:10:36.027 に答える
77

コンパイラが最適化に適していない場合は、do-while の方が適しています。条件付きジャンプと無条件ジャンプがある for と while とは対照的に、do-while には条件付きジャンプが 1 つしかありません。パイプライン化され、分岐予測を行わない CPU の場合、これはタイトなループのパフォーマンスに大きな違いをもたらす可能性があります。

また、ほとんどのコンパイラはこの最適化を実行できるほどスマートであるため、逆コンパイルされたコードで見つかったすべてのループは通常 do-while になります (逆コンパイラが逆方向のローカル goto からループを再構築することさえ気にしない場合)。

于 2010-07-27T19:15:39.200 に答える
13

これを TryDeleteDirectory 関数で使用しました。こんな感じでした

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);
于 2010-07-27T19:24:46.910 に答える
11

これは一種の間接的な答えですが、この質問の背後にあるロジックについて考えさせられました。これは共有する価値があるかもしれないと思いました.

他の誰もが言っdo ... whileたように、本体を少なくとも 1 回実行する場合は、ループを使用します。しかし、どのような状況でそれをしたいですか?

まあ、私が考えることができる状況の最も明白なクラスは、チェック条件の初期 (「プライミングされていない」) 値が、終了したい場合と同じ場合です。これは、ループ本体を 1 回実行して条件を存在しない値に設定し、その条件に基づいて実際の繰り返しを実行する必要があることを意味します。プログラマーが非常に怠け者であるために、誰かがこれを制御構造にまとめることにしました。

たとえば、タイムアウト付きのシリアルポートからの文字の読み取りは、(Python で)次の形式を取る可能性があります。

response_buffer = []
char_read = port.read(1)

while char_read:
    response_buffer.append(char_read)
    char_read = port.read(1)

# When there's nothing to read after 1s, there is no more data

response = ''.join(response_buffer)

コードの重複に注意してください: char_read = port.read(1) . Python にdo ... whileループがあった場合、次を使用した可能性があります。

do:
    char_read = port.read(1)
    response_buffer.append(char_read)
while char_read

ループの新しいスコープを作成する言語の追加の利点はchar_read、関数の名前空間を汚染しないことです。しかし、これを行うためのより良い方法があることにも注意してください。それは、Python のNone値を使用することです。

response_buffer = []
char_read = None

while char_read != '':
    char_read = port.read(1)
    response_buffer.append(char_read)

response = ''.join(response_buffer)

したがって、ここで私の要点は次のとおりです。null 許容型の言語では、この状況がinitial_value == exit_value発生する頻度ははるかに低く、それが原因で発生しない可能性があります。None関数が有効な状態を示すために戻る場合がまだあるため、決して起こらないと言っているわけではありません。しかし、私の急いで簡単に考えた意見では、使用した言語が意味する値を許可していない場合、この変数はまだ初期化されていません。

これは完全な推論ではありません。実際には、null 値が一般的になったため、変数が取り得る有効な値のセットのもう 1 つの要素を形成するだけです。しかし、実際には、プログラマーは、変数が適切な状態 (ループ終了状態を含む場合があります) にあるか、初期化されていない状態にあるかを区別する方法を持っています。

于 2010-07-28T05:16:56.453 に答える
11

Do while は、少なくとも 1 回何かを実行したい場合に便利です。do while と while を使用する良い例として、次のようなものを作りたいとしましょう: 電卓。

ループを使用して、各計算の後にその人がプログラムを終了したいかどうかを確認することで、これにアプローチできます。これで、プログラムが開かれると、その人は少なくとも 1 回はこれを実行したいと考えているので、次のようにすることができます。

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue
于 2010-07-27T19:17:35.293 に答える
7

学生時代はよく使っていましたが、それ以降はあまり使わなくなりました。

理論的には、終了条件チェックの前にループ本体を 1 回実行する場合に便利です。問題は、最初にチェックしたくないいくつかのインスタンスでは、通常、ループ本体の最後ではなく途中で終了チェックが必要なことです。その場合、よく知られているものを体for (;;)if (condition) exit;どこかに付けて使用することを好みます。

実際、ループの終了条件に少し自信がない場合はfor (;;) {}、必要に応じて終了ステートメントを使用してループを記述し始めると便利な場合があります。forの括弧内の初期化、終了条件、および/またはインクリメントコードを移動することにより、クリーンアップされました。

于 2010-07-27T19:16:46.250 に答える
6

コードの一部を常に 1 回実行する必要があり、その結果によっては複数回実行する必要がある状況。同じことが通常のwhileループでも生成できます。

rc = get_something();
while (rc == wrong_stuff)
{
    rc = get_something();
}

do
{
    rc = get_something();
}
while (rc == wrong_stuff);
于 2010-07-27T19:30:53.600 に答える
6

do whileコード ブロックを少なくとも 1 回実行する場合です。while一方、指定された基準によっては常に実行されるとは限りません。

于 2010-07-27T19:11:10.753 に答える
5

それはそれと同じくらい簡単です:

事前条件と事後条件

  • while (cond) {...} - 前提条件、チェック後にのみコードを実行します。
  • do {...} while (cond) - 事後条件、コードは少なくとも 1 回実行されます。

秘密を知ったので、それらを賢く使用してください:)

于 2010-07-27T19:34:08.773 に答える
4

この質問には適切に回答されているようですが、この非常に具体的なユース ケース シナリオを追加したいと思います。do...while をより頻繁に使用するようになるかもしれません。

do
{
   ...
} while (0)

複数行の #define によく使用されます。例えば:

#define compute_values     \
   area = pi * r * r;      \
   volume = area * h

これは、次の場合に問題なく機能します。

r = 4;
h = 3;
compute_values;

-しかし- 落とし穴があります:

if (shape == circle)  compute_values;

これは次のように展開されます。

if (shape == circle) area = pi *r * r;
volume = area * h;

do ... while(0) ループでラップすると、単一のブロックに適切に展開されます。

if (shape == circle)
  do
  {
    area = pi * r * r;
    volume = area * h;
  } while (0);
于 2010-07-28T00:06:32.470 に答える
2

これまでの回答は、do-while の一般的な使用法をまとめたものです。しかし、OP は例を求めたので、ここに例を示します。ユーザー入力を取得します。しかし、ユーザーの入力が無効である可能性があります。そのため、入力を求め、検証し、有効であれば続行し、そうでなければ繰り返します。

do-while を使用すると、入力が無効なときに入力を取得できます。通常の while ループでは、入力を 1 回取得しますが、それが無効な場合は、有効になるまで何度も取得します。ループの本体がより複雑になれば、前者の方が短く、エレガントで、保守が簡単であることは容易に理解できます。

于 2010-07-27T19:19:05.660 に答える
2

同じ構造を複数回読み取るリーダーに使用しました。

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}
于 2010-07-27T19:34:40.940 に答える
2

私はこれら 2 つを次のように理解したいと思います:
while-> 'repeat until',
do ... while-> 'repeat if'.

于 2020-10-24T15:23:06.790 に答える
1

ファイルの先頭にある番兵の値を読み取るときにを使用しましたdo whileが、それ以外は、この構造があまり一般的に使用されていないことは異常ではないと思います。これdo-whileは実際には状況に応じたものです。

-- file --
5
Joe
Bob
Jake
Sarah
Sue

-- code --
int MAX;
int count = 0;
do {
MAX = a.readLine();
k[count] = a.readLine();
count++;
} while(count <= MAX)
于 2010-07-27T19:20:14.887 に答える
1

私は約 12 年間プログラミングしていますが、わずか 3 か月前に、状態をチェックする前に常に 1 回の反復が必要であったため、do- を使用するのが本当に便利な状況に遭遇しました。だから、あなたの大事な時間が先にあると思います:)。

于 2010-07-27T19:24:34.333 に答える
1

ほとんどの人 (私を含む) が do{}while() よりも while(){} ループを好む理由を以下に示します。真実ではない。while ループは、ある意味で「より一般的」です。また、プログラマーはパターンを把握しやすいことを好みます。while ループは、開始時にその不変式が何であるかを示しており、これは素晴らしいことです。

「より一般的な」ことについて私が言いたいことは次のとおりです。この do..while ループを見てください:

do {
 A;
 if (condition) INV=false; 
 B;
} while(INV);

これを while ループに変換するのは簡単です。

INV=true;
while(INV) {
 A;
 if (condition) INV=false; 
 B;
}

ここで、while ループのモデルを取り上げます。

while(INV) {
     A;
     if (condition) INV=false; 
     B;
}

そして、これを do..while ループに変換すると、次の怪物が生成されます。

if (INV) {
 do
 {
         A;
         if (condition) INV=false; 
         B;

 } while(INV)
}

これで、両端に 2 つのチェックがあり、不変条件が変更された場合は、2 つの場所で更新する必要があります。ある意味で、do..while は、ツール ボックスに入っている、決して使用しない特殊なドライバーのようなものです。

于 2010-07-27T19:57:37.087 に答える
1

do...whileループを使用せずにこれほど長い間、どのように過ごしてきたのか想像できません。

現在、別のモニターに 1 つあり、そのプログラムにはそのようなループが複数あります。それらはすべて次の形式です。

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());
于 2010-07-28T00:14:04.557 に答える
1

サーバー/コンシューマでは非常に一般的な構造です。

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      REPEAT
          process
      UNTIL(wait for work(0 timeout) indicates no work)
      do what is supposed to be done at end of busy period.
   ENDIF
ENDDO

REPEAT UNTIL(cond)存在_do {...} while(!cond)

場合によっては、work(0) を待機する方が CPU のコストが低くなることがあります (タイムアウトの計算をなくしても、非常に高い到着率で改善される場合があります)。さらに、繁忙期のサービス提供数を重要な統計とする待ち行列理論の結果も数多くあります。(たとえば、クラインロック - Vol 1 を参照してください。)

同様に:

DOWHILE (no shutdown requested)
   determine timeout
   wait for work(timeout)
   IF (there is work)
      set throttle
      REPEAT
          process
      UNTIL(--throttle<0 **OR** wait for work(0 timeout) indicates no work)
   ENDIF
   check for and do other (perhaps polled) work.
ENDDO

check for and do other workメイン ループに配置するのに法外なコストがかかる場合や、効率的な型操作をサポートしていないカーネルを配置したりwaitany(waitcontrol*,n)、優先順位付けされたキューが他の作業を枯渇させたり、スロットルが枯渇制御として使用されたりする可能性があります。

この種のバランス調整はハックのように思えるかもしれませんが、必要になる場合があります。スレッド プールを盲目的に使用すると、更新率の高い複雑なデータ構造に対してプライベート キューを使用して管理スレッドを使用することによるパフォーマンス上の利点が完全に失われます。管理スレッドではなくスレッド プールを使用すると、スレッド セーフな実装が必要になるためです。

疑似コード (たとえば、要求されたシャットダウンを UNTIL でテストする必要があるかどうか) や、世話人スレッドとスレッド プールの比較について議論するつもりはありません。制御フロー構造。

于 2010-07-28T04:49:28.367 に答える
0

ファイルを読み込むときは、常に do-while ループを使用します。ヘッダーにコメントを含む多くのテキスト ファイルを使用しています。

# some comments
# some more comments
column1 column2
  1.234   5.678
  9.012   3.456
    ...     ...

do-while ループを使用して "column1 column2" 行まで読み取り、目的の列を探すことができます。擬似コードは次のとおりです。

do {
    line = read_line();
} while ( line[0] == '#');
/* parse line */

次に、while ループを実行して、ファイルの残りの部分を読み取ります。

于 2010-07-27T19:46:55.847 に答える
0

オタク プログラマーである私の学校のプログラミング プロジェクトの多くは、テキスト メニュー駆動のインタラクションを使用していました。実質的にすべてが、メイン プロシージャに次のロジックのようなものを使用しました。

do
    display options
    get choice
    perform action appropriate to choice
while choice is something other than exit

学生時代から、while ループをより頻繁に使用するようになりました。

于 2010-07-27T19:54:22.627 に答える
0

私が見たアプリケーションの 1 つは、結果セットを見ると Oracle にあります。

結果セットを取得したら、最初にそれからフェッチし(do)、その時点から..フェッチが要素を返すかどうかを確認します(要素が見つかった場合..)..同じことが他の "フェッチのような」実装。

于 2010-07-27T19:56:39.020 に答える
0

do/ループを使用する最も一般的なシナリオwhileは、何らかの入力に基づいて実行され、ユーザーが好きなだけ繰り返す小さなコンソール プログラムです。明らかに、コンソール プログラムがまったく実行されないのは意味がありません。しかし、それはユーザー次第です。したがってdowhile単なるwhile.

これにより、ユーザーは必要に応じてさまざまな入力を試すことができます。

do
{
   int input = GetInt("Enter any integer");
   // Do something with input.
}
while (GetBool("Go again?"));

ソフトウェア開発者はdo/を使用することがますますwhile少なくなっているのではないかと思います。実際、太陽の下のほぼすべてのプログラムが何らかの GUI を備えているからです。コンソール アプリでは、指示を提供したり、ユーザーに新しい情報を表示したりするために出力を継続的に更新する必要があるため、より理にかなっています。対照的に、GUI では、ユーザーに情報を提供するテキストはフォーム上に置くだけでよく、プログラムで繰り返す必要はありません。

于 2010-07-27T19:31:15.143 に答える
0

utf-8 文字列の次の文字位置を返す関数で使用しました。

char *next_utf8_character(const char *txt)
{
    if (!txt || *txt == '\0')
        return txt;

    do {
        txt++;
    } while (((signed char) *txt) < 0 && (((unsigned char) *txt) & 0xc0) == 0xc0)

    return (char *)txt;
}

この関数は心から書かれており、テストされていないことに注意してください。重要なのは、とにかく最初のステップを実行する必要があり、条件を評価する前に実行する必要があるということです。

于 2010-07-27T20:14:27.773 に答える
0

最初にプロンプ​​トを表示し、入力の検証が失敗するたびに再プロンプトを表示するため、どのような種類のコンソール入力も do-while でうまく機能します。

于 2010-07-27T20:23:25.123 に答える
0

whileループはループ前の状態をdo...whileチェックし、ループはループ後の状態をチェックします。これは、ループの実行による副作用に基づいて条件を設定したい場合、または他のポスターが言ったように、ループを少なくとも1回実行したい場合に便利です。

あなたがどこから来たのかは理解していますが、do-whileはほとんどの人がめったに使用しないものであり、私自身は使用したことがありません. あなたのやり方は間違っていません。

あなたのやり方は間違っていません。byteそれは、プリミティブを使ったことがないからといって、間違ったことをしていると言っているようなものです。それほど一般的に使用されているわけではありません。

于 2010-07-27T19:14:13.307 に答える
-1

私が持っている状況で使用する適切なループを調査しているときに、これに出くわしました。これは、do.. while ループが while ループよりも優れた実装であるという一般的な状況を完全に満たすと思います (C# 言語、それが仕事の主要な言語であると述べたからです)。

SQL クエリの結果に基づいて文字列のリストを生成しています。私のクエリによって返されるオブジェクトは SQLDataReader です。このオブジェクトには、オブジェクトをデータの次の行に進める Read() という関数があり、別の行がある場合は true を返します。別の行がない場合は false を返します。

この情報を使用して、各行をリストに戻し、返すデータがなくなったら停止します。Do... While ループは、別の行があるかどうかを確認する前に、リストに項目を追加することを保証するため、この状況で最適に機能します。これが while(condition) をチェックする前に行われなければならない理由は、それがチェックするときにそれも進むからです。この状況で while ループを使用すると、その特定の関数の性質により、最初の行がバイパスされます。

要するに:

これは私の状況ではうまくいきません。

    //This will skip the first row because Read() returns true after advancing.
    while (_read.NextResult())
           {
               list.Add(_read.GetValue(0).ToString());
           }

   return list;

この意志。

    //This will make sure the currently read row is added before advancing.
    do
        {
            list.Add(_read.GetValue(0).ToString());
        } 
        while (_read.NextResult());

    return list;
于 2017-01-10T17:42:46.503 に答える