newbie-- reading from keyboard

J

Jim Bancroft

I'm having trouble reading input from the keyboard. My goal: to prompt the
user for some text and then react accordingly. Here's what I've got so far
(relevant parts excerpted):

char input[2];

while(1)
{
printf("Type 0, 1 or 2 to do something. Press 3 to quit\n");

fgets(input,2,stdin);

switch(input[0])
{
case '0' : printf("you typed 0\n");break;
case '1' : printf("you typed 1\n");break;
case '2': printf("you typed 2\n");break;
case '3' : printf("you just quit\n");
default : printf("I don't know what you just typed\n");
}

}


That code works ok, but for some reason every time I type something the loop
runs twice-- I see the expected reaction, followed by the default statement.
So for instance, if I type "1" it tells me I typed a 1, but then it loops
and tells me it doesn't know what I typed.

I'm new to reading the keyboard in C, so any help you can give I'd be glad
for. Essentially I'd like to read a character and newline, then react
accordingly. Thanks!




}
 
J

Jim Bancroft

Quick addendum-- In my actual code there's an "exit(0)" right after my 'case
3' statement. Cut-and-paste failed me on the original post, what can I tell
you.
 
W

Walter Roberson

I'm having trouble reading input from the keyboard.
char input[2];
fgets(input,2,stdin);

That code works ok, but for some reason every time I type something the loop
runs twice-- I see the expected reaction, followed by the default statement.

According to my local system's fgets() man page:

fgets reads characters from the stream into the array pointed to by s,
until n-1 characters are read, or a new-line character is read and
transferred to s, or an end-of-file condition is encountered. The string
is then terminated with a null character.

Your "n" in this case is 2, so it is going to read only 1 character
and then put a null character after it in the input buffer. So you've
read one character -- but you haven't read the newline you entered
after that one character. That newline is still in the buffer so
the next time through the loop, the newline will be read, recognized
as the end of line, put into the buffer and then the string will be
terminated with the null character. Your switch() does not recognize
newline as a possible character so your program complains.
 
?

=?ISO-8859-1?Q?Une_b=E9vue?=

Walter Roberson said:
Your switch() does not recognize
newline as a possible character so your program complains.

I'm also a newbie in C, i wonder if their is no C equivalent to Perl and
Ruby chomp, leaving out the newline ???
 
R

Richard Heathfield

Une bévue said:
I'm also a newbie in C, i wonder if their is no C equivalent to Perl and
Ruby chomp, leaving out the newline ???

If fgets did this, how would you know whether you'd read a complete line?

Removing the '\n' (if present) is trivial:

int chomp(char *s)
{
int chomped = 0;
if(s != NULL)
{
while(!chomped && *s != '\0')
{
if(*s == '\n')
{
*s = '\0';
chomped = 1;
}
}
}
return chomped;
}
 
J

jaysome

Une bévue said:


If fgets did this, how would you know whether you'd read a complete line?

Removing the '\n' (if present) is trivial:

int chomp(char *s)
{
int chomped = 0;
if(s != NULL)
{
while(!chomped && *s != '\0')
{
if(*s == '\n')
{
*s = '\0';
chomped = 1;
}
}
}
return chomped;
}

This implementation uses 100% of my CPU. Thank goodeness for
preemptive multitasking OSes like Windows 95 and XP, which allow me to
kill the program that uses this code.

I think you meant to increment s somewhere. Fix it using *s++ and you
should be forgiven.
 
?

=?ISO-8859-1?Q?Une_b=E9vue?=

Richard Heathfield said:
If fgets did this, how would you know whether you'd read a complete line?

clever remark ))
i was and be still sleeping, i apologize for this noisy question !
Removing the '\n' (if present) is trivial:

int chomp(char *s)
{
int chomped = 0;
if(s != NULL)
{
while(!chomped && *s != '\0')
{
if(*s == '\n')
{
*s = '\0';
chomped = 1;
}
}
}
return chomped;
}

thanxs for that function, i'll open another thread upon default value.
 
R

Richard Heathfield

jaysome said:

This implementation uses 100% of my CPU. Thank goodeness for
preemptive multitasking OSes like Windows 95 and XP, which allow me to
kill the program that uses this code.

I think you meant to increment s somewhere. Fix it using *s++ and you
should be forgiven.

Oops. :)
 
B

Bill Reid

Une bévue said:
line?

clever remark ))
i was and be still sleeping, i apologize for this noisy question !


thanxs for that function, i'll open another thread upon default value.

Aside from forgetting to actually increment *s, I can name that
tune in less lines and instructions with more functionality (from my
personal string processing libraries):

/* truncates a line at a specified character */
void truncate_line(char *target_line,char unwanted_char) {
unsigned char_idx=0;

while(target_line[char_idx]!='\0') {
if(target_line[char_idx]==unwanted_char) {
target_line[char_idx]='\0';
break;
}
char_idx++;
}
}

To remove the newline, call "truncate_line(myline,'\n');". And
as a bonus, you can use it to terminate the line at any character
you want, such as deleting the file extensions (*.txt,*.c) from
a list of filenames...

