Programing

'do… while'대 'while'

lottogame 2020. 10. 18. 08:20
반응형

'do… while'대 'while'


중복 가능성 :
While 대 Do While
언제 while 루프 대신 do-while을 사용해야합니까?

나는 한동안 프로그래밍을 해왔고 (2 년 근무 + 4.5 년 학위 + 1 년 예비 대학), 프로그래밍 입문 과정에서 강요 당할 수밖에없는 do-while 루프를 사용한 적이 없습니다. 그렇게 근본적인 일에 부딪히지 않으면 프로그래밍을 잘못하고 있다는 느낌이 커집니다.

내가 올바른 상황에 빠지지 않았을까요?

잠시 대신 do-while을 사용해야하는 몇 가지 예는 무엇입니까?

(내 학교 교육은 거의 모두 C / C ++이고 내 작업은 C #이므로 do-while이 다르게 작동하기 때문에 절대적으로 의미가있는 다른 언어가 있다면이 질문은 실제로 적용되지 않습니다.)

명확히하기 위해 ... 나는 a while와 a 의 차이점을 알고 do-while있습니다. 종료 조건을 확인하고 작업을 수행하는 동안. do-while작업을 수행하고 종료 조건을 확인합니다.


항상 루프를 한 번 이상 실행하려는 경우. 흔하지는 않지만 가끔 사용합니다. 이를 사용하려는 경우는 재 시도가 필요할 수있는 리소스에 액세스하려는 경우입니다. 예 :

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

} while (user says retry);

컴파일러가 최적화에 능숙하지 않으면 do-while이 더 좋습니다. do-while에는 조건부 점프와 무조건 점프가있는 for 및 while과는 반대로 단일 조건부 점프 만 있습니다. 파이프 라인되고 분기 예측을 수행하지 않는 CPU의 경우 이는 타이트 루프의 성능에 큰 차이를 만들 수 있습니다.

또한 대부분의 컴파일러는이 최적화를 수행 할 수있을만큼 똑똑하기 때문에 디 컴파일 된 코드에서 발견 된 모든 루프는 일반적으로 do-while입니다 (디 컴파일러가 역방향 로컬 gotos에서 루프를 재구성하는 것을 방해하는 경우).


TryDeleteDirectory 함수에서 이것을 사용했습니다. 이런 거였어

do
{
    try
    {
        DisableReadOnly(directory);
        directory.Delete(true);
    }
    catch (Exception)
    {
        retryDeleteDirectoryCount++;
    }
} while (Directory.Exists(fullPath) && retryDeleteDirectoryCount < 4);

Do while은 무언가를 적어도 한 번 실행하고자 할 때 유용합니다. do while 대 while 사용에 대한 좋은 예로서 다음을 만들고 싶다고 가정 해 보겠습니다. 계산기.

루프를 사용하고 각 계산 후 그 사람이 프로그램을 종료 하려는지 확인하여 접근 할 수 있습니다. 이제 프로그램이 열리면 사용자가이 작업을 한 번 이상 수행하기를 원하므로 다음을 수행 할 수 있다고 가정 할 수 있습니다.

do
{
    //do calculator logic here
    //prompt user for continue here
} while(cont==true);//cont is short for continue

이것은 일종의 간접적 인 대답이지만,이 질문은 그 뒤에있는 논리에 대해 생각하게했고 공유 할 가치가있을 것이라고 생각했습니다.

다른 사람들이 말했듯이 do ... while적어도 한 번 본문을 실행하려면 루프 를 사용합니다 . 하지만 어떤 상황에서 그렇게하고 싶습니까?

글쎄요, 제가 생각할 수있는 가장 명백한 상황 은 체크 조건의 초기 ( "unprimed") 값이 종료 할 때와 같을 때 입니다. 즉, 조건을 종료되지 않는 값으로 초기화하려면 루프 본문을 한 번 실행 한 다음 해당 조건에 따라 실제 반복을 수행해야합니다. 프로그래머가 너무 게을러서 누군가가 이것을 제어 구조로 감싸기로 결정했습니다.

예를 들어 시간 초과가있는 직렬 포트에서 문자를 읽는 것은 다음과 같은 형식을 취할 수 있습니다 (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)

