scanf (yes/no) - doesn't work + deprecation errors scanf, fopen etc.

  • Thread starter =?ISO-8859-1?Q?Martin_J=F8rgensen?=
  • Start date
B

Barry Schwarz

Martin said:
Hi,

Consider:
------------
char stringinput[64]

.bla. bla. bla.

do
{
printf("Write to result.txt (y/n)? ");
scanf("%s", stringinput);
}
while (writechar != 'y' || != 'n');
This should be :
while (writechar != 'y' || writechar != 'n');

While it is now syntactically correct, the expression will always
evaluate to true. Use &&, not ||.



Remove del for email
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Barry Schwarz wrote:
-snip-
While it is now syntactically correct, the expression will always
evaluate to true. Use &&, not ||.

Damn... Thanks...


Med venlig hilsen / Best regards
Martin Jørgensen
 
M

Martin Joergensen

"Michael Mair" <[email protected]> skrev i en meddelelse
-snip-
Another thing: There is no equivalent to the run-time determination
of field width and precision for printf(). If you do not want to
have magic numbers you always have something like that:

#define STRINGIZE(S) #s
#define XSTR(S) STRINGIZE(S)

#define BUFSIZE 20

...
char buffer[BUFSIZE+1];
....
ret = sscanf("%" XSTR(BUFSIZE) "s", buffer);
....

Not really what I'd call flexible. And I am a friend of sscanf().

How about using getchar() like this for a yes/no test:

printf("Write to file result.txt (y/n)? ");
while ( tolower(writechar = getchar() ) != 'y' && tolower(writechar) != 'n')
{
if (writechar != '\n')
printf("Write to file result.txt (y/n)? ");
};

if (tolower(writechar) == 'j')
bla. bla. (write to file)
if no, then quit etc...


Best regards / Med venlig hilsen
Martin Jørgensen
 
S

stathis gotsis

Martin Joergensen said:
How about using getchar() like this for a yes/no test:

It would be better if you posted a fully compilable program. I assume you
printf("Write to file result.txt (y/n)? ");
while ( tolower(writechar = getchar() ) != 'y' && tolower(writechar) != 'n')
{
if (writechar != '\n')
printf("Write to file result.txt (y/n)? ");
};

You are not taking into account that a call to getchar() may return EOF
except for a character. This may happen if end of file is encountered or in
case of an error.

What happens if the user of your program types more than one character and
then presses <Enter>?
1) If the first character is one of those you are looking for
('y','n','Y','N'), the while loop exits and the rest of the typed characters
still reside in stdin. If you read the stdin later on, you will first read
those characters.
2) If the first character is not one of the expected ones, the message
printed in the body of your loop, will be printed repeatedly until all
characters in the stdin are consumed.
I do not think this is the behaviour you desire, so you should focus on
fixing these problems.
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

stathis said:
-snip-

You are not taking into account that a call to getchar() may return EOF
except for a character. This may happen if end of file is encountered or in
case of an error.

EOF when I read from keyboard?
What happens if the user of your program types more than one character and
then presses <Enter>?

Yeah, I know it's a problem I'm trying to fix...
1) If the first character is one of those you are looking for
('y','n','Y','N'), the while loop exits and the rest of the typed characters
still reside in stdin. If you read the stdin later on, you will first read
those characters.
2) If the first character is not one of the expected ones, the message
printed in the body of your loop, will be printed repeatedly until all
characters in the stdin are consumed.
I do not think this is the behaviour you desire, so you should focus on
fixing these problems.

#include <stdio.h>
#include <ctype.h>

#define buffer_length 2

main()
{
char writechar[buffer_length];

writechar[0]='a'; // initialize it to something other than y/n

while ( tolower(writechar[0] ) != 'y' && tolower(writechar[0]) != 'n')
{
if (writechar[0] != '\n')
printf("Write to the file result.txt (y/n)? ");
fgets(writechar, buffer_length, stdin);
}

if (tolower(writechar[0]) == 'y')
printf("You typed \"y\"\n");
else if (tolower(writechar[0]) == 'n')
printf("You typed \"n\"\n");
}


