scanf, getchar() and negative numbers in C - c

I'm looking at past papers for my exam. I have this one question that I don't know why this is the correct answer.
A loop is required to read a negative integer from the user into a variable c. It should ignore all characters
inputted by the user, until a valid negative number is entered. For example, if the user types x-x-x89--90,
then c should be filled with -90. Which one of the program excerpts below is correct:
(b)
int c=0;
while (c>=0)
while (scanf("%d", &c)!=1 && getchar());
^ This is the correct answer, I've run it myself and it works.

Well: scanf... tries to read in an integral value (positive or negative); the return value of scanf is the number of correctly read in formats like %d, so you may expect 1 for a successful read of "%d". If scanf returns 1, the inner loop exits; otherwise, getchar() is called which takes a character from the input stream and leads to the next try of scanf. The outer loop then makes sure that positive values are ignored.
Note that the "correct" answer has a bug if "end-of-file" is entered. This will lead to an endless loop then. So I'd actually adapt the code as follows:
int c=0;
while (c>=0 && !feof(stdin))
while (scanf("%d", &c)!=1 && getchar() != EOF);

Related

C code, scanf and getchar

I'm just asking what does the getchar do in this code and how does it work? I don't understand why the getchar affects the code, to me it seems as if its just getting the value but nothing is being done with the value.
int c=0;
while (c>=0)
{
scanf("%d", &c);
getchar();
}
Some possibilities of why getchar() might have been used there:
1) If it's done to ignore whitespaces (typically used when scanning chars with %c), it's not needed here because %d ignores whitespaces anyway.
2) Other possibility is that after this loop, some further scanning is done where the last \n left by the last call to scanf() might be a problem. So, getchar() might be used to ignore it.
3) In case you enter characters do not match %d, scanf() will fail. In that the characters you entered are left in the input stream and you'll never be able to read an int again (For example, if you input abcdddgdfg without that getchar() call). So, getchar() here will consume all those
chars (one per iteration) and eventually you'll be able to read int (using %d) again.
But this is all really not needed; it's just an attempt to fix flaws of scanf(). Reading inputs using scanf() and getting it correct is really difficult. That's why it's always recommended to use fgets() and parse using sscanf() or using strto*() functions if you are just scanning integers.
See: Why does everyone say not to use scanf? What should I use instead?
In this code, getchar is being called for its side effects: it reads a character from standard input and throws it away.
Probably this is reading input from the user. scanf will consume a number, but leave the newline character after the number untouched. The getchar consumes the newline and throws it away. This isn't strictly necessary in this loop, because the next scanf will skip over whitespace to find the next number, but it might be useful if the code after the loop isn't expecting to have a newline as the first thing on stdin.
This code is buggy, because it doesn't check for EOF, because it doesn't do anything sensible when the input is not a number or when there's more text on the line after the number, and because it uses scanf, which is broken-as-specified (for instance, it's allowed to crash the program if the input overflows the range of an int). Better code would be something like
char *linep = 0;
size_t asize = 0;
char *endp;
long c;
while (getline(&linep, &asize, stdin) > 0) {
errno = 0;
c = strtol(linep, &endp, 10);
if (linep == endp || *endp != '\0' || errno) {
puts("?Redo from start");
continue;
}
if (c == 0) break;
do_something_with(c);
}
free(linep);
Most likely the code is for reading in a list of integers, separated by a new line.
scanf will read in an integer, and put it into variable c.
The getchar is reading in the next character (assuming a new line)
Since it doesn't check, there is some potential that it wasn't a new line, or that scanf failed as the what it tried to read wasn't a number.
getchar(); is simply reading and consuming the character after the number, be it a space, comma, new line or the beginning of another integer or anything else.
IMO, this is not robust code. Good code would 1) at least test the result of scanf() and 2) test or limit the consumption of the following character to prevent "eating" a potential sign of the following number. Remember code cannot control what a user types, but has to cope with whatever is entered.
v space
"123 456"
v comma
"123,456"
v negative sign
"123-456"

understanding of scanf() function