nullable 형식과 언어, 상황이 : 그래서 여기 내 지점의 핵심입니다 initial_value == exit_value훨씬 덜 자주 발생하고, 당신이 그것을 발생하지 않는 이유가 될 수 있습니다. 함수가 None유효한 조건을 나타 내기 위해 반환 될 때가 아직 있기 때문에 결코 발생하지 않는다고 말하는 것이 아닙니다 . 그러나 서두르고 잠깐 생각한 의견으로는 사용하는 언어가 의미하는 값을 허용하지 않으면 더 많이 발생할 것입니다.이 변수는 아직 초기화되지 않았습니다.

이것은 완벽한 추론이 아닙니다. 실제로는 null 값이 일반적이므로 변수가 취할 수있는 유효한 값 집합의 하나 이상의 요소를 형성합니다. 그러나 실제로 프로그래머는 루프 종료 상태를 포함 할 수있는 합리적인 상태에있는 변수와 초기화되지 않은 상태에있는 변수를 구별하는 방법이 있습니다.


학교 다닐 때 꽤 많이 사용했지만 그 이후로는 많이 사용하지 않았습니다.

이론적으로는 종료 조건 확인 전에 루프 본문을 한 번 실행하려는 경우 유용합니다. 문제는 내가 먼저 확인을 원하지 않는 몇 가지 인스턴스의 경우 일반적으로 맨 끝이 아닌 루프 본문 중간종료 확인을 원한다는 것입니다. 그럴 때는 몸 for (;;)if (condition) exit;어딘가에 잘 알려진 것을 사용하는 것을 선호합니다 .

실제로 루프 종료 조건이 약간 불안정한 for (;;) {}경우 필요한 경우 종료 문을 사용 하여 루프를 작성하는 것이 유용 할 때가 있습니다. 그런 다음 완료되면 " 초기화, 종료 조건 및 / 또는 for괄호 안의 증가 코드를 이동하여 정리했습니다 .


항상 한 번의 코드를 실행해야하는 상황이며 그 결과에 따라 더 많이 실행해야합니다. 일반 while루프에서도 동일한 결과를 얻을 수 있습니다 .

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

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

do while코드 블록을 한 번 이상 실행하려는 경우입니다. while반면에 지정된 기준에 따라 항상 실행되는 것은 아닙니다.


다음과 같이 간단합니다.

전제 조건과 후 조건

  • while (cond) {...}-전제 조건, 확인 후에 만 ​​코드를 실행합니다.
  • do {...} while (cond)-사후 조건, 코드가 한 번 이상 실행됩니다.

이제 비밀을 알았으니 .. 현명하게 사용하십시오 :)


이 질문에 대한 답이 적절하다는 것을 알지만이 매우 구체적인 사용 사례 시나리오를 추가하고 싶습니다. do ...를 더 자주 사용할 수 있습니다.

do
{
   ...
} while (0)

여러 줄 # 정의에 자주 사용됩니다. 예를 들면 :

#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);

지금까지의 답변은 do-while의 일반적인 사용을 요약합니다. 그러나 OP는 예제를 요청 했으므로 여기에 하나가 있습니다. 사용자 입력 가져 오기. 그러나 사용자의 입력이 유효하지 않을 수 있으므로 입력을 요청하고 유효성을 검사하고 유효하면 계속하고 그렇지 않으면 반복합니다.

do-while을 사용하면 입력이 유효하지 않은 동안 입력을받습니다. 일반 while 루프를 사용하면 입력을 한 번 얻지 만 유효하지 않으면 유효 할 때까지 반복해서 얻습니다. 루프의 몸체가 더 복잡해지면 전자가 더 짧고 우아하며 유지 관리가 더 간단하다는 것을 확인하는 것은 어렵지 않습니다.


동일한 구조를 여러 번 읽는 독자에게 사용했습니다.

using(IDataReader reader = connection.ExecuteReader())
{
    do
    {
        while(reader.Read())
        {
            //Read record
        }
    } while(reader.NextResult());
}

대부분의 사람들 (나를 포함하여)이 왜 while () {} 루프를 do {} while ()보다 선호하는 내 이론은 다음과 같습니다. while () {} 루프는 do..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)
}

