for some simple HW code I wrote I needed to get 7 arguments via the scanf function:
scanf("%d %d %d %d\n", &vodka, &country, &life, &glut);
scanf("%d\n", &ageof);
scanf("%d\n", &dprice);
scanf("%d\n", &mprice);
as you can see, I'm asking for 7 arguments in this order:
argument [space] argument [space] argument [space] argument (down line)
argument (down line)
argument (down line)
argument (down line)
BUT, when running the code, I'm suddenly required to input 8 of them, and I have no idea why....
any help anyone?
As explained by #chqrlie and #Blue Moon a white space in the format, be it ' ', '\n', '\n' or any white-space does the same thing. It directs scanf() to consume white-space, such as '\n' from an Enter, until non-white-space is detected. That non-white-space character is then put back into stdin for the next input operation.
scanf("%d\n", ...) does not return until some non-white space is entered after the int. Hence the need for the 8th input. That 8th input is not consumed, but available for subsequent input.
The best way to read the 4 lines of input is to .... drum roll ... read 4 lines. Then process the inputs.
char buf[4][80];
for (int i=0; i<4; i++) {
if (fgets(buf[i], sizeof buf[i], stdin) == NULL) return Fail;
}
if (sscanf(buf[0], "%d%d%d%d", &vodka, &country, &life, &glut) != 4) {
return Fail;
}
if (sscanf(buf[1], "%d", &ageof) != 1) {
return Fail;
}
if (sscanf(buf[2], "%d", &dprice) != 1) {
return Fail;
}
if (sscanf(buf[3], "%d", &mprice) != 1) {
return Fail;
}
// Use vodka, country, life, glut, ageof, dprice, mprice
return Success
When you have a whitespace in the format string, you tell scanf() to ignore any number of whitespace characters. So the spaces you have between the %d requires to input a non-whitespace char(s) which are consumed for each of the subsequent %d.
The effect of spaces and \n in the following scanf() calls you have isn't quite obvious. But the newline character at the end of each last scanf() forces you to input a non-whitespace char. Hence, it looks like scanf() requires an extra input.
However, you don't really any whitespace characters here as %d would always ignore whitespace characters. So simply remove all spaces and \n characters from the format strings.
White space characters in the scanf format string are directives that mean read white space characters until you get a non white space character. A trailing \n in your format string causes scanf to consume the linefeed that was typed by the user and to keep asking for input until a non white space character is seen, but is left in the input buffer.
To consume the \n exactly, you can use this ugly scanf format:
scanf("%d%*1[\n]", &mprice);
Or you can just remove the trailing \n and consume the character with getchar() but be aware that neither of these approaches provide for exact matching of the input:
scanf("%d", &mprice);
getchar();
Related
I could not find the answer anywhere else.
%[^\n] - When I run this one, scanf is getting input and terminating after I press enter. ( Probably leaving \n in the input system)
%[^\n]\n - this one is getting the input but scanf is NOT terminating immediately after I press enter like the one above. I hit more enter and it makes more newlines. When I give a character and then press enter it finally terminates. Example:
int main(void)
{
char s[100];
scanf("%[^\n]\n", s);
printf("%s", s);
return 0;
}
The results:
Last one:
%[^\n]%*c - When I give some input and press enter. scanf immediately terminates.
How do those 3 work and how do they differ?
All 3 format begin with "%[^\n]".
"%[^\n]" is poor code2 that lacks a width limit and is susceptible to buffer overrun. Use a width limit like "%99[^\n]" with char s[100];.
"%[...]" does not consume leading whitespace like many other specifiers.
This specifier directs reading input until a '\n'1 is encountered. The '\n' is put back into stdin. All other characters are saved in the matching destination's array s.
If no characters were read (not counting the '\n'), the specifier fails and scanf() returns without changing s - rest of the format is not used. No null character appended.
If characters were read, they are saved and a null character is appended to s and scanning continues with the next portion of the format.
"\n" acts just like " ", "\t", "any_white_space_chracter" and reads and tosses 0 or more whitespace characters. It continues to do so until a non-white-space1 is read. That non-whitespace character is put back into stdin.
Given line buffered input, this means a line with non-whitespace following input is needed to see the next non-whitespace and allow scanf() to move on.
With scanf(), a "\n" at the end of a format is bad and caused OP's problem.
"%*c" reads 1 character1 and throws it away - even if it is not a '\n'. This specifier does not contribute to the return count due to the '*'.
A better alternative is to use fgets().
char s[100];
if (fgets(s, sizeof s, stdin)) {
s[strcspn(s, "\n")] = '\0'; // To lop off potential trailing \n
A lesser alternative is
char s[100] = { 0 };
scanf("%99[^\n]", s);
// With a separate scanf ....
scanf("%*1[\n]"); // read the next character if it is a \n and toss it.
1 ... or end-of-file or rare input error.
2 IMO, worse than gets().
I've seen a few examples where people give scanf a "%[^\n]\n" format string to read a whole line of user input. If my understanding is correct, this will read every character until a newline character is reached, and then the newline is consumed by scanf (and not included in the resulting input).
But I can't get this to work on my machine. A simple example I've tried:
#include <stdio.h>
int main(void)
{
char input[64];
printf("Enter some input: ");
scanf("%[^\n]\n", input);
printf("You entered %s\n", input);
}
When I run this, I'm prompted for input, I type some characters, I hit Enter, and the cursor goes to the beginning of the next line but the scanf call doesn't finish.
I can hit Enter as many times as I like, and it will never finish.
The only ways I've found to conclude the scanf call are:
enter \n as the first (and only) character at the prompt
enter Ctrl-d as the first (and only) character at the prompt
enter some input, one or more \n, zero or more other characters, and enter Ctrl-d
I don't know if this is machine dependent, but I'm very curious to know what's going on. I'm on OS X, if that's relevant.
According to the documentation for scanf (emphasis mine):
The format string consists of whitespace characters (any single whitespace character in the format string consumes all available consecutive whitespace characters from the input), non-whitespace multibyte characters except % (each such character in the format string consumes exactly one identical character from the input) and conversion specifications.
Thus, your format string %[^\n]\n will first read (and store) an arbitrary number of non-whitespace characters from the input (because of the %[^\n] part) and then, because of the following newline, read (and discard) an arbitrary number of whitespace characters, such as spaces, tabs or newlines.
Thus, to make your scanf stop reading input, you either need to type at least one non-whitespace character after the newline, or else arrange for the input stream to end (e.g. by pressing Ctrl+D on Unix-ish systems).
Instead, to make your code work as you expect, just remove the last \n from the end of your format string (as already suggested by Umamahesh P).
Of course, this will leave the newline still in the input stream. To get rid of it (in case you want to read another line later), you can getc it off the stream, or just append %*c (which means "read one character and discard it") or even %*1[\n] (read one newline and discard it) to the end of your scanf format string.
Ps. Note that your code has a couple of other problems. For example, to avoid buffer overflow bugs, you really should use %63[^\n] instead of %[^\n] to limit the number of characters scanf will read into your buffer. (The limit needs to be one less than the size of your buffer, since scanf will always append a trailing null character.)
Also, the %[ format specifier always expects at least one matching character, and will fail if none is available. Thus, if you press enter immediately without typing anything, your scanf will fail (silently, since you don't check the return value) and will leave your input buffer filled with random garbage. To avoid this, you should a) check the return value of scanf, b) set input[0] = '\0' before calling scanf, or c) preferably both.
Finally, note that, if you just want to read input line by line, it's much easier to just use fgets. Yes, you'll need to strip the trailing newline character (if any) yourself if you don't want it, but that's still a lot easier and safer that trying to use scanf for a job it's not really meant for:
#include <stdio.h>
#include <string.h>
void chomp(char *string) {
int len = strlen(string);
if (len > 0 && string[len-1] == '\n') string[len-1] = '\0';
}
int main(void)
{
char input[64];
printf("Enter some input: ");
fgets(input, sizeof(input), stdin);
chomp(input);
printf("You entered \"%s\".\n", input);
}
Whitespace characters in format of scanf() has an special meaning:
Whitespace character: the function will read and ignore any whitespace
characters encountered before the next non-whitespace character
(whitespace characters include spaces, newline and tab characters --
see isspace). A single whitespace in the format string validates any
quantity of whitespace characters extracted from the stream (including
none).
Thus, "%[^\n]\n" is just equivalent to "%[^\n] ", telling scanf() to ignore all whitespace characters after %[^\n]. This is why all '\n's are ignored until a non-whitespace character is entered, which is happened in your case.
Reference: http://www.cplusplus.com/reference/cstdio/scanf/
Remove the the 2nd new line character and the following is sufficient.
scanf("%[^\n]", input);
To answer the original one,
scanf("%[^\n]\n", input);
This should also work, provided you enter a non white space character after the input. Example:
Enter some input: lkfjdlfkjdlfjdlfjldj
t
You entered lkfjdlfkjdlfjdlfjldj
Here is my c code:
int main()
{
int a;
for (int i = 0; i < 3; i++)
scanf("%d ", &a);
return 0;
}
When I input things like 1 2 3, it will ask me to input more, and I need to input something not ' '.
However, when I change it to (or other thing not ' ')
scanf("%d !", &a);
and input 1 ! 2! 3!, it will not ask more input.
The final space in scanf("%d ", &a); instructs scanf to consume all white space following the number. It will keep reading from stdin until you type something that is not white space. Simplify the format this way:
scanf("%d", &a);
scanf will still ignore white space before the numbers.
Conversely, the format "%d !" consumes any white space following the number and a single !. It stops scanning when it gets this character, or another non space character which it leaves in the input stream. You cannot tell from the return value whether it matched the ! or not.
scanf is very clunky, it is very difficult to use it correctly. It is often better to read a line of input with fgets() and parse that with sscanf() or even simpler functions such as strtol(), strspn() or strcspn().
scanf("%d", &a);
This should do the job.
Basically, scanf() consumes stdin input as much as its pattern matches. If you pass "%d" as the pattern, it will stop reading input after a integer is found. However, if you feed it with "%dx" for example, it matches with all integers followed by a character 'x'.
More Details:
Your pattern string could have the following characters:
Whitespace character: the function will read and ignore any whitespace
characters encountered before the next non-whitespace character
(whitespace characters include spaces, newline and tab characters --
see isspace). A single whitespace in the format string validates any
quantity of whitespace characters extracted from the stream (including
none).
Non-whitespace character, except format specifier (%): Any character that is not either a whitespace character (blank, newline or
tab) or part of a format specifier (which begin with a % character)
causes the function to read the next character from the stream,
compare it to this non-whitespace character and if it matches, it is
discarded and the function continues with the next character of
format. If the character does not match, the function fails, returning
and leaving subsequent characters of the stream unread.
Format specifiers: A sequence formed by an initial percentage sign (%) indicates a format specifier, which is used to specify the type
and format of the data to be retrieved from the stream and stored into
the locations pointed by the additional arguments.
Source: http://www.cplusplus.com/reference/cstdio/scanf/
Why does scanf not read white spaces?
Also in my code if I use scanf first then fgets or scanf the second time after a few lines, as you can see in the code, then if I give an input that has a space like, "Hey How are u" then my code loops, why so?
I fixed it by just using fgets
while(1)
{
entry=&entry_var;
*entry=0;
printf("\n++++++++DFS CLIENT MENU++++++++");
printf("\n1- ENTER THE COMMAND");
printf("\n2- EXIT\n");
/*instance 1:if I use scanf here then whether i use scanf or fgets the
second time it loops in *entry==1 */
fgets (command, sizeof(command), stdin);
*entry=atoi(command);
printf("Entry: %d", *entry);
if(*entry==1)
{
printf("\n--------COMMANDING ZONE--------");
printf("\nInput the Function: ");
//This is the second instance
fgets (command, sizeof(command), stdin);
//scanf("%s",command);
printf("\n%s",command);
command_parse(command);
}
else if(*entry==2)
{
break;
}
}
Why cant scanf read white spaces?
This is a false question as scanf() does read white spaces.
scanf() reads from stdin and given various directives and specifiers, does its best to match them. Some specifiers cause scanf() to save data.
"%d" specifies scanf() to:
1- Read and discard all white-space.
2- Read and covert numeric text into an int, saving the result into i.
3- Continue step 2 until reading a non-numeric character, which is returned to stdin.
4- Return 1 if step 2 successful. Return 0 if step 2 only encountered non-numeric input. Else return EOF.
int i;
if (1 == scanf("%d", &i)) GoodToGo();
All scanf() format specifiers except "%c", "%n", "%[]", first read and discard leading white-space.
"%c" specifies scanf() to:
Read a char into c, including any whitespace character.
Return 1 or EOF.
char c;
if (1 == scanf("%c", &c)) GoodToGo();
scanf() and family details are beyond a simple answer here. Check on-line resources for details.
Better to use fgets() to read a line than scanf(any_format)
In the below program when am reading input from keyboard its taking only 2 characters instead of 4 and remaining 2 characters its taking spaces by default.
why is it???
program to take char input through pointers/
int c,inc,arrysize;
char *revstring;
printf("enter the size of char arry:");
scanf("%d",&arrysize);
revstring = (char *)malloc(arrysize * sizeof(*revstring));
printf("%d",sizeof(revstring));
printf("enter the array elements:");
for(inc=0;inc<arrysize;inc++)
{
scanf("%c",&revstring[inc]);
}
for(inc =0;inc<arrysize;inc++)
printf("%c",revstring[inc]);
getch();
return 0;
}
scanf reads formatted inputs. When you tape a number, you tape the digits, and then, you press <Enter>. So there is a remaining \n in stdin, which is read in the next scanf. The same applies if you press <Enter> between the characters.
A solution is to consume the characters in the standard input stream after each input, as follow:
#include <stdio.h>
void
clean_stdin (void)
{
int c;
while ((c = getchar ()) != '\n' && c != EOF)
;
}
Another idea is to use fgets to get human inputs. scanf is not suitable for such readings.
Most of the time scanf reads formatted input. For most % formats, scanf will first read and discard any whitespace and then parse the item specified. So with scanf("%d", ... it will accept inputs with initial spaces (or even extra newlines!) with no problems.
One of the exceptions, however, is %c. With %c, scanf reads the very next character, whatever it may be. If that next character is a space or newline, that is what you get.
Depending on what exactly you want, you may be able to just use a blank space in your format string:
scanf(" %c",&revstring[inc]);
The space causes scanf to skip any whitespace in the input, giving you the next non-whitespace character read. However, this will make it impossible to enter a string with spaces in it (the spaces will be ignored). Alternately, you could do scanf(" "); before the loop to skip whitespace once, or scanf("%*[^\n]"); scanf("%*c"); to skip everything up to the next newline, and then skip the newline.