Basic noob question re console input

J

James Kuyper

Yes, of course, but I don't understand *exactly* why it's required, as
in, I haven't seen for myself, but I'll get there.

Your call to printf() doesn't include a newline character before calling
fgets(). If stdout is unbuffered, it should work exactly as you expect,
but that's pretty uncommon. stdout is normally line-buffered, in which
case the user won't see any output until the next time your program
prints a newline.
stdout is permitted to be fully buffered only if the implementation
cannot determine that stdout is connected to an interactive device.
Systems where that can be determined are commonplace, and
implementations for systems where it cannot be determined will generally
not take advantage of that fact. However, if an implementation does
choose to fully buffer stdout, the failure mode is even more confusing:
if your call to printf() doesn't fill up the buffer, the user won't see
anything. If it does fill up the buffer, the buffer will be output, but
it's likely to be the case that only part of your prompt will be
printed, the rest will be put at the beginning of the newly-flushed buffer.
int getChoice2(void){

int BUFSIZE = 4;
char buffer[BUFSIZE];
int count = 0, choice = 0;

while(count == 0 || count == EOF){

printf("%s", "Input an integer >> ");
fflush(stdout);
if(NULL != fgets(buffer, BUFSIZE, stdin)){
count = sscanf(buffer, "%d", &choice);
stdin[0]._IO_read_ptr = stdin[0]._IO_read_end;

It is generally an extremely bad idea to fiddle with the contents of a
FILE*. In addition to making your code unportable, there's a pretty good
chance that your fiddling with that structure may interfere with use of
Well I can't comment on that as I only have a Linux box here. I think I
have an old Windows machine around somewhere, maybe I'll dig it out
although the processor architecture is likely the same.

It's the architecture of <stdio.h> that matters, the processor
Anyway, if you look at how

getchar();
fgetc();
scanf();

and

fgets();

work they all work by advancing the read pointer if they successfully
read one or or more characters, advancing the read pointer 'by hand'
simply simulates a read ... it's just much, much faster.

The fact that they work that way is highly system-specific. Don't expect
any portability, whatsoever, of code that is based upon such assumptions.
 
B

Barry Schwarz

On 14/02/14 14:50, Eric Sosman wrote:
snip


Well I can't comment on that as I only have a Linux box here. I think I
have an old Windows machine around somewhere, maybe I'll dig it out
although the processor architecture is likely the same.

Anyway, if you look at how

getchar();
fgetc();
scanf();

and

fgets();

work they all work by advancing the read pointer if they successfully
read one or or more characters, advancing the read pointer 'by hand'
simply simulates a read ... it's just much, much faster. I'm currently
investigating what happens to the pushback pointer etc

Advancing the pointer by hand assumes you know the structure of the
control data pointed to by stdin. Not all systems are intel based.
Not all systems will use the naming convention yours does. Even the
assumption that stdin points to a struct is unsupportable. And on
what do you base your conclusion that setting stdin[0]._IO_read_ptr to
the current value of stdin[0]._IO_read_end is either appropriate or
sufficient?
 
R

Robbie Brown

snip


Advancing the pointer by hand assumes you know the structure of the
control data pointed to by stdin.

cat /usr/include/libio.h
Not all systems are intel based.
Not all systems will use the naming convention yours does. Even the
assumption that stdin points to a struct is unsupportable. And on
what do you base your conclusion that setting stdin[0]._IO_read_ptr to
the current value of stdin[0]._IO_read_end is either appropriate or
sufficient?

Observation. Inspecting the values of the various pointers using gdb
watching what happens call by call, line by line for several different
functions that can be used to read stdin ... experimentation, testing
and testing again ... but it's all a fair point, I've never had to worry
about portability before, I thought it might be too good to be true.
 
K

Keith Thompson

James Kuyper said:
Your call to printf() doesn't include a newline character before calling
fgets(). If stdout is unbuffered, it should work exactly as you expect,
but that's pretty uncommon. stdout is normally line-buffered, in which
case the user won't see any output until the next time your program
prints a newline.

It's not that uncommon. On Unix-like systems, at least in my
experience, stdout is commonly unbuffered if it's writing to an
interactive device.

Streams can be unbuffered, line buffered, or fully buffered. Both ISO C
and POSIX merely require stdout to be either unbuffered or line buffered
if it refers to an interactive device, so you shouldn't depend on it
being unbuffered.

Adding `fflush(stdout);` after printing a partial line is good practice,
and it makes your code more portable, but *on some systems* it may not
make any visible difference in behavior.

[snip]
 
M

Malcolm McLean

It's not that uncommon. On Unix-like systems, at least in my
experience, stdout is commonly unbuffered if it's writing to an
interactive device.
In fact it's deeply evil. Unix programmers like to connect programs
together with pipes. Which is great. Until you need some interactivity,
or a two-way communication, a full duplex pipe in the jargon.

Then you find that the pipes keep on hanging because of buffers. Process
one says "Hello Fred" and process two replies, "Hi Bert". But process
one never gets that "Hi Bert" message. It's lost in the pipes and
buffers somewhere.
 
J

Jorgen Grahn

....
I long ago decided to deal only with line-oriented input for this sort of
task.

Then there are two of us!

....
The point is that once it's in a string, then you can forget about the
intricacies of C input processing, and use any string processing techniques
to extract the data. (Someone mentioned sscanf(), but even atoi() will do.)

strtol() is better than atoi(), since it lets you detect parse errors.

/Jorgen
 
J

Jorgen Grahn

In fact it's deeply evil. Unix programmers like to connect programs
together with pipes. Which is great. Until you need some interactivity,
or a two-way communication, a full duplex pipe in the jargon.

Then you find that the pipes keep on hanging because of buffers. Process
one says "Hello Fred" and process two replies, "Hi Bert". But process
one never gets that "Hi Bert" message. It's lost in the pipes and
buffers somewhere.

That's why they recommend against doing that. If you need to write to
some program's stdin and read its answers from stdout, you should use
something like expect(1). I think even the Perl and Python
documentation says full duplex pipes don't work.

The alternative would mean low thoughput for other pipelines and
redirections, and some of those need to be as fast as possible.

/Jorgen
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,075
Messages
2,570,547
Members
47,197
Latest member
NDTShavonn

Latest Threads

Top