이제 우리는 반대쪽 끝에서 두 가지 검사를 받았으며 불변이 변경되면 두 곳에서 업데이트해야합니다. 표준 드라이버가 필요한 모든 작업을 수행하기 때문에 특정 방식으로 ..while은 사용하지 않는 도구 상자의 특수 드라이버와 같습니다.


저는 약 12 ​​년 동안 프로그래밍을하고 있고 불과 3 개월 전에 조건을 확인하기 전에 항상 한 번의 반복이 필요했기 때문에 do-while을 사용하는 것이 정말 편리한 상황을 만났습니다. 그래서 당신의 큰 시간이 앞서 있다고 생각하십시오 :).


나는 당신이 do...while루프 를 사용하지 않고 어떻게 이렇게 오래 갔는지 상상할 수 없습니다 .

현재 다른 모니터에 하나가 있고 해당 프로그램에 여러 루프가 있습니다. 모두 다음과 같은 형식입니다.

do
{
    GetProspectiveResult();
}
while (!ProspectIsGood());

while루프는 루프 이전의 상태를 확인하고 루프는 do...while루프 이후의 상태를 확인합니다. 이것은 루프 실행으로 인한 부작용 또는 다른 포스터가 말했듯이 루프를 한 번 이상 실행하려는 경우 조건을 기반으로 할 때 유용합니다.

나는 당신이 어디에서 왔는지 이해하지만 do-while거의 사용하지 않는 것입니다. 당신은 그것을 잘못하고 있지 않습니다.

당신은 그것을 잘못하고 있지 않습니다. 그것은 누군가가 byte원시를 사용한 적이 없기 때문에 잘못하고 있다고 말하는 것과 같습니다 . 일반적으로 사용되지 않습니다.


do while파일 시작 부분에서 센티넬 값을 읽을 때 a를 사용 했지만 그 외에는이 구조가 너무 일반적으로 사용되지 않는 것이 비정상적이라고 생각하지 않습니다 do-while. s는 실제로 상황에 따라 다릅니다 .

-- 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)

내가 do/ while루프를 사용하는 가장 일반적인 시나리오 는 일부 입력을 기반으로 실행되고 사용자가 원하는만큼 반복되는 작은 콘솔 프로그램에 있습니다. 분명히 콘솔 프로그램이 시간없이 실행되는 것은 의미가 없습니다. 하지만, 처음 이상이 사용자에게이야 - 따라서 do/ while대신의 while.

이를 통해 사용자는 원하는 경우 다양한 입력을 시도 할 수 있습니다.

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

나는 소프트웨어 개발자가 요즘 사용하는 것이 do/ while점점 줄어들고 있다고 생각합니다 . 이제는 거의 모든 프로그램에 일종의 GUI가 있습니다. 콘솔 앱에서는 지침을 제공하거나 사용자에게 새 정보를 입력하라는 메시지를 표시하기 위해 출력을 지속적으로 새로 고쳐야하기 때문에 더 의미가 있습니다. 반대로 GUI에서는 해당 정보를 사용자에게 제공하는 텍스트가 양식에있을 수 있으며 프로그래밍 방식으로 반복 할 필요가 없습니다.


파일을 읽을 때 항상 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 루프를 수행합니다.


괴짜 프로그래머이기 때문에 많은 학교 프로그래밍 프로젝트에서 텍스트 메뉴 기반 상호 작용을 사용했습니다. 거의 모두 기본 절차에 대해 다음 논리와 같은 것을 사용했습니다.

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

학교 시절부터 저는 while 루프를 더 자주 사용한다는 것을 알게되었습니다.


내가 본 애플리케이션 중 하나는 결과 세트를 볼 때 Oracle에 있습니다.

일단 결과 세트가 있으면 먼저 가져 와서 (do) 그 시점부터 가져옵니다. 가져 오기가 요소를 반환하는지 확인합니다 (요소가 발견되는 동안 ..) .. 다른 "에 대해서도 동일하게 적용 할 수 있습니다." 가져 오기와 유사한 "구현.


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;
}

이 함수는 마음에서 작성되었으며 테스트되지 않았습니다. 요점은 어쨌든 첫 번째 단계를 수행해야하고 상태를 평가하기 전에 수행해야한다는 것입니다.