Now, even though I made "#define buffer_length 2" I would expect that if
the user typed something like "asdfa", then the question wouldn't be
printed 5 times... But it is printed 5 times... Without having to
download any libraries or whatever, how to fix this final problem? I
assume the definition of writechar is ok (or should be it an array of
length 3)?


Med venlig hilsen / Best regards
Martin Jørgensen
 
K

Keith Thompson

Martin Jørgensen said:
EOF when I read from keyboard?

Yes, of course, typically triggered by control-D or control-Z.

[snip]
#include <stdio.h>
#include <ctype.h>

#define buffer_length 2

main()
{
char writechar[buffer_length];

writechar[0]='a'; // initialize it to something other than y/n

while ( tolower(writechar[0] ) != 'y' && tolower(writechar[0]) != 'n')
{
if (writechar[0] != '\n')
printf("Write to the file result.txt (y/n)? ");
fgets(writechar, buffer_length, stdin);
}

if (tolower(writechar[0]) == 'y')
printf("You typed \"y\"\n");
else if (tolower(writechar[0]) == 'n')
printf("You typed \"n\"\n");
}


Now, even though I made "#define buffer_length 2" I would expect that
if the user typed something like "asdfa", then the question wouldn't
be printed 5 times... But it is printed 5 times... Without having to
download any libraries or whatever, how to fix this final problem? I
assume the definition of writechar is ok (or should be it an array of
length 3)?

If fgets() tries to read a line longer than the specified length
(buffer_length), the remainder of the line is left on the input
stream, to be read by the next call to fgets(). Repeated calls to
fgets() will read the entire line, a chunk at a time.

You probably don't want to examine every character on the input line,
just the first one. Or maybe you want to skip whitespace.

You can use fgets() with larger size argument to read the entire input
line into a string, then examine just the first character of the
string. If fgets() didn't read the entire line, the last character of
the string won't be a '\n' character; you can then discard the rest of
the line.

Or you can read a single character, check whether it's 'y' or 'n', and
then discard the rest of the line (up to the first '\n'). Decide what
you want to do on an empty input line (i.e., if the first character
you read is '\n'), and how you want to handle an EOF condition.
 
S

stathis gotsis

Martin Jørgensen said:
EOF when I read from keyboard?

Yes, it is possible when you type something like CTRL-D or CTRL-Z(It is
CTRL-Z typed at the start of the input line on a windows dos console). Also,
getchar() may return EOF in case of an error, so you should consider
comparing the return value of getchar() to EOF too.
#include <stdio.h>
#include <ctype.h>

#define buffer_length 2

main()
{
char writechar[buffer_length];

writechar[0]='a'; // initialize it to something other than y/n

while ( tolower(writechar[0] ) != 'y' && tolower(writechar[0]) != 'n')
{
if (writechar[0] != '\n')
printf("Write to the file result.txt (y/n)? ");
fgets(writechar, buffer_length, stdin);

fgets() will read up to (buffer_length-1 = 1) characters, so the problem
remains unsolved. Even if you increase buffer_lenth, the user might input
long lines so that fgets() does not read all of the input. I think you
should stick with your previous implementation where you used getchar(). You
will just have to read the first character each time, then eat up rest of
the input until you reach the newline. In all cases, handle EOF.
}

if (tolower(writechar[0]) == 'y')
printf("You typed \"y\"\n");
else if (tolower(writechar[0]) == 'n')
printf("You typed \"n\"\n");
}
 
M

Michael Mair

Martin said:
EOF when I read from keyboard?

As the others have not mentioned it: You can redirect a file
to stdin on many systems. I like to do that for C courses;
redirect stdin/stdout/stderr and let a bash script or batch
file check whether everything has been done correctly...

