0

I have the question that was asked here.

The top answer had two recommendations, and one of them (which was presented as slightly more reliable) was to use setbuf(stdin, NULL);. However, the setbuf() function is deprecated, and the replacement function is setvbuf(). I am unsure how to use the parameters for this new function in a way that replicates the old function; how do I do this?

Background: when I use getchar() in a loop, the second iteration of the loop always reads the '\n' character next, and I want to get rid of that.

Brandon_J
  • 172
  • 1
  • 16
  • 1
    Can you be more clear on why you want to disable buffering? If it's to avoid problems with newline interlacing between `scanf` and `fgets`, as alluded to in the [linked question](https://stackoverflow.com/questions/34219549/how-to-properly-flush-stdin-in-fgets-loop), that's a horrible way to "solve" that problem, and I'm not at all sure it'd even work. – Steve Summit Nov 30 '19 at 18:09
  • 1
    At least 99% of the time, if you're trying to "flush the input buffer", it's because of recurring problems with `scanf` that are best solved some other way. Please don't try to flush input (much less disable input buffering for this reason). Please either learn how to use `scanf` correctly, or (since using it correctly is all but impossible), learn about alternatives to `scanf`. See also [here](https://stackoverflow.com/questions/18170410), [here](https://stackoverflow.com/questions/2979209), and [here](https://stackoverflow.com/questions/58403537). – Steve Summit Nov 30 '19 at 18:12
  • @SteveSummit I'll edit this into the question in a moment, but I'm attempting to use `getchar()` in a loop. – Brandon_J Nov 30 '19 at 18:15
  • *when I use getchar() in a loop, the second iteration of the loop always reads the '\n' character next* It sounds like you're asking the user to type a character, and the user is typing a character and hitting the Enter key, so you're getting two characters. That's correct and expected behavior, and "flushing" won't help. – Steve Summit Nov 30 '19 at 19:11
  • If you're expecting a 1-character response from the user, and depending on what kind of program you're writing, I recommend either (1) investigating how to [read input immediately without waiting for the Return key](https://stackoverflow.com/questions/10152381) or (2) reading a *line* of input using `fgets` and then (after stripping the newline from the buffer) complaining if it's not a line of length 1. – Steve Summit Nov 30 '19 at 19:44
  • You are on a wrong road, by a hundred miles. – n. 'pronouns' m. Dec 01 '19 at 05:25

2 Answers2

2

In answer to your stated question, the best setvbuf equivalent of

setbuf(stdin, NULL);

should be

setvbuf(stdin, NULL, _IONBF, 0);

Contrary to the note in the documentation you linked, however, I'm not aware of setbuf being deprecated, however, and I'm not aware of any disincentives to using it.

And, as I mentioned in the comments, if the reason you want to disable buffering is as a workaround for the problem that scanf tends to leave newlines "in the buffer" thus causing problems later, I would say that disabling buffering entirely is a particularly poor way of addressing that problem.

Steve Summit
  • 29,350
  • 5
  • 43
  • 68
  • Would you disagree with the answer to the linked question? If setvbuf is a poor solution to my problem, I'm not sure how to find the correct solution without asking a duplicate of the linked question. – Brandon_J Nov 30 '19 at 18:22
  • 1
    @Brandon_J I disagree strongly with the parts of that answer recommending `fflush(stdin)` and `setbuf(stdin, NULL)`, yes. – Steve Summit Nov 30 '19 at 18:23
  • heh, that's pretty much the entire answer. Would it be out of line for me to ask what your answer to that question would be? – Brandon_J Nov 30 '19 at 18:25
  • Also, VS 2019 doesn't allow setbuf (says it's deprecated). – Brandon_J Nov 30 '19 at 18:26
  • @Brandon_J This comment box is way too small for a full answer to that question. If you use poor input techniques in C, newline management can be a huge problem. But if you use good techniques (like, use `fgets` for everything), it's generally not a problem at all. If you *are* having newline problems, my suggestions would be (1) don't use `scanf`, (2) if you must use `scanf`, don't mix it with other input methods like `getchar` and `fgets`, and (3) if you must mix, meaning that you do need to flush newlines, do so using `while((c = getchar()) != '\n' && c != EOF)`. – Steve Summit Nov 30 '19 at 18:29
  • 2
    @Brandon_J There's a big difference between "Microsoft says X is deprecated" and "X is disallowed". I don't believe `setbuf` is disallowed anywhere, and I don't believe it's deprecated by anyone other than Microsoft, either. – Steve Summit Nov 30 '19 at 18:31
  • 2
    @Brandon_J When Microsoft says something is deprecated, it's bullsh*t. When ISO says something is deprecated, it's true. – S.S. Anne Nov 30 '19 at 18:33
  • @Brandon_J *what would your answer to that question be?* I've now [written it](https://stackoverflow.com/questions/34219549/how-to-properly-flush-stdin-in-fgets-loop/59119187#59119187). – Steve Summit Nov 30 '19 at 18:53
  • @Brandon_J The linked question fully deserves to be closed, and the accepted answer has no useful content. Ask a question that shows your program, its input verbatim, its desired behaviour, and its actual behaviour. – n. 'pronouns' m. Dec 01 '19 at 05:33
1

The manpage states this (added parameters to setbuf for ease of understanding):

The other three calls are, in effect, simply aliases for calls to setvbuf(). The setbuf(FILE *stream, char *buf) function is exactly equivalent to the call

setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);

Therefore, your call would be equivalent to:

setvbuf(stream, NULL, _IONBF, BUFSIZ);

because NULL is false.

However, a much easier way to avoid the \n in a loop with getchar is to simply do this:

int c;
while((c = getchar()) != EOF)
{
    if(c == '\n')
        continue;
    /* use c as a character */
}

I'd also like to note that setbuf isn't deprecated. As a general rule, all of the functions not beginning with an underscore in Windows that are present in POSIX and not in the ANSI C standard are "deprecated" in Microsoft's eyes. If you use the underscore-prefixed versions, though, your code won't be portable. What a rabbit hole.

S.S. Anne
  • 13,819
  • 7
  • 31
  • 62