C에서 입력 버퍼를 지우는 방법은 무엇입니까?


84

다음 프로그램이 있습니다.

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 키를 누르면 입력 버퍼 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' );
    }
    

이 코드는 실제로 작동했습니다. 하지만 어떻게 작동하는지 스스로 설명 할 수 없습니까? while 문에서를 사용하므로 ?를 getchar() != '\n'제외한 모든 단일 문자를 읽습니다 '\n'. 그렇다면 입력 버퍼에 여전히 '\n'문자 가 남아 있습니까?

답변:


89

라인 1에서 사용자가 Enter 키를 누르면 입력 버퍼 2 문자 인 Enter 키 (ASCII 코드 13) 및 \ n (ASCII 코드 10)에 남아 있으므로 프로그램이 제대로 작동하지 않습니다. 따라서 2 행에서 \ n을 읽고 사용자가 문자를 입력 할 때까지 기다리지 않습니다.

2 행에서 보는 동작은 정확하지만 정확한 설명은 아닙니다. 텍스트 모드 스트림에서는 플랫폼에서 사용하는 줄 끝 (캐리지 리턴 (0x0D) + 줄 ​​바꿈 (0x0A), 베어 CR 또는 베어 LF)이 무엇인지는 중요하지 않습니다. C 런타임 라이브러리가이를 처리합니다. 프로그램은 '\n'개행 문자 만 볼 것 입니다.

문자를 입력하고 Enter 키를 누르면 해당 입력 문자를 1 행에서 읽은 다음 '\n'2 행 에서 읽습니다. Y / N 응답을 읽는 데 사용 scanf %c하고 있지만 나중에 입력을 건너 뜁니다. comp.lang.c FAQ에서.

제안 된 솔루션에 대해서는 다음을 참조하십시오 (comp.lang.c FAQ에서 다시 참조).

기본적으로 유일한 이식 가능한 접근 방식은 다음과 같습니다.

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

당신의 getchar() != '\n'당신이 전화를 한 번 때문에 루프 작동 getchar(), 반환 된 캐릭터가 이미 입력 스트림에서 제거되었습니다.

또한, 나는 당신이 scanf완전히 사용하는 것을 막아야 할 의무가 있다고 느낍니다 . 왜 모든 사람들이 사용하지 말라고 말하는가 scanf? 대신 무엇을 사용해야합니까?


1
사용자가 Enter 키를 누를 때까지 대기합니다. 단순히 stdin을 지우려면 termios를 직접 사용하십시오. stackoverflow.com/a/23885008/544099
— ishmael

@ishmael Enter 키를 눌러 stdin 을 지울 필요가 없기 때문에 귀하의 의견이 의미가 없습니다 . 먼저 입력을 받아야합니다. (그리고 이것이 C에서 입력을 읽는 유일한 표준 방법입니다. 키를 즉시 읽을 수 있으려면 비표준 라이브러리를 사용해야합니다.)
— jamesdlin

@jamesdlin Linux에서 getchar ()는 사용자가 Enter 키를 누를 때까지 기다립니다. 그래야만 while 루프에서 벗어날 수 있습니다. 내가 아는 한 termios는 표준 라이브러리입니다.
— ishmael 2019

@ishmael 아니요, 두 가지 모두 틀 렸습니다. 이 질문은 입력 을 읽은 후 stdin에서 나머지 입력을 지우는 방법 과 표준 C에서 해당 입력을 먼저 입력하고 Enter 키를 눌러야하는 경우에 대한 것입니다. 해당 줄을 입력 한 후getchar() 해당 문자를 읽고 반환합니다. 사용자는 다시 Enter 키를 누를 필요가 없습니다. 또한 termios는 Linux 에서 공통적 일 수 있지만 C 표준 라이브러리의 일부가 아닙니다 .
— jamesdlin

scanf(" %c", &char_var)% c 지정자 앞에 공백을 추가하여 개행을 무시하고 작동 하는 이유는 무엇 입니까?
— Cătălina Sîrbu

44

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

fseek(stdin,0,SEEK_END);

와우 ... btw, 표준 fseek은 사용할 수 있다고 말 stdin합니까?
— ikh