Interestingly, if I feed the elsethread (*) posted get_double
programme with an invalid file (containing only ".\n"), the
programme is caught in an endless loop as I forgot to break
the loop on file end and file error conditions... ;-)
This was not a problem for interactive input as the EOF
condition was given once and afterwards the loop could
continue, but in this case, we always get EOF. So much for
sufficient error handling.

<snip>


Cheers
Michael

(*) <[email protected]>
 
M

Martin Joergensen

"stathis gotsis" <[email protected]> skrev i en meddelelse
-snip-
Yes, it is possible when you type something like CTRL-D or CTRL-Z(It is
CTRL-Z typed at the start of the input line on a windows dos console).
Also,
getchar() may return EOF in case of an error, so you should consider
comparing the return value of getchar() to EOF too.

Ok, clear...
#include <stdio.h>
#include <ctype.h>

#define buffer_length 2

main()
{
char writechar[buffer_length];

writechar[0]='a'; // initialize it to something other than y/n

while ( tolower(writechar[0] ) != 'y' && tolower(writechar[0]) != 'n')
{
if (writechar[0] != '\n')
printf("Write to the file result.txt (y/n)? ");
fgets(writechar, buffer_length, stdin);

fgets() will read up to (buffer_length-1 = 1) characters, so the problem
remains unsolved. Even if you increase buffer_lenth, the user might input
long lines so that fgets() does not read all of the input. I think you
should stick with your previous implementation where you used getchar().
You
will just have to read the first character each time, then eat up rest of
the input until you reach the newline. In all cases, handle EOF.

Hmm. Okay, but I'm not really sure about how to discard the rest of the
line....... This program that was posted earlier had an error with the
__fpurge(stdin) - how do I modify it to work with standard C without
downloading any libraries or anything?:


#include <stdio.h>

int main(void)
{
char stringInput;

do
{
printf("\nWrite to result.txt (y/n)? ");
stringInput = getchar();
__fpurge(stdin); // clear the stdin to strip off the previous newline char.
}
while (stringInput != 'y' && stringInput != 'n');

printf("Thank you very much\n");

return 0;
}



Best regards / Med venlig hilsen
Martin Jørgensen
 
C

CBFalconer

Martin said:
.... snip ...

Hmm. Okay, but I'm not really sure about how to discard the rest
of the line....... This program that was posted earlier had an
error with the __fpurge(stdin) - how do I modify it to work with
standard C without downloading any libraries or anything?:

int flushln(FILE *f)
{
int ch;

do {
ch = getc(f);
while ((EOF != ch) && ('\n' != ch));
return ch;
}

--
"If you want to post a followup via groups.google.com, don't use
the broken "Reply" link at the bottom of the article. Click on
"show options" at the top of the article, then click on the
"Reply" at the bottom of the article headers." - Keith Thompson
More details at: <http://cfaj.freeshell.org/google/>
Also see <http://www.safalra.com/special/googlegroupsreply/>
 
M

Michael Mair

Martin said:
"stathis gotsis" <[email protected]> skrev i en meddelelse

Hmm. Okay, but I'm not really sure about how to discard the rest of the
line....... This program that was posted earlier had an error with the
__fpurge(stdin) - how do I modify it to work with standard C without
downloading any libraries or anything?:

#include <stdio.h>

int main(void)
{
char stringInput; int tmp;

do
{
printf("\nWrite to result.txt (y/n)? ");
stringInput = getchar();

Hmmm, go back to the comp.lang.c FAQ and read it carefully.

getchar() returns int, where the characters are cast to
unsigned char and EOF is a negative int value.
Every character literal in C is of type int.
If you make stringInput type char you can miss EOF returns or
returns >= SCHAR_MAX.
__fpurge(stdin); // clear the stdin to strip off the previous newline char.

while (EOF != (tmp = getchar()))
if ('\n' == tmp)
break;
or
do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp);
}
while (stringInput != 'y' && stringInput != 'n');

printf("Thank you very much\n");

return 0;
}

Cheers
Michael
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip-
while (EOF != (tmp = getchar()))
if ('\n' == tmp)
break;
or
do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp);

Thanks Michael. I took me really long time to realize that I needed two
integers (an extra int tmp). So it really works now.

I just don't really understand why it works... Let's look at my code
(int charInput, tmp;)

do
{
printf("\nWrite to result.txt (y/n)? ");
charInput = getchar();

do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp); // */

}
while (charInput != 'y' && charInput != 'n');