If you feel the need for a return value, add it; if you really
want a dedicated "chomp" function, make a macro?
 
G

goose

Bill said:
line?

clever remark ))

i was and be still sleeping, i apologize for this noisy question !



thanxs for that function, i'll open another thread upon default value.


Aside from forgetting to actually increment *s, I can name that
tune in less lines and instructions with more functionality (from my
personal string processing libraries):

/* truncates a line at a specified character */
void truncate_line(char *target_line,char unwanted_char) {
unsigned char_idx=0;

while(target_line[char_idx]!='\0') {
if(target_line[char_idx]==unwanted_char) {
target_line[char_idx]='\0';
break;
}
char_idx++;
}
}

To remove the newline, call "truncate_line(myline,'\n');". And
as a bonus, you can use it to terminate the line at any character
you want, such as deleting the file extensions (*.txt,*.c) from
a list of filenames...

Throw me a bone; I'm a little confused here, what
exactly is wrong with:

char *end_here = strchr (target_line, '\n');
if (end_here) {
*end_here = 0;
}

???

As a bonus, replace "strchr" with "strrchr" and
you get even more functionality. Chuck it into
two macros and you're good to go.

Thats even fewer lines with even more
functionality. As a bonus, you don't confuse
the maintainer by (almost) rewriting a library
function ('cos if I were reading that (or Richards
chomp) in production code I'd be trying to find
the "trick" that required a whole new function).
 
B

Bill Reid

goose said:
Bill said:
Une bévue said:
If fgets did this, how would you know whether you'd read a complete
line?

clever remark ))
i was and be still sleeping, i apologize for this noisy question !

Removing the '\n' (if present) is trivial:

int chomp(char *s)
{
int chomped = 0;
if(s != NULL)
{
while(!chomped && *s != '\0')
{
if(*s == '\n')
{
*s = '\0';
chomped = 1;
}
}
}
return chomped;
}

thanxs for that function, i'll open another thread upon default value.

Aside from forgetting to actually increment *s, I can name that
tune in less lines and instructions with more functionality (from my
personal string processing libraries):

/* truncates a line at a specified character */
void truncate_line(char *target_line,char unwanted_char) {
unsigned char_idx=0;

while(target_line[char_idx]!='\0') {
if(target_line[char_idx]==unwanted_char) {
target_line[char_idx]='\0';
break;
}
char_idx++;
}
}

To remove the newline, call "truncate_line(myline,'\n');". And
as a bonus, you can use it to terminate the line at any character
you want, such as deleting the file extensions (*.txt,*.c) from
a list of filenames...
Throw me a bone; I'm a little confused here, what
exactly is wrong with:

char *end_here = strchr (target_line, '\n');
if (end_here) {
*end_here = 0;
}
Even better! Except I personally would actually write it:

void truncate_line(char *target_line,char unwanted_char) {
char *char_ptr;

if(NULL!=(char_ptr=strchr(target_line,unwanted char)))
char_ptr='\0';
}

For what I think are the usual reasons (I too am capable of
pedantry)...
As a bonus, replace "strchr" with "strrchr" and
you get even more functionality.

No, less, because it becomes more oriented to just replacing
the newline at the end of the string. For other uses, it becomes
a little more burdensome...
Chuck it into
two macros and you're good to go.
Maybe. A macro would probably be best. Maybe I'll make the
change my own self...
Thats even fewer lines with even more
functionality. As a bonus, you don't confuse
the maintainer by (almost) rewriting a library
function ('cos if I were reading that (or Richards
chomp) in production code I'd be trying to find
the "trick" that required a whole new function).
Well, you wouldn't be reading it, it's a library, so
you just use it, and to the best of my knowledge there
is no function in the standard "C" libraries that does
exactly what it does.

But you know, that code I posted is as old as the hills
and twice as dusty, but vaguely I remember something
about shuttling code back and forth between Unix and
DOS (not Windows!) and there were certain discrepancies
between the string functions in each, just enough to be
irritating as hell, so I just rolled some of my own...near as I
can tell right now from the NON-documentation, strchr()
appears to be fully portable, but I hate getting burned that
way...
 
R

Richard Heathfield

[It seems that I'm not the only one who can leave out a vital component of a
simple function! :) ]

Bill Reid said:

void truncate_line(char *target_line,char unwanted_char) {
char *char_ptr;

if(NULL!=(char_ptr=strchr(target_line,unwanted char)))
char_ptr='\0';

ITYM *char_ptr = '\0';

<snip>
 
D

Dave Thompson

Une bévue said:


If fgets did this, how would you know whether you'd read a complete line?

Removing the '\n' (if present) is trivial:
<snip code>
which zaps the first newline, if any, thus hiding any remainder.

Perl chomp, and I assume Ruby, removes a newline only if it is the
last character in the string. Immediately following (successful)
fgets(), newline is indeed last if present at all; but it's only
minimally more work to handle the other cases, and then you have,
well, something that handles the other cases. <G>

- David.Thompson1 at worldnet.att.net
 

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

No members online now.

Forum statistics

Threads
473,995
Messages
2,570,236
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top