3
나는 그것을 언급하지 않는다고 생각한다. 그러나 stdin은 FILE *이고 fseek는 FILE * 매개 변수를 받아 들인다. 테스트했는데 Mac OS X에서는 작동하지만 Linux에서는 작동하지 않습니다.
— Ramy Al Zuhouri 2014 년

설명 해주십시오. 저자가이 방법의 시사점을 작성한다면 훌륭한 대답이 될 것입니다. 문제가 있습니까?
— EvAlex

7
@EvAlex : 이것과 관련된 많은 문제가 있습니다. 시스템에서 작동하면 좋습니다. 그렇지 않다면 표준 입력이 대화 형 장치 (또는 파이프, 소켓 또는 FIFO와 같은 검색 불가능한 장치) 일 때 작동 할 것이라는 보장이 없다는 것은 놀라운 일이 아닙니다. 불합격).
— Jonathan Leffler

SEEK_END 여야하는 이유는 무엇입니까? 대신 SEEK_SET을 사용할 수 있습니까? FP stdin은 어떻게 작동합니까?
— Rajesh

11

이미 부분적으로 읽으려고 한 줄의 끝까지 정리하는 이식 가능한 방법은 다음과 같습니다.

int c;

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

이것은 \n파일의 끝을 알릴 때까지 문자를 읽고 버립니다 . 또한 EOF입력 스트림이 줄이 끝나기 전에 닫히는 경우를 확인합니다 . 값을 보유하려면 의 유형이 (또는 그 이상) c이어야합니다 .intEOF

현재 줄 뒤에 줄이 더 있는지 알아내는 이식 가능한 방법은 없습니다 (없으면 getchar입력을 차단합니다).


왜 while ((c = getchar ())! = EOF); 작동하지 않습니까? 무한 루프입니다. stdin에서 EOF의 위치를 ​​이해할 수 없습니다.
— Rajesh

@Rajesh 입력 스트림이 닫힐 때까지 삭제됩니다. 나중에 입력 할 입력이 더 있으면 없을 것입니다.
— MM

@Rajesh 네, 맞습니다. 이것이 호출 될 때 플러시 할 stdin이 없으면 무한 루프에 걸리기 때문에 차단 (중지)됩니다.
— Jason Enochs

11

선:

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

줄 바꿈 ( '\n') 앞의 문자 만 읽지 않습니다 . 다음 줄 바꿈 (또는 EOF가 발견됨 ) 까지 스트림의 모든 문자를 읽고 삭제합니다 . 테스트가 참이 되려면 먼저 줄 바꿈을 읽어야합니다. 따라서 루프가 중지되면 줄 바꿈은 마지막으로 읽은 문자이지만 읽은 것입니다.

캐리지 리턴 대신 라인 피드를 읽는 이유는 시스템이 리턴을 라인 피드로 변환했기 때문입니다. 엔터를 누르면 라인의 끝을 알립니다 ...하지만 스트림에는 시스템의 일반 라인 끝 마커이기 때문에 대신 라인 피드가 포함됩니다. 플랫폼에 따라 다를 수 있습니다.

또한 fflush()입력 스트림 에서 사용 하는 것이 모든 플랫폼에서 작동하는 것은 아닙니다. 예를 들어 일반적으로 Linux에서는 작동하지 않습니다.


참고 : 파일 끝으로 인해 while ( getchar() != '\n' );무한 루프가 getchar()반환 되어야 EOF합니다.
— chux-Monica 복원

물론, 같은 EOF를 확인하려면 int ch; while ((ch = getchar()) != '\n' && ch != EOF);사용할 수 있습니다
— 드미트리

8

하지만 어떻게 작동하는지 스스로 설명 할 수 없습니까? while 문에서를 사용하므로 ??를 getchar() != '\n'제외한 모든 단일 문자를 읽습니다 '\n'. 그렇다면 입력 버퍼에 여전히 '\n'문자 가 남아 있습니까 ??? 내가 뭔가를 오해하고 있습니까 ??