I was trying to figure out whether my input is numeric or not and I found this example:
while ( (scanf ("%d", &number) ) == 0) {
printf("Entered value is not integer");
}
I searched online but I did not find any explanation about this. Why it means not a integer (Does this mean your input contains alphabets?)if you scanf() a integer and equal to 0?
There probably wasn't any explanation for the code:
while ( (scanf ("%d", &number) ) == 0) {
printf("Entered value is not integer");
}
because there isn't a good explanation for it. It is bad code on multiple grounds, some of which have been covered by other answers, but some of which have not been mentioned.
The novel problems are:
If the scanf() reports 0, the program goes into an infinite loop. The character that was rejected as 'not part of a number' still isn't part of a number on the next cycle, so scanf() will consistently return 0 until the program is interrupted in some way.
You can work around this by eating (at minimum) the first character of the remaining input. It is probably better to eat up all the characters until the next newline is read. After all, if the user mistyped the number, whatever else is on the line is not reliably what they wanted to type.
The diagnostic message doesn't end with a newline, so it may not appear until enough copies of the message have been generated to fill the standard output buffer, whereupon a number of copies of the message will appear. There's a chance that you won't see this behaviour because the standard input and standard output stream might be synchronized so that any pending output is flushed before an input operation, but it is not reliable.
Then there's the boring stuff everyone else mentioned:
The scanf() function might return EOF, or 0, or 1 (because there is only one conversion specification). If it returns EOF, you have another cause for an infinite loop: it will return EOF each time it is called, but the code doesn't react to the information.
Most often, the correct way to detect that scanf() worked is to check that the return value is the number of values you expected should be returned (the number of active conversion specifications — you don't count %*d or %n or %% in the number of active conversion specifications, and maybe active isn't the best word, but it suffices for now).
Putting fixes for these issues together, you might arrive at:
int rc;
while ((rc = scanf("%d", &number)) != 1)
{
if (rc == EOF)
{
printf("EOF detected without a number\n");
break; // return, exit, ...
}
printf("Entered value is not an integer: ");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
putchar('\n');
// Optionally fflush(stdout);
}
See Using fflush(stdin) for why I didn't use fflush(stdin) instead of the loop. You may prefer not to echo the invalid entry, in which case you can replace the putchar(c); with just the semicolon (and adjust the error message before, and the putchar('\n'); after too), but it often helps people to understand what they did wrong if they see what the program thinks they typed. You might want to think about whether error messages should be written to standard error instead of standard output. If getchar() returns EOF, the next iteration of scanf() will also return EOF, so that case will be handled. Note the use of int c; — getchar() returns an int, not a character.
As mentioned in the man page, in case the matching is failure, scanf() retunes 0. IN other words, scanf() returns the number of successful matches.
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
In case for a %d format specifier, the entered value is a char (i.e., not a match for an int) matching fails and scanf() returns 0.
So, the bottom line is, a return value of 0 here indicates, the input was improper and the scanning has failed. That also mentioned, the assignment of the value expected of scanf() has failed, leaving the possibility of usage of indeterminate value for the supplied argument.
If user gives integer then scanf will return 1 [the no of successfully scanned variable(s)] else return 0.
ALREADY AVAILABLE HERE :
Value returned by scanf function in c
Btw the code is not proper as if EOF reached then also it will show ".. not inte..." as scanf will return -1 [also != 0] .
See Value returned by scanf function in c
On success, the function returns the number of items successfully
read. This count can match the expected number of readings or fewer,
even zero, if a matching failure happens. In the case of an input
failure before any data could be successfully read, EOF is returned.
If it successfully reads the number, it returns 1. The loop will end.
If it fails to read anything (probably due to EOF), it returns EOF, which is -1. The loop will end.
If it reads something, but unable to convert it to integer, it returns 0, the loop continues.
From the man page for scanf:
Upon successful completion, these functions shall return the number of successfully matched and assigned input items
and
An input item shall be defined as the longest sequence of input bytes (up to any specified maximum field width, which may be measured in characters or bytes dependent on the conversion specifier) which is an initial subsequence of a matching sequence. The first byte, if any, after the input item shall remain unread. If the length of the input item is 0, the execution of the conversion specification shall fail; this condition is a matching failure, unless end-of-file, an encoding error, or a read error prevented input from the stream, in which case it is an input failure.
In your case, the input specifier is "%d", which Matches an optionally signed decimal integer.... So if the first character (after skipping any white space) is a numeric digit (or a +/- sign), this will convert the number (one or more digits), stopping when it sees any non-digit characters. The return value is the number of converted values, which will be 1 if it found a valid decimal number, or 0 if it didn't.
Beware that the result may not be what you expect, for example:
4-hydroxytoluene
would convert the number 4 and return 1, even though it doesn't appear to be the intent of the input. Similary 1337age, for "leetage", would convert the number 1337. I often use a code snippet like the following to avoid such cases:
char dummy;
int conversions = scanf("%d%c", &number, &dummy);
if ((conversions != 1) && ((conversion != 2) || !isspace(dummy)))
printf("Entered value is not an integer.\n");

