programing

C의 입력 버퍼를 클리어하려면 어떻게 해야 합니까?

goodcopy 2022. 7. 24. 23:04
반응형

C의 입력 버퍼를 클리어하려면 어떻게 해야 합니까?

다음과 같은 프로그램이 있습니다.

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

에서 사용자가 키를 때문이 제대로 .Enter 1 에 、 2 에: 。Enter key (ASCII code 13) ★★★★★★★★★★★★★★★★★」\n (ASCII code 10)에서는 2호선이라고 \n사용자가 문자를 입력할 때까지 기다리지 않습니다.

았어 、 내내 、 할할 。두 번째가 되는 getchar() )ch2 = getchar();은(는).Enter key (13) 보다\n★★★★★★★★★★★★★★★★★?

다음으로, 저자는 이러한 문제를 해결하기 위한 두 가지 방법을 제안했다.

  1. fflush()

  2. 다음과 같은 함수를 작성합니다.

    void
    clear (void)
    {    
      while ( getchar() != '\n' );
    }
    

이 코드는 실제로 작동했다.하지만 그게 어떻게 돌아가는지 설명할 수 없다고요? 「」를 사용하고, 「」를 사용하고 있기 에,getchar() != '\n' '읽기', '1'을 제외한 모든 한.'\n' 남습니다'\n'★★★★★★★★★★★★★★★★★?

회선 1에서 사용자가 Enter 키를 누르면 입력 버퍼2 문자가 남기 때문에 프로그램은 정상적으로 동작하지 않습니다.키(ASCII 코드 13) 및 \n(ASCII 코드 10)을 입력합니다.따라서 2행에서는 \n을 읽고 사용자가 문자를 입력할 때까지 기다리지 않습니다.

두 번째 줄에 표시되는 동작은 맞지만, 이는 올바른 설명이 아닙니다.텍스트 모드 스트림에서는 플랫폼이 사용하는 회선 엔딩(캐리지 리턴(0x0D) + 회선 피드(0x0A), 베어 CR 또는 베어 LF)은 중요하지 않습니다.는 C 런타임 되는 것은 C 런타임 입니다.프로그램은 이 기능을 인식합니다.'\n'를 참조해 주세요.

그 Enter 키를 누릅니다.'\n'2행으로 읽습니다.자세한 내용은 Y/N 응답을 읽는 데 사용하지만 나중에 입력은 건너뜁니다.comp.lang.c FAQ를 참조해 주세요.

제안된 솔루션에 대해서는 (comp.lang.c FAQ에서 다시 참조):

기본적으로 휴대용 접근법만이 다음 작업을 수행한다고 명시되어 있습니다.

int c;
while ((c = getchar()) != '\n' && c != EOF) { }

의 ★★★★★★★★★★★★★★★★★.getchar() != '\n'하는 것은 을 하면, 「」를 발신할 수 있기 때문입니다.getchar()반환된 문자는 입력 스트림에서 이미 삭제되어 있습니다.

저는 해야 할 생각합니다.scanf완전:왜 다들 쓰지 말라고 하지? 대신 무엇을 사용하면 좋을까요?

다음과 같이 할 수도 있습니다.

fseek(stdin,0,SEEK_END);

아무도 이런 말을 하지 않았다니 놀랍다.

scanf("%*[^\n]");

이미 부분적으로 읽으려고 한 행의 마지막까지 지우기 위한 휴대용 방법은 다음과 같습니다.

int c;

while ( (c = getchar()) != '\n' && c != EOF ) { }

합니다.\n파일의 끝을 알립니다. ,, 음, 음, 음, 다, 다, 다, 다, against, against, against, against, against, against, against, against, against, againstEOF입력 스트림이 종료되기 전에 닫히는 경우.c야 한다.int 그 이상)할 수 ( 「」 「」 「」).EOF.

행 이 더 할 수 행이 더 이상 없는 경우).getchar입력이 차단됩니다).

이것을 시험해 보세요.

stdin->_IO_read_ptr = stdin->_IO_read_end;

scanf영화 워게임의 고전적인 대사가 있는데, "유일한 승부수는 플레이하지 않는 것이다."

「투자를 쇄신」할 필요가 있는 경우는, 이미입니다.가장 좋은 방법은 귀찮은 입력을 지우는 방법을 필사적으로 찾는 것이 아니라 입력 스트림에 읽지 않은 입력을 남기지 않고 더 나은 방법으로 입력을 하는 것입니다.그 때문에 문제가 발생하여 플래시를 시도해야 하는 등 문제가 발생하지 않습니다.