모든 종류의 콘솔 입력은 do-while과 잘 작동합니다. 처음에 메시지를 표시하고 입력 유효성 검사가 실패 할 때마다 다시 메시지를 표시하기 때문입니다.


서버 / 소비자에서 매우 일반적인 구조입니다.

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)

때로는 작업 (0) 대기가 CPU에 비해 ​​저렴할 수 있습니다 (시간 초과 계산을 제거하더라도 매우 높은 도착률로 개선 될 수 있음). 더욱이, 바쁜 기간에 제공된 숫자를 중요한 통계로 만드는 많은 대기열 이론 결과가 있습니다. (예를 들어 Kleinrock-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)유형 작업을 지원하지 않는 커널 또는 우선 순위가 지정된 대기열이 다른 작업을 고갈시키고 스로틀이 고갈 제어로 사용되는 상황 에 넣는 데 엄청난 비용 이들 수 있습니다 .

This type of balancing can seem like a hack, but it can be necessary. Blind use of thread pools would entirely defeat the performance benefits of the use of a caretaker thread with a private queue for a high updating rate complicated data structure as the use of a thread pool rather than a caretaker thread would require thread-safe implementation.

I really don't want to get into a debate about the pseudo code (for example, whether shutdown requested should be tested in the UNTIL) or caretaker threads versus thread pools - this is just meant to give a flavor of a particular use case of the control flow structure.


This is my personal opinion, but this question begs for an answer rooted in experience:

  • I have been programming in C for 36 years, and I never use do / while loops in regular code.

  • The only compelling use for this construct is in macros where it can wrap multiple statements into a single statement via a do { multiple statements } while (0)

  • I have seen countless examples of do / while loops with bogus error detection or redundant function calls.

  • My explanation for this observation is programmers tend to model problems incorrectly when they think in terms of do / while loops. They either miss an important ending condition or they miss the possible failure of the initial condition which they move to the end.

For these reasons, I have come to believe that where there is a do / while loop, there is a bug, and I regularly challenge newbie programmers to show me a do / while loop where I cannot spot a bug nearby.

This type of loop can be easily avoided: use a for (;;) { ... } and add the necessary termination tests where they are appropriate. It is quite common that there need be more than one such test.

Here is a classic example:

/* skip the line */
do {
    c = getc(fp);
} while (c != '\n');

This will fail if the file does not end with a newline. A trivial example of such a file is the empty file.

A better version is this:

int c;  // another classic bug is to define c as char.
while ((c = getc(fp)) != EOF && c != '\n')
    continue;

Alternately, this version also hides the c variable:

for (;;) {
    int c = getc(fp);
    if (c == EOF || c == '\n')
        break;
}

Try searching for while (c != '\n'); in any search engine, and you will find bugs such as this one (retrieved June 24, 2017):

In ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c , function getword(stream,p,ignore), has a do / while and sure enough at least 2 bugs:

  • c is defined as a char and
  • there is a potential infinite loop while (c!='\n') c=getc(stream);

Conclusion: avoid do / while loops and look for bugs when you see one.


I ran across this while researching the proper loop to use for a situation I have. I believe this will fully satisfy a common situation where a do.. while loop is a better implementation than a while loop (C# language, since you stated that is your primary for work).

I am generating a list of strings based on the results of an SQL query. The returned object by my query is an SQLDataReader. This object has a function called Read() which advances the object to the next row of data, and returns true if there was another row. It will return false if there is not another row.

Using this information, I want to return each row to a list, then stop when there is no more data to return. A Do... While loop works best in this situation as it ensures that adding an item to the list will happen BEFORE checking if there is another row. The reason this must be done BEFORE checking the while(condition) is that when it checks, it also advances. Using a while loop in this situation would cause it to bypass the first row due to the nature of that particular function.

In short:

This won't work in my situation.

    //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.

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

    return list;

Console.WriteLine("hoeveel keer moet je de zin schrijven?");
        int aantal = Convert.ToInt32(Console.ReadLine());
        int counter = 0;

        while ( counter <= aantal)
        {
            Console.WriteLine("Ik mag geen stiften gooien");
            counter = counter + 1;

참고URL : https://stackoverflow.com/questions/3347001/do-while-vs-while

반응형