I did a little debugging and it seems like charInput always contains the
first character I enter, while tmp always contains "10" which AFAIR is \n.

Shouldn't the while line be changed to: } while(EOF != tmp || '\n' !=
tmp);? I mean: tmp can't be EOF and \n at the same time, can it?

I tried Ctrl+D on mac os x. Isn't that EOF? I'll try ctrl+D or ctrl+Z on
my windows machine later...


Best regards / Med venlig hilsen
Martin Jørgense
 
M

Michael Mair

Martin said:
Michael Mair wrote:
-snip-



Thanks Michael. I took me really long time to realize that I needed two
integers (an extra int tmp). So it really works now.

I just don't really understand why it works... Let's look at my code
(int charInput, tmp;)

do
{
printf("\nWrite to result.txt (y/n)? ");
charInput = getchar();

do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp); // */

}
while (charInput != 'y' && charInput != 'n');


I did a little debugging and it seems like charInput always contains the
first character I enter, while tmp always contains "10" which AFAIR is \n.

Shouldn't the while line be changed to: } while(EOF != tmp || '\n' !=
tmp);? I mean: tmp can't be EOF and \n at the same time, can it?

No. But the loop has to stop if tmp either equals EOF or equals '\n',
that is, it runs as long as tmp equals neither.

I tried Ctrl+D on mac os x. Isn't that EOF? I'll try ctrl+D or ctrl+Z on
my windows machine later...

I do not know about Mac OS X. Ctrl+Z works with Windows, Ctrl+D with
Linux or Cygwin.

Cheers
Michael
 
C

Chris Torek

Thanks Michael. I took me really long time to realize that I needed two
integers (an extra int tmp). So it really works now.

I just don't really understand why it works...

OK, think of "stdin" as coming from a file, rather than from the
keyboard. (It works the same either way, except that when reading
from the keyboard, the "contents" cannot be predicted in advance
by peeking at the file. You would have to peek at the typist's
mind instead.)

If a file consists in its entirety of a pair of lines like this:

abcdefg
wxyz

then the contents of the stream, taken one character at a time, are:

'a', 'b', 'c', 'd', 'e', 'f', 'g', '\n', 'w', 'x', 'y', 'z', '\n'

after which a subsequent attempt to read will encounter the EOF
condition, which getc(stream) will represent by returning the special
EOF value (typically -1).

Suppose we edit the file with a "binary editor" and remove the last
line, but also remove the newline that comes after the first line.
Then getc() will return:

'a', 'b', 'c', 'd', 'e', 'f', 'g', EOF
Let's look at my code (int charInput, tmp;)

do
{
printf("\nWrite to result.txt (y/n)? ");
charInput = getchar();

do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp); // */

}
while (charInput != 'y' && charInput != 'n');

Here, charInput will get the 'a', leaving 'b' thorugh 'g' in the
stream. Then the loop using "tmp" will get the 'b', then 'c', then
'd', ..., then 'g', then EOF. Since EOF == EOF, the loop will stop
at this point, with tmp==EOF.

What happens if we replace the input file with one that contains the
character sequence '\n', 'y', '\n' (then EOF)?
I did a little debugging and it seems like charInput always contains the
first character I enter, while tmp always contains "10" which AFAIR is \n.

It is on most systems.
Shouldn't the while line be changed to: } while(EOF != tmp || '\n' !=
tmp);? I mean: tmp can't be EOF and \n at the same time, can it?