기본적으로 다음 세 가지 경우가 있습니다.

  1. 하다를 사용해서 입력 있습니다.scanf, 그 새이, 에 「Newline」이 「Newline」이라고 에 의해서, 「Newline」이라고 하는 것은, 「Newline 」는, 「Newline 」의 「Newline은, 「Newline 」로 있습니다.getchar ★★★★★★★★★★★★★★★★★」fgets(무엇보다)

  2. 하다를 사용해서 입력 있습니다.scanf, 그 새이, 에 「Newline」이 「Newline」이라고 에 의해서, 「Newline」이라고 하는 것은, 「Newline 」는, 「Newline 」의 「Newline은, 「Newline 」로 있습니다.scanf("%c").

  3. '먹다'를 사용해서 숫자 을 보고 .scanf가 숫자 입력을 , "Non-timeout input", "Non-timeout input", "Non-timeout input", "Non-timeout input"이 됩니다.scanf콜도 실패합니다.

이 세 가지 경우 모두 문제가 되는 입력을 "플래시"하는 것이 올바른 것처럼 보일 수 있습니다.노력은 할 수 있지만, 아무리 잘해도 번거롭고, 최악의 경우 불가능하다.결국, 입력을 플러싱하는 것은 잘못된 접근법이며, 우려하는 경우에 따라서는 더 나은 방법이 있다고 생각합니다.

케이스 1의 경우 콜을 다른 입력 함수와 혼재시키지 않는 것이 좋습니다.다음 중 하나로 모든 입력을 수행합니다.scanf 모든 을 ""로 getchar "/"/"fgets으로 모든 을 할 수.scanf 「」에의 콜을 할 수 .getcharscanf("%c")를를를 2 를 2 ★을 「」로 할 수 있습니다.fgetsscanf("%[^\n]%*c")하지만 이것에는 여러 가지 다른 문제가 있어 추천하지 않습니다.을 ""로 하려면:fgets원/한 것이 scanf에서는 의 구문 분석, 의 구문 에서는 의 분석, 의 구문 분석 등을 하여 행을 읽을 수 fgets '', '보다', '보다'를 사용해서 분석합니다.sscanf.

케이스 2의 경우는, 「절대 사용하지 않는다」라고 하는 것이 좋습니다.사용하다scanf(" %c") the. 의 여유 큰 차이를 . 이 되는지에 는 긴 이 답변의 벗어납니다.

그리고 사례 3에서는 좋은 해결책이 없는 것 같습니다. scanf에는 많은 문제가 있습니다.그 많은 문제 중 하나는 에러 처리가 형편없다는 것입니다.숫자 입력을 읽는 간단한 프로그램을 작성하고 사용자가 항상 적절한 숫자 입력을 요구할 때 입력한다고 가정할 수 있는 경우scanf("%d")적절한 입력 방법이 될 수 있습니다(거의 적절하지 않습니다).다만, 유저에게 수치를 입력하도록 지시해, 유저가 실제로 수치를 입력했는지 확인해, 입력하지 않은 경우는, 에러 메세지를 인쇄해 재시도하도록 유저에게 요구하는 것이 목적이라면, 에 근거해 이 목표를 달성할 수 없다고 생각합니다.시도는 할 수 있지만, 마치 아기에게 외투를 씌우는 것과 같습니다. 두 번째 팔을 넣으려고 할 때 한쪽 다리가 꿈틀거립니다.잘못된 숫자 입력을 읽고 검증하는 것은 너무 많은 작업입니다.scanf을 사용하다

세 경우 '을 읽고 '로시작하는 를 알 수.입력 내용을 읽고 있습니다.scanf"..." 여기에는 피할 수 없는 결론이 있습니다.다음 질문을 참조하십시오.scanf 대신 입력 변환에 사용할 수 있는 것은 무엇입니까?

난 아직 네 질문에 대답하지 않았다는 걸 깨달았어사람들이 "X를 어떻게 하면 좋을까요?"라고 물었을 때, 모든 대답이 "X를 하고 싶지 않습니다."라고 대답할 때, 매우 답답할 수 있습니다.만약 당신이 정말로, 정말로 입력을 쇄도하고 싶다면, 여기에 있는 사람들이 당신에게 준 다른 대답 외에, 다음의 두 가지 좋은 질문들이 있습니다.

