C의 입력 버퍼를 비우는 방법

HDNua의 이미지

안녕하세요. 휴가 나온 군인입니다.

제가 봤던 입문서에서도 그랬지만 Windows에서 입력 버퍼를 비울 때는
fflush(stdin)을 호출하여 입력 버퍼를 제법 간단히 비울 수 있습니다.
다만 이건 Windows에서만 가능한 것이고 다른 운영체제에선 정의되지 않은 동작이다라는 설명이 붙어있군요.

그래서 저는 모든 운영체제에 범용적으로 적용 가능한 clearReadBuffer를 만드려고 검색도 해보고 많은 노력을 했습니다.

1번 방법

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

가장 널리 알려진 방법이지만 입력 버퍼가 이미 비어있는 경우에 사용자로부터 입력을 받기 위해 대기하는 게 가장 큰 문제입니다.
엔터를 두 번 이상 치던지 일부러 잘못된 입력을 넣던지 해야 제대로 동작하는 경우가 있습니다.

2번 방법

void clearReadBuffer() {
 if (stdin->_cnt)
  while (getchar() != '\n');
}

입대 전까지 애용하던 입력 버퍼 삭제 함수입니다. 아주 잘 동작하지만
Mac OS X에서는 _cnt 멤버의 역할을 _r 멤버가 했기 때문에 운영체제가 달라지면 매번 이 함수를 수정해야 합니다.

3번 방법

int isBufferEmpty(FILE *stream) {
 return (stream->_cnt > 0);
}
void clearReadBuffer() {
 while (!isBufferEmpty(stdin))
  getchar();
}

지금 새로 고안했는데, 개행 이후에도 문자가 남아있는 경우에도 확실하게 입력 버퍼를 비울 수 있습니다.
다만 2번 방법에서 존재하던 문제는 해결되지 않았습니다. (서로 분리한다면 2번보다야 적게 수정할 수 있지 않을까 합니다.)

4번 방법

void clearReadBuffer() {
 fseek(stdin, 0, SEEK_END);
}

인터넷을 검색하다 stackoverflow에서 찾은 아주 참신한 방법이지만, 이해하기 힘들어 모든 운영체제에서 반드시 옳다고 할 수가 없습니다.
https://stackoverflow.com/questions/7898215/how-to-clear-input-buffer-in-c/9750394#9750394
(링크는 위. 본인도 리눅스에서 이것이 항상 옳은지 확인하지 못했다고 합니다.)

-----
1. 3번 방법에서 isBufferEmpty를 대체할 표준 함수가 C 라이브러리에 정의되어있을까요?
처음에는 입력 버퍼의 끝에 도달했다면 feof로 검출할 수 있을 줄 알고 이를 이용해봤지만 뜻대로 되지 않습니다.

2. 4번 방법이 항상 옳다면 왜 그런지 설명해주시면 감사하겠습니다. 버퍼의 끝으로 포인터를 옮기는 것 같은데
컴파일러 구현에 따라 다를 수도 있는 내용이 아닌지, 아니면 그렇게 구현하는 것이 표준인지 궁금합니다.

3. C에서 입력 버퍼를 비우는 더 멋진 방법을 알고 계시는 분은 답변 부탁합니다.

이런 이유로 KLDP에 도움을 청합니다.
읽어주셔서 감사합니다.

peecky의 이미지

int isBufferEmpty(FILE *stream) {
#ifdef __APPLE__
    return (stream->_r > 0);
#else
    return (stream->_cnt > 0);
#endif
}

이런 방법도 있습니다.

HDNua의 이미지

그냥 isBufferEmpty() 함수를 시스템 별로 만드는 것 외엔 방법이 없을까요?
궁금해서 문서를 계속 뒤지고 있는데 도움이 될 만한 어떤 문서도 찾을 수가 없습니다.

문자 배열에 입력 버퍼의 내용을 모두 옮긴 다음 이 배열을 체크할 수도 있지만
입력 버퍼가 비어있는지 확인하는, 간단하면서도 '분명 엄청나게 유용한' 이런 함수를
구현하지 않았을 것 같지 않습니다.

뭐 없다면 어쩔 수 없는데 답답하네요.

저는 이렇게 생각했습니다.

bushi의 이미지

if (isatty(fileno(stream))) tcflush(fileno(stream), TCIFLUSH);
HDNua의 이미지

그냥 fflush가 안 동작하니 tcflush로 바꾼 게 전부네요.
tcflush를 찾아보니 리눅스에서 동작하도록 되어있다는데 좀 더 찾아봐야겠습니다.

저는 이렇게 생각했습니다.

bushi의 이미지

괜한 것을 던진 것 같네요.
tcflush() 에 집중하지 말고 POSIX terminal 의 canonical mode 에 대해 공부하시면 그나마 뭔가 좀 남는 삽질이었다고 자위하실 수 있을 겁니다.

cinsk의 이미지

먼저, 왜 입력 버퍼를 비우는 기능이 필요한지 생각해 보세요. 그런 기능 없이 충분히 프로그램 작성할 수 있을 텐데요.

HDNua의 이미지

중요한 건 아니고.. 그냥 궁금해서 한 질문이었습니다.
MSP Code Challenge라고 학교 과제 비스무리한 걸 하는데 잘못된 입력으로 오류가 나면 틀린 답이라고 되어있어서
어느 환경에서나 반드시 입력 버퍼를 비울 수 있으면 좋겠다는 생각이 문득 들어서요.

결국엔 그냥 직접 버퍼를 만들어 문자열로 받고 변수로 변환한 다음 이 버퍼를 비우는 식으로 해결했습니다.

저는 이렇게 생각했습니다.

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.