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.