하지만 그게 어떻게 돌아가는지 설명할 수 없다고요? 「」를 사용하고, 「」를 사용하고 있기 에,getchar() != '\n' '읽기', '1'을 제외한 모든 한.'\n'입니다.'\n'??? 하고 있는 야?가가 뭘뭘 ?고 ?? ???

여러분이 깨닫지 못할 수도 있는 것은 비교가 다음에 일어난다는 것입니다. getchar()입력 버퍼에서 문자를 삭제합니다. '이렇게'에했을 때'\n'소비된 후 루프에서 이탈합니다.

해 볼 수 있습니다

scanf("%c%*c", &ch1);

여기서 %*c는 줄바꿈을 받아들이고 무시합니다.

정의되지 않은 동작을 호출하는 fflush(stdin) 대신 쓸 수 있는 다른 방법

while((getchar())!='\n');

while loop 뒤에 세미콜론을 잊지 마세요.

회선:

int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
    ;

행피드 앞의 만을 읽어 ( 를 참조해 주세요).'\n'다음 줄바꿈(또는 EOF가 발생)까지 스트림 내의 모든 문자를 읽습니다(및 그것들을 파기합니다).테스트가 참이 되려면 먼저 라인피드를 읽어야 합니다. 따라서 루프가 정지하면 라인피드가 마지막으로 읽혔지만 이미 읽혔습니다.

캐리지 리턴이 아닌 라인피드를 읽는 이유는 시스템이 리턴을 라인피드로 변환했기 때문입니다.Enter 키를 누르면 회선의 끝이 표시됩니다.그러나 스트림에는 라인 피드가 포함되어 있습니다.이것은 시스템의 일반적인 엔드 오브 라인 마커이기 때문입니다.플랫폼에 따라 다를 수 있습니다.

「 」, 「 」를 사용합니다.fflush()입력 스트림이 모든 플랫폼에서 동작하는 것은 아닙니다.【Linux】【Linux】【Linux】【Linux】【Linux】【Linux】【Linux】【Linux】【Linux】【Linux】키로 했다.

솔루션을 구현하려고 할 때 문제가 발생함

while ((c = getchar()) != '\n' && c != EOF) { }

같은 문제가 있을 수 있는 사람을 위해 약간의 수정 사항 '코드 B'를 게시합니다.

문제는 프로그램에 의해 엔터 문자와는 별개로 '\n' 문자가 계속 잡혔다는 것입니다.이것이 문제의 원인이 된 코드입니다.

코드 A

int y;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   continue;
}
printf("\n%c\n", toupper(y));

그리고 조정은 (n-1)자를 평가하기 직전에 (while loop) 조건부로 하는 것입니다.다음 코드는 다음과 같습니다.

코드 B

int y, x;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   x = y;
}
printf("\n%c\n", toupper(x));

생각할 수 있는 설명은 while loop이 끊기 위해서는 변수 y에 값 \n을 할당해야 하기 때문에 이것이 마지막으로 할당된 값이 된다는 것입니다.

만약 제가 설명, 코드 A 또는 코드 B를 놓쳤다면, 저는 c에 거의 익숙하지 않습니다.

도움이 되기를 바라다

쇼트, 휴대성, stdio.h로 선언

stdin = freopen(NULL,"r",stdin);

stdin에 다음 well-know line과 같이 플러시할 것이 없는 경우 무한 루프에 걸리지 않습니다.

while ((c = getchar()) != '\n' && c != EOF) { }

조금 비싸기 때문에 버퍼를 반복해서 클리어해야 하는 프로그램에서는 사용하지 마십시오.

동료로부터 도난당함 :)

unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

-혹은...

_getch_nolock()

아직 언급되지 않은 또 다른 솔루션은 rewind(stdin)를 사용하는 것입니다.

간단히 말하면.줄을 놓는 중...

while ((c = getchar()) != '\n') ;

...입력값을 판독하는 라인이 유일하게 보장되는 방법입니다.모든 상황에서 모든 컴파일러와 함께 동작할 수 있는 것이 보증되는 코어 C 기능(K&R에 따르면 "C 언어의 기존 코어")만을 사용합니다.

실제로는 ENTER 키를 눌러 계속 진행하도록 사용자에게 요구하는 프롬프트를 추가할 수도 있습니다(또는 Ctrl+D 또는 기타 버튼을 눌러 종료하거나 다른 코드를 실행할 수도 있습니다).

printf("\nPress ENTER to continue, press CTRL-D when finished\n");    
while ((c = getchar()) != '\n') {
        if (c == EOF) {
            printf("\nEnd of program, exiting now...\n");
            return 0;
        }
        ...
    }