Indeed, it cannot be equal to both EOF (a negative integer) and '\n'
(a positive integer). What happens if you ask whether, for instance:

if (EOF != EOF || EOF != '\n')

?
I tried Ctrl+D on mac os x. Isn't that EOF?

It is set-able, but that is the default. However, depending on the
C library, you may sometimes have to type it more than once. The
C standard allows, but in C89 at least does not require, EOF to be
"sticky": if a stream encounters EOF, the C library can stop asking
the underlying OS for more input until you call clearerr() on the
stream. On the other hand, the C library can go ahead and keep
asking for more input anyway. Different systems do different things
here.
 
?

=?ISO-8859-15?Q?Martin_J=F8rgensen?=

Michael Mair wrote:
-snip-
No. But the loop has to stop if tmp either equals EOF or equals '\n',
that is, it runs as long as tmp equals neither.

Oh, yeah... The other thing also didn't work. Thanks...


Best regards / Med venlig hilsen
Martin Jørgensen
 
?

=?ISO-8859-1?Q?Martin_J=F8rgensen?=

Chris Torek wrote:
-snip-
Here, charInput will get the 'a', leaving 'b' thorugh 'g' in the
stream. Then the loop using "tmp" will get the 'b', then 'c', then
'd', ..., then 'g', then EOF. Since EOF == EOF, the loop will stop
at this point, with tmp==EOF.

What happens if we replace the input file with one that contains the
character sequence '\n', 'y', '\n' (then EOF)?

Great explanation... And there we have a (small) bug... charInput will
be "\n" while "tmp" will be y. Therefore the program will never test the
y positive in the outer loop (the line: while (charInput != 'y' &&
charInput != 'n');)

Hmmm... I'm not so experienced here, so what would a good solution to
the program be? Perhaps adding (to the inner loop) if(tmp == 'y' || tmp
== 'n'), then do: charInput == tmp (untested)? Would that work?
It is on most systems.




Indeed, it cannot be equal to both EOF (a negative integer) and '\n'
(a positive integer). What happens if you ask whether, for instance:

if (EOF != EOF || EOF != '\n')

Oh, yeah... You mean: "while" instead of "if", right (like in the
program)? It never asks me for input again... Must be because that
if-sentence is always true and therefore tmp = getchar() will run
forever... Your if-sentence will also run forever, I can see now because
either one of the two expressions will always be true - therefore the
whole thing is true...
It is set-able, but that is the default. However, depending on the

How to set it up in linux? Might be the same for mac os x.
C library, you may sometimes have to type it more than once. The
C standard allows, but in C89 at least does not require, EOF to be
"sticky": if a stream encounters EOF, the C library can stop asking
the underlying OS for more input until you call clearerr() on the
stream. On the other hand, the C library can go ahead and keep
asking for more input anyway. Different systems do different things
here.

Strange... Under xcode development tool ctrl+D doesn't work. But in a
terminal window, typing ctrl+D makes it go crazy like an infinite loop
writing: "Write to result.txt (y/n)? "

Is this code correct when typing ctrl+D = EOF I assume?

main() // can't remember if this syntax is correct
{
int charInput, tmp;


do
{
printf("\nWrite to result.txt (y/n)? ");
charInput = getchar();

do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp); // */

}
while (charInput != 'y' && charInput != 'n');

}

I wanted to copy/paste my own code but it has a lot of ^M in it and I
haven't figured out yet how to convert those line endings on
linux/unix/mac correct (wrote be the textedit application) so I just
inserted main(){ ... } to the code I previously posted.


Best regards / Med venlig hilsen
Martin Jørgensen
 
K

Keith Thompson

Chris Torek said:
It is set-able, but that is the default. However, depending on the
C library, you may sometimes have to type it more than once. The
C standard allows, but in C89 at least does not require, EOF to be
"sticky": if a stream encounters EOF, the C library can stop asking
the underlying OS for more input until you call clearerr() on the
stream. On the other hand, the C library can go ahead and keep
asking for more input anyway. Different systems do different things
here.