인식하지 못할 수있는 것은 입력 버퍼에서 문자를 제거한 후에 비교가 발생한다는 것입니다 getchar(). 당신이 도달했을 때 그래서 '\n',이 소비되고 다음 당신은 루프의 탈출.


6

당신은 시도 할 수 있습니다

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

% * c는 개행을 허용하고 무시합니다.

정의되지 않은 동작을 호출하는 fflush (stdin) 대신 작성할 수있는 메서드가 하나 더 있습니다.

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

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


2
1) "%*c"개행 문자이든 다른 문자이든 모든 문자를 스캔합니다 (저장하지 않음). 코드는 두 번째 문자가 새 줄에 의존합니다. 2) 파일 끝으로 인해 while((getchar())!='\n');무한 루프가 getchar()반환 되어야 EOF합니다.
— chux-Monica 복원

1
두 번째 방법은 개행, 널 문자, EOF 등과 같은 조건에 따라 달라집니다 (위는 개행)
— kapil

1

솔루션을 구현하는 데 문제가 발생했습니다.

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

그리고 조정은 while 루프의 조건이 평가되기 직전에 (n-1) 문자를 'catch'하는 것이 었습니다. 다음은 코드입니다.

코드 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 루프가 중단 되려면 변수 y에 '\ n'값을 할당해야하므로 마지막으로 할당 된 값이됩니다.

설명, 코드 A 또는 코드 B와 함께 뭔가를 놓친 경우 나에게 말 해주세요, 나는 c에서 거의 새롭지 않습니다.

누군가에게 도움이되기를 바랍니다


루프 내에서 " 예상 된 "문자를 처리해야 while합니다. 루프 후에는 고려할 수 stdin로 / 클린 앤 클리어 와 y중 개최한다 ' \n'또는 EOF. EOF개행이없고 버퍼가 고갈 될 때 반환됩니다 (입력 [ENTER]이 눌러 지기 전에 버퍼가 오버플로되는 경우 ). -를 효과적으로 사용 while((ch=getchar())!='\n'&&ch!=EOF);하여 stdin입력 버퍼의 모든 문자를 씹습니다 .
— veganaiZe

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

-또는-

사용 _getch_nolock().. ???


문제는 C ++가 아니라 C에 관한 것입니다.
— Spikatrix

1
하는 것으로 kbhit()하고 getch()선언 함수입니다 <conio.h>및 Windows에서 표준으로 만 사용할 수는. Unix와 유사한 컴퓨터에서 에뮬레이션 할 수 있지만 그렇게하려면 약간의주의가 필요합니다.
— 조나단 레플러

0

아직 언급되지 않은 또 다른 해결책은 다음을 사용하는 것입니다. rewind (stdin);


2
stdin이 파일로 리디렉션되면 프로그램이 완전히 중단됩니다. 대화 형 입력의 경우 아무 작업도 수행하지 않을 수도 있습니다.
— melpomene 19

0

아무도 이것을 언급하지 않은 것에 놀랐습니다.

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

-1

짧고 이식 가능하며 stdio.h에서 선언 됨

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

다음 잘 알고있는 줄과 같이 플러시 할 stdin에 아무것도 없을 때 무한 루프에서 중단되지 않습니다.

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

약간 비싸므로 버퍼를 반복적으로 지워야하는 프로그램에서는 사용하지 마십시오.

동료에게서 훔쳤습니다 :)


Linux에서는 작동하지 않습니다. 대신 termios를 직접 사용하십시오. stackoverflow.com/a/23885008/544099
— ishmael

2
잘 알려진 선이 무한 루프가 가능한 이유를 자세히 설명해 주시겠습니까?
— Cacahuete Frito

freopen존재 하는 모든 이유 는에 이식 가능하게 할당 할 수 없기 때문 stdin입니다. 매크로입니다.
— melpomene 19

1
ishmael : 여기 Cyber ​​Command의 모든 컴퓨터는 Linux이며 잘 작동합니다. 데비안과 페도라 모두에서 테스트했습니다.
— Jason Enochs 19

"무한 루프"라고 부르는 것은 입력을 기다리는 프로그램입니다. 그것은 같은 것이 아닙니다.
— jamesdlin

당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.