아직 문제가 있어요.사용자는 ENTER를 여러 번 누를 수 있습니다.이 문제는 입력 라인에 입력 체크를 추가하여 해결할 수 있습니다.

while ((ch2 = getchar()) < 'a' || ch1 > 'Z') ;

이론적으로 위의 두 가지 방법의 조합은 방탄이어야 한다.그 외의 모든 측면에서는 @jamesdlin의 답변이 가장 포괄적입니다.

빠른 해결책은 ch2가 캐리지 리턴을 일시적으로 먹도록 두 번째 스캔을 추가하는 것입니다.어떤 체크도 하지 않기 때문에, 유저가 착하게 플레이 하는 것을 전제로 하고 있습니다.정확히 입력 버퍼를 지우는 것은 아니지만 정상적으로 작동합니다.

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  scanf("%c", &ch2); // This eats '\n' and allows you to enter your input
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

stdin에서 입력을 받아 추가 입력(문자)을 폐기하는 함수를 작성했습니다(및 테스트도 실시했습니다).이 함수는 get_input_from_stdin_and_discard_extra_characters(char *str, int size)라고 불리며 최대 "size - 1"자로 읽혀져 마지막에 "\0"이 추가됩니다.

코드는 다음과 같습니다.


/* read at most size - 1 characters. */
char *get_input_from_stdin_and_discard_extra_characters(char *str, int size)
{

    char c = 0;
    int num_chars_to_read = size - 1;
    int i = 0;

    if (!str)
        return NULL;

    if (num_chars_to_read <= 0)
        return NULL;

    for (i = 0; i < num_chars_to_read; i++) {

        c = getchar();

        if ((c == '\n') || (c == EOF)) {
            str[i] = 0;
            return str;
        }

        str[i] = c;

    } // end of for loop

    str[i] = 0;

    // discard rest of input
    while ((c = getchar()) && (c != '\n') && (c != EOF));

    return str;

} // end of get_input_from_stdin_and_discard_extra_characters

'Clear'를 클리어 할 수 요?stdin력력로 로로 로로 로로로 로로?

cppreference.com 커뮤니티 Wiki 상태 참조(추가 정보):

입력 스트림(및 마지막 작업이 입력된 업데이트스트림)의 경우 동작은 정의되지 않습니다.

그러니 사용하지 마세요.fflush()stdin..

"플러싱"'세상화'의 목표가의 만약 여러분의 목표.stdin모든 chars은그 안에에 앉아 있숯을 제거하는 것입니다 모든 있는을 제거하는 거야stdin버퍼를 사용하는 가장 좋은 방법은 또는 (같은 작업)을 수동으로 사용하는 것입니다.또, POSIX 또는 Linux 를 사용하고 있는 경우는 (첫 번째 인수로 사용하는 경우도 있습니다.

가장 많이 인용된 답변은 다음과 같습니다.

int c;
while ((c = getchar()) != '\n' && c != EOF);

이렇게 하는 것이 더 명료한 방법이라고 생각합니다.물론 제 코멘트는 저의 접근방식을 지금보다 훨씬 더 길게 보이게 합니다.

/// Clear the stdin input stream by reading and discarding all incoming chars up
/// to and including the Enter key's newline ('\n') char. Once we hit the
/// newline char, stop calling `getc()`, as calls to `getc()` beyond that will
/// block again, waiting for more user input.
/// - I copied this function
///   from "eRCaGuy_hello_world/c/read_stdin_getc_until_only_enter_key.c".
void clear_stdin()
{
    // keep reading 1 more char as long as the end of the stream, indicated by
    // `EOF` (end of file), and the end of the line, indicated by the newline
    // char inserted into the stream when you pressed Enter, have NOT been
    // reached
    while (true)
    {
        int c = getc(stdin);
        if (c == EOF || c == '\n')
        {
            break;
        }
    }
}

예를 들어, 이 기능은 여기 있는 두 개의 파일에 사용합니다. 파일의 콘텍스트를 참조해 주세요.stdinmost-useful일 수 있습니다.가장 중요한 것은다음과 같습니다.

  1. array_2d_fill_from_user_input_scanf_and_getc.c
  2. 읽기_stdin_getc_until_only_enter_key.c

자기 메모:저는 원래 이 답변을 여기에 올렸습니다만, 그 후 이 답변을 삭제하여 대신 이 답변만 남겨두었습니다.

언급URL : https://stackoverflow.com/questions/7898215/how-to-clear-input-buffer-in-c

반응형