Where to use this while loop?

I've just started to learn c programming. I don't know weather this question is silly or not.
Where do i use
while(getchar()! ='\n') ;
When using scanf function in some program the above mentioned while loop is used whereas some other program doesn't use the while loop after the scanf function.
So, where should i use this while loop and where not to?
Use the loop to clean up the rest of a line after an error
You use code similar to the loop in the question when you think there is debris left on a line of input after you (attempted to) read some data from standard input but the operation failed.
For example, if you have:
int n;
if (scanf("%d", &n) != 1)
…recover from error here?…
The error recovery should check for EOF (it is correct to use feof() here — but see while (!feof(file)) is always wrong for how not to use feof()), and if you didn't get EOF, then you probably got a letter or punctuation character instead of a digit, and the loop might be appropriate.
Note that you should always check that the scanf() operations — or any other input operation — succeeded, and the correct check for the scanf() family of functions is to ensure you got the expected number of successful conversions. It is not correct to check whether scanf() returned EOF; you can can get 0 returned when there's a letter in the input queue and you ask for a number.
Beware EOF
Incidentally, the loop in the question is not safe. It should be:
int c;
while ((c = getchar()) != EOF && c != '\n')
;
If the loop in the question gets EOF, it continues to get EOF, and isn't going to do anything useful. Always remember to deal with it. Note the use of int c; too — getchar() returns an int and not a char, despite its name. It has to return an int since it returns every valid character code and also returns a distinct value EOF, and you can't fit 257 values into an 8-bit quantity.
While loop syntax :
while (condition test)
{
// C- statements, which requires repetition.
// Increment (++) or Decrement (--) Operation.
}
while(getchar()! ='\n') ;
Here your condition is getchar()!='\n'.
First getchar() will execute . It will ask input from user. This function returns the character read as an unsigned char cast to an int or EOF on end of file or error. While loop keep continue executing until return value will not match with '\n'
scanf() example : scanf("%s", &str1);
With scanf you can ask user for enter input one time only For more than one input you have to place scanf in loop.
Where as you ask to enter input to user in while loop condition So It will keep asking input from user until EOF signal occur.
When the scanf() format string does not cause it to read the newline from the input buffer.
Most simple format specifiers will not read the newline. However if you use %c, any character may be read, including newline, in which case the loop will need modification:
while( ch != '\n' && getchar() != '\n' ) ;
Where ch is the variable receiving the %c input.
Because console input is normally line-buffered, failing to consume the newline will cause subsequent stdin reading functions to return immediately without waiting for further input, which is seldom what is intended.
You would not use such a loop in cases where multiple fields are entered in a single line but processed in separate scanf() (or other stdin function) calls.

confused about getchar and scanf