I'm going to jump in here and point out that the term EOF is being
used to refer to several different things. Control-D is not EOF;
Control-D might be (on some systems) the character that you enter to
trigger and end-of-file condition, which will then cause getchar() to
return the value EOF.

EOF is a macro, defined in <stdio.h>. It expands to a negative
integer value. getchar() returns that value to denote an end-of-file
or error condition. The way an end-of-file condition is triggered
varies from system to system and from file to file, and is outside the
scope of the C standard. If you're reading from a disk file, reaching
the end of the file commonly triggers the end-of-file condition; this
is a function of the size of the file, not of its contents (i.e.,
there's not necessarily a character that marks the end of the file).
If you're reading from a keyboard, typically some special character is
used by the system to trigger an end-of-file condition; this is
usually control-D on Unix-like systems and control-Z on DOS-like
systems. The character itself is not seen by the program, though
there may be a way to transmit that character directly. For example,
on Unix, if you type control-V control-D, your program will see a
control-D (ASCII code 4) character; this is *not* EOF.
 
S

stathis gotsis

Martin Jørgensen said:
main() // can't remember if this syntax is correct

int main(void)
{
int charInput, tmp;


do
{
printf("\nWrite to result.txt (y/n)? ");
charInput = getchar();

First character can be EOF or '\n', you should compare charInput to those
values and take desired action. Maybe you want to do it this way or maybe
not:

if (charInput==EOF)
break;

if (charInput=='\n')
continue;
do {
tmp = getchar();
} while(EOF != tmp && '\n' != tmp); // */

You will have to check why the previous while loop exited. That would be
because EOF or newline was encoutered. You should take action not to read
beyond EOF, the same way as above.
}
while (charInput != 'y' && charInput != 'n');

When you exit the above while loop, you have to determine why it exited.
Maybe you reached EOF before 'y'/'n' were typed.
 
R

Rod Pemberton

stathis gotsis said:
int main(void)


First character can be EOF or '\n', you should compare charInput to those
values and take desired action. Maybe you want to do it this way or maybe
not:

if (charInput==EOF)
break;

I thought feof(), not EOF, was the preferred method for ANSI C to check
end-of-file. Am I mistaken?
if (charInput=='\n')
continue;


You will have to check why the previous while loop exited. That would be
because EOF or newline was encoutered. You should take action not to read
beyond EOF, the same way as above.


When you exit the above while loop, you have to determine why it exited.
Maybe you reached EOF before 'y'/'n' were typed.

Rod Pemberton
 
J

Jordan Abel

Chris Torek wrote:
-snip-


Great explanation... And there we have a (small) bug... charInput will
be "\n" while "tmp" will be y. Therefore the program will never test the
y positive in the outer loop (the line: while (charInput != 'y' &&
charInput != 'n');)

Hmmm... I'm not so experienced here, so what would a good solution to
the program be? Perhaps adding (to the inner loop) if(tmp == 'y' || tmp
== 'n'), then do: charInput == tmp (untested)? Would that work?


Oh, yeah... You mean: "while" instead of "if", right (like in the
program)? It never asks me for input again... Must be because that
if-sentence is always true and therefore tmp = getchar() will run
forever... Your if-sentence will also run forever, I can see now because
either one of the two expressions will always be true - therefore the
whole thing is true...


How to set it up in linux? Might be the same for mac os x.


Strange... Under xcode development tool ctrl+D doesn't work. But in a
terminal window, typing ctrl+D makes it go crazy like an infinite loop
writing: "Write to result.txt (y/n)? "

The most common reason for this is if you fail to check for an
end-of-file condition and break a loop. This is most commonly from using
scanf incorrectly, but the issue exists with many other functions.

For example, if you're re-prompting if the character input is not 'y' or
'n' - well, end-of-file is neither. If you're using scanf, it's nothing
at all. [the pointed-at object is not assigned to]
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top