I'm really confused about the usage of getchar() and scanf(). What's the difference between these two?
I know that scanf() [and family] get a character by character from the user [or file] and save it into a variable, but does it do that immediately or after pressing something (Enter)?
and I don't really understand this code, I saw many pieces of code using getchar() and they all let you type whatever you want on the screen and no response happen, but when you press enter it quits.
int j, ch;
printf("please enter a number : \n");
while (scanf("%i", &j) != 1) {
while((ch = getchar()) != '\n') ;
printf("enter an integer: ");
}
Here in this code can't I use scanf() to get a character by character and test it? Also, what does this line mean?
scanf("%i", &j) != 1
because when I pressed 1 it doesn't differ when I pressed 2? what does this piece do?
and when this line is gonna happen?
printf("enter an integer: ");
because it never happens.
Well, scanf is a versatile utility function which can read many types of data, based on the format string, while getchar() only reads one character.
Basically,
char someCharacter = getchar();
is equivalent to
char someCharacter;
scanf("%c", &someCharacter);
I am not 100% sure, but if you only need to read one character, getchar() might be 'cheaper' than scanf(), as the overhead of processing the format string does not exist (this could count to something if you read many characters, like in a huge for loop).
For the second question.
This code:
scanf("%i", &j) != 1
means you want scanf to read an integer in the variable 'j'. If read successfully, that is, the next input in the stream actually is an integer, scanf will return 1, as it correctly read and assigned 1 integer.
See the oldest answer to this SO question for more details on scanf return values.
As far as I understand,
the getchar function will read your input one character at a time.
scanf will read all types of data, and will be more useful to define a data group.
However, as far as strings go, my teacher recommends using gets instead of scanf. This is because scanf will stop 'getting' the data at the first white space you put in, like in a sentence...
while (scanf("%i", &j) != 1) {
while((ch = getchar()) != '\n') ;
printf("enter an integer: ");
}
Here's how this code breaks down.
scanf() consumes individual characters from the input stream until it sees a character that does not match the %i conversion specifier1, and that non-matching character is left in the input stream;
scanf() attempts to convert the input text into a value of the appropriate type; i.e., if you enter the string "1234\n", it will be converted to the integer value 1234, the converted value will be assigned to the variable j, and the '\n' will be left in the input stream;
if there are no characters in the input string that match the conversion specifier (such as "abcd"), then no conversion is performed and nothing is assigned to j;
scanf() returns the number of successful conversions and assignments.
if the result of the scanf() call is not 1, then the user did not enter a valid integer string;
since non-matching characters are left in the input stream, we need to remove them before we can try another scanf() call, so we use getchar() to consume characters until we see a newline, at which point we prompt the user to try again and perform the scanf() call again.
1. The %i conversion specifier skips over any leading whitespace and accepts optionally signed integer constants in octal, decimal, or hexadecimal formats. So it will accept strings of the form [+|-]{0x[0-9a-fA-F]+ | 0[0-7]+ | [1-9][0-9]*}
The scanf can scan arbitrarily formatted data and parse it as multiple types (integers, floating point, strings, etc). The getchar function just gets a single character and returns it.
The expression
scanf("%i", &j) != 1
reads a (possibly signed) integer from the standard input, and stores it in the variable j. It then compares the return value of the scanf function (which returns the number of successfully scanned conversions) and compares it to 1. That means the expression will be "true" if scanf didn't read or converted an integer value. So the loop will continue to loop as long as scanf fails.
You might want to check this scanf reference.
That the printf doesn't happen might be either because it never happens (use a debugger to find out), or it just seemingly doesn't happen but it really does because the output needs to be flushed. Flushing output is done either by printing a newline, or with the fflush function:
fflush(stdout);
As far as I know, scanf will read user input until the first whitespace, considering the input format specified. getchar, however, reads only a single character.
scanf will return the number of arguments of the format list that were successfully read, as explained here. You obtain the same result when pressing 1 or 2 because both of them are successfully read by the %i format specifier.
getchar reads one char at a time from input. where as scanf can read more depending upon the data type u specify.
its not good practice to use scanf() try using fgets(), its much more efficient and safe than scanf.

why the getchar() function does not loop?

I have read so many questions about getchar() and its behaviour, but still I don't understand this simple code..
while (scanf("%d", &z) != 1)
{
while (getchar() != '\n');
printf ("Try again: ");}
This code is to validate for characters.. From what I infer from this code is that if I input
Stackoverflow
Then the whole line is pushed to the buffer with the newline '\n' also..
Then the getchar() reads each character from the buffer and returns an integer, cleaning the buffer.. In this case the while loop should loop 12 times (number of characters in Stackoverflow) until it reaches the '\n' character.. but actually it just loops once and the output is
Try again:
means its out of loop and asking for scanf again.. It goes against my understanding of looping.. Maybe I misunderstood looping.. One additional question,, if getchar() returns integers then how it could be compared to characters like '\n'?
Reformatting the code to assist with my explanation:
while (scanf("%d", &z) < 1) {
int c; // for getchar()'s return value
while ((c = getchar()) != EOF && c != '\n')
;
printf ("Try again: ");
}
Note that scanf returns the number of items it read successfully. (I changed the outer while condition.)
Edit: It is very important that getchar() be checked for EOF. The loop could spin forever otherwise.
The inner while is followed by a semicolon. This means it does not have a loop body, i.e. does nothing except evaluate its condition until said condition is false.
But what does the code do?
Say I type in Stackoverflow. scanf sees %d in its format string, looks for an integer (any number of digits, optionally prefixed by a sign), finds nothing of the sort, and returns failure (i.e. 0) without changing z.
Execution enters the loop, where getchar is called repeatedly until it finds a newline; this reads and discards all erroneous input. The program prints Try again: (no newline), and the outer loop then evaluates its condition again, trying to read an integer.
Rinse and repeat until an integer is entered, at which point scanf stuffs it in z and the loop finishes.
And what about comparing getchar() (int) to '\n' (char int)?
In C, char is just a smaller int. C does not have a concept of characters separate from a concept of the integers that represent them. '\n' is an int, not a char, so no problems here. (It's for historical reasons - something to do with K&R C.)

Resources