So I had a code where I use
scanf("%[^\n]s",a);
and has multiple scanf to take different inputs some being string input. So I understand that scanf("%[^\n]s",a) takes input until new line has been reached, however I was wondering suppose my string can only hold up to 10 characters, then after my string has been filled, but new line hasn't been reached how can i get rid of the extra input before going to new line. I was thinking of doing getchar() until new line has been reached however in order to even check if my 10 spots has been filled I need to use getchar, so doesn't that mess up my next scanf input? Anybody have any other way to do it? Still using scanf() and getchar?
scanf("%[^\n]s",a) is a common mistake; the %[ directive is distinct from the %s directive. What you're asking from scanf is:
A group of non-'\n' characters, followed by...
A literal s character.
Perhaps you intended to write scanf("%[^\n]",a)? Note the deleted s...
You can use the * modifier to suppress assignment for a directive, for example scanf("%10[^\n]", a); followed by scanf("%*[^\n]"); to read and discard up to the next newline and getchar(); to read and discard that newline:
scanf("%10[^\n]", a);
scanf("%*[^\n]"); // read and discard up to the next newline
getchar(); // read and discard that newline
As pointed out, the two format strings could be concatenated to reduce the number of calls to scanf. I wrote my answer this way for the sake of documentation, and I'll leave it as is. Besides, I figure that attempt at optimisation would be negligible; a profiler is likely to indicate much more significant bottlenecks for optimisation in realistic scenarios.
You can use this format to hold the first 10 characters and keep the next lines of input:
scanf("%10[^\n]%*[^\n]",a);
getchar();
Related
https://i.imgur.com/FLxF9sP.png
As shown in the link above I have to input '<' twice instead of once, why is that? Also it seems that the first input is ignored but the second '<' is the one the program recognizes.
The same thing occurs even without a loop too.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
int randomGen, upper, lower, end, newRandomGen;
char answer;
upper = 100;
lower = 1;
end = 1;
do {
srand(time(0));
randomGen = rand()%(upper + lower);
printf("%d\n", randomGen);
scanf("%s\n", &answer);
}while(answer != '=');
}
Whitespace in scanf format strings, like the \n in "%c\n", tries to match any amount of whitespace, and scanf doesn’t know that there’s no whitespace left to skip until it encounters something that isn’t whitespace (like the second character you type) or the end of input. You provide it with =\n, which fills in the %c and waits until the whitespace is over. Then you provide it with another = and scanf returns. The second time around, the character could be anything and it’d still work.
Skip leading whitespace instead (and use the correct specifier for one character, %c, as has been mentioned):
scanf(" %c", &answer);
Also, it’s good practice to make sure you actually succeeded in reading something, especially when failing to read something means leaving it uninitialized and trying to read it later (another example of undefined behaviour). So check scanf’s return value, which should match the number of conversion specifiers you provided:
if (scanf(" %c", &answer) != 1) {
return EXIT_FAILURE;
}
As has been commented, you should not use the scanf format %s if you want to read a single character. Indeed, you should never use the scanf format %s for any purpose, because it will read an arbitrary number of characters into the buffer you supply, so you have no way to ensure that your buffer is large enough. So you should always supply a maximum character count. For example, %1s will read only one character. But note: that will still not work with a char variable, since it reads a string and in C, strings are arrays of char terminated with a NUL. (NUL is the character whose value is 0, also sometimes spelled \0. You could just write it as 0, but don't confuse that with the character '0' (whose value is 48, in most modern systems).
So a string containing a single character actually occupies two bytes: the character itself, and a NUL.
If you just want to read a single character, you could use the format %c. %c has a few differences from %s, and you need to be aware of all of them:
The default maximum length read by %s is "unlimited". The default for %c is 1, so %c is identical to %1c.
%s will put a NUL at the end of the characters read (which you need to leave space for), so the result is a C string. %c does not add the NUL, so you only need to leave enough space for the characters themselves.
%s skips whitespace before storing any characters. %c does not ignore whitespace. Note: a newline character (at the end of each line) is considered whitespace.
So, based on the first two rules, you could use either of the following:
char theShortString[2];
scanf("%1s", theShortString);
char theChar = theShortString[0];
or
char theChar;
scanf("%c", &theChar);
Now, when you used
scanf("%s", &theChar);
you will cause scanf to write a NUL (that is, a zero) in the byte following theChar, which quite possibly is part of a different variable. That's really bad. Don't do that. Ever. Even if you get away with it today, it will get you into serious trouble some time soon.
But that's not the problem here. The problem here is with what comes after the %s format code.
Let's take a minute (ok, maybe half an hour) to read the documentation of scanf, by typing man scanf. What we'll see, quite near the beginning, is: (emphasis added)
A directive is one of the following:
A sequence of white-space characters (space, tab, newline, etc.; see isspace(3)). This directive matches any amount of white space, including none, in the input.
So when you use "%s\n", scanf will do the following:
skip over any white-space characters in the input buffer.
read the following word up to but not including the next white-space character, and store it in the corresponding argument, followed by a NUL.
skip over any white-space following the word which it just read.
It does the last step because \n — a newline — is itself white-space, as noted in the quote from the manpage.
Now, what you actually typed was < followed by a newline, so the word read at step 2 will be just he character <. The newline you typed afterwards is white-space, so it will be ignored by step 3. But that doesn't satisfy step 3, because scanf (as documented) will ignore "any amount of white space". It doesn't know that there isn't more white space coming. You might, for example, be intending to type a blank line (that is, just a newline), in which case scanf must skip over that newline as well. So scanf keeps on reading.
Since the input buffer is now empty, the I/O library must now read the next line, which it does. And now you type another < followed by a newline. Clearly, the < is not white-space, so scanf leaves it in the input buffer and returns, knowing that it has done its duty.
Your program then checks the word read by scanf and realises that it is not an =. So it loops again, and the scanf executes again. Now there is already data in the input buffer (the second < which you typed), so scanf can immediately store that word. But it will again try to skip "any amount of white space" afterwards, which by the same logic as above will cause it to read a third line of input, which it leaves in the input buffer.
The end result is that you always need to type the next line before the previous line is passed back to your program. Obviously that's not what you want.
So what's the solution? Simple. Don't put a \n at the end of your format string.
Of course, you do want to skip that newline character. But you don't need to skip it until the next call to scanf. If you used a %1s format code, scanf would automatically skip white-space before returning input, but as we've seen above, %c is far simpler if you only want to read a single character. Since %c does not skip white-space before returning input, you need to insert an explicit directive to do so: a white-space character. It's usual to use an actual space rather than a newline for this purpose, so we would normally write this loop as:
char answer;
srand(time(0)); /* Only call srand once, at the beginning of the program */
do {
randomGen = rand()%(upper + lower); /* This is not right */
printf("%d\n", randomGen);
scanf(" %c", &answer);
} while (answer != '=');
scanf("%s\n", &answer);
Here you used the %s flag in the format string, which tells scanf to read as many characters as possible into a pre-allocated array of chars, then a null terminator to make it a C-string.
However, answer is a single char. Just writing the terminator is enough to go out of bounds, causing undefined behaviour and strange mishaps.
Instead, you should have used %c. This reads a single character into a char.
I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.
I want to ask a specific question and get a Y/N answer read in by the user. I will need to use the character Y or N to change the outcome of the next question eventually, which is why I need the character to be saved so I can retrieve it later. I don't want to use a string or a for/while loop. Also, why do I need to include the * after "%c*"?
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int avgTemp, lowestTemp, temperature;
char choice ='Y';
char decision ='N';
printf("What is the average temperature?\n");
scanf("%d", &avgTemp);
printf("What is the lowest temperature in last 24 hours?\n");
scanf("%d", &lowestTemp);
printf("Has the temperature been over 99 degrees F for more than 30 minutes?
Please answer Y for yes and N for no.\n");
scanf("%c*", &choice);
printf("choice is %c", choice);
return 0;
}
Also, why do I need to include the * after "%c*"?
%c* means to scan for a character and then a * (which it will discard). Maybe you meant %*c which means do the scan but discard it. You don't need either of them.
scanf is a very problematic function and should be avoided. Your program illustrates the problem. scanf does not read a whole line. scanf will only scan stdin up to what you asked for and then stop. This means extra input and newlines can sometimes be left on the input stream for the next unsuspecting scanf. From the man page...
Each successive pointer argument must correspond properly with each
successive conversion specifier (but see the * conversion below). All
conversions are introduced by the % (percent sign) character. The format string may also contain other characters. White space (such as blanks, tabs, or newlines) in the format string match any
amount of white space, including none, in the input. Everything else matches only
itself. Scanning stops when an input character does not match such a format character. Scanning also stops when an input conversion cannot be made (see below).
This makes it very easy to accidentally leave characters on the input buffer. Each of your scanf("%d") will read in the number and stop. This leaves a newline on the input buffer. This is fine for %d because...
Before conversion begins, most conversions skip white space
...but not for %c.
Matches a sequence of width count characters (default 1); the next pointer must be a pointer to char, and there must be enough room for all the characters (no terminating NUL is added). The usual skip of leading white space is suppressed. To skip white space first, use an explicit space in the format.
So you need scanf(" %c") to make it work at all.
scanf is to be avoided because it's very, very vulnerable to unexpected input. Try giving "foo" to the first question. All the scanf("%d") will silently fail. And scanf("%c") will read f.
Instead, read the whole line with getline (preferred as it handles memory allocation for you) or fgets and then use sscanf on the resulting string. This avoids all the above problems.
I am using gcc (Ubuntu 4.8.2-19ubuntu1) 4.8.2
I am writing a very simple script to take string as input and print the same with the some custom message. First user enters the T(no. of times to take string) and then takes input by fgets.. I used this&this as reference. I am getting a very strange output ie fgets is adding some extra new lines and even loop is not working properly for T=2 it is asking input only once. Can anybody explain me what is wrong with snippet. Thanks in advance!
#include<stdio.h>
#include<string.h>
int main()
{
int T;
scanf("%d",&T);
while(T--){
char str[100]={""};
int i;
printf("Hello\n");
fgets(str,80,stdin);
i = strlen(str)-1;
if(str[i]=='\n')
str[i]='\0';
printf("World\n");
printf("%s\n",str);
}
return 0;
}
Please see the image reference for T=2, even T=2 it is taking string only once and order of printing statement is also not as expected.
This is because your scanf() call
scanf("%d",&T);
does not consume the new line character \n accompanied by your input.
When you input T, your input is 2Enter.
scanf() consumes the 2, sees \n and stops consuming, leaving \n in the input buffer.
When the fgets() gets called, it sees the \n in the buffer and treats this as the input.
To solve this, you have a few choices (in decreasing order of my subjective preference):
Use fgets() to get the first input, then parse it using strtol() to get T.
Add an extra fgets() after the scanf().
Add getchar() to consume one extra character. This works if you are certain that exactly one \n will be present after the input. So for example it won't work if you type 2SpaceEnter. Alternatively, you may use while(getchar() != '\n'); after the scanf() to consume everything up to a new line, but this may cause problems if an empty line is a valid input to your later fgets() calls.
If your implementation supports it, you may use fpurge(stdin) or __fpurge(stdin).
And, very importantly, do not use fflush(stdin) unless your implementation clearly defines its behavior. Otherwise it is undefined behavior. You may refer to this question for more details. Also, note that the fpurge() and fflush() methods may not work correctly if your input can be piped into the program.
This line
scanf("%d",&T);
reads the input until the first non-numeral is found, which is newline. Then fgets() reads that newline for its first input.
I suggest using fgets() to read the number too.
fgets(str,80,stdin);
sscanf(str, "%d", &T);
With your first call to scanf you allow the user to input an integer for the number of loops. They do so, and use a carriage return to signal the end of input. At this point scanf reads the integer, but leaves the end-of-line (\n) in the stream..
So when you call fgets, fgets gets from the stream until it reaches the first newline -- in you code, on the first loop, this is the very first character it encounters.
If you discard the newline before calling fgets, you should get your desired results. You can do this, for example by changing your first three lines to:
int T;
char newline;
scanf("%d%c",&T, &newline);
Although there are probably stylistically superior ways of doing this.
You have a newline character in the input stream when you press "enter" after typing 2 for the first scanf. This is consumed by fgets() initially, hence it prints nothing (You replace the newline by \0).
In the next line, your input is read and echoed after World because you are printing it after it.
I've been having a lot of problems trying to figure out how to use scanf(). It seems to work fine with integers, being fairly straight forward scanf("%d", &i).
Where I am running into issues is using scanf() in loops trying to read input. For example:
do {
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
} while (command != 'q');
When I enter in a validly structured input like c P101, it seems to loop again before prompting me. This seems to happen even with a single:
scanf("%c", &c)
in a while loop. It'll do the loop twice before prompting me again. What is making it loop twice, and how do I stop it?
When I enter in less amount of input that programmatically wouldn't have another character or number such as q, pressing enter seems to prompt me to enter more. How do I get scanf() to process both single and double character entries?
When you enter "c P101" the program actually receives "c P101\n". Most of the conversion specifiers skip leading whitespace including newlines but %c does not. The first time around everything up til the "\n" is read, the second time around the "\n" is read into command, "c" is read into prefix, and "P" is left which is not a number so the conversion fails and "P101\n" is left on the stream. The next time "P" is stored into command, "1" is stored into prefix, and 1 (from the remaining "01") is stored into input with the "\n" still on the stream for next time. You can fix this issue by putting a space at the beginning of the format string which will skip any leading whitespace including newlines.
A similiar thing is happening for the second case, when you enter "q", "q\n" is entered into the stream, the first time around the "q" is read, the second time the "\n" is read, only on the third call is the second "q" read, you can avoid the problem again by adding a space character at the beginning of the format string.
A better way to do this would be to use something like fgets() to process a line at a time and then use sscanf() to do the parsing.
It's really broken! I didn't know it
#include <stdio.h>
int main(void)
{
int counter = 1;
char command, prefix;
int input;
do
{
printf("counter: %d: ", counter);
scanf("%c %c%d", &command, &prefix, &input);
printf("---%c %c%d---\n", command, prefix, input);
counter++;
} while (command != 'q');
}
counter: 1: a b1
---a b1---
counter: 2: c d2
---
c1---
counter: 3: e f3
---d 21---
counter: 4: ---e f3---
counter: 5: g h4
---
g3---
The output seems to fit with Robert's answer.
Once you have the string that contains the line. i.e. "C P101", you can use the parsing abilities of sscanf.
See:
http://www.cplusplus.com/reference/clibrary/cstdio/sscanf.html
For question 1, I suspect that you've got a problem with your printf(), since there is no terminating "\n".
The default behavior of printf is to buffer output until it has a complete line. That is unless you explicitly change the buffering on stdout.
For question 2, you've just hit one of the biggest problems with scanf(). Unless your input exactly matches the scan string that you've specified, your results are going to be nothing like what you expect.
If you've got an option you'll have better results (and fewer security issues) by ignoring scanf() and doing your own parsing. For example, use fgets() to read an entire line into a string, and then process the individual fields of the string — maybe even using sscanf().
Perhaps using a while loop, not a do...while loop will help. This way the condition is tested before execution of the code.
Try the following code snippet:
while(command != 'q')
{
//statements
}
Also, if you know the string length ahead of time, 'for' loops can be much easier to work with than 'while' loops. There are also some trickier ways to dynamically determine the length as well.
As a final rant: scanf() does not "suck." It does what it does and that is all.
The gets() function is very dangerous (though convenient for no-risk applications), since it does not natively do any checking of the input. It is VERY commonly known as a point of exploit, specifically buffer overflow attacks, overwriting space in registers not allocated for that variable. Therefore if you choose to use it, spend some time putting some solid error checking/correction in.
However, almost invariably, either fgets() or POSIX getline() should be used to read the line — noting that the functions both include the newline in the input string, unlike gets(). You can remove the trailing newline from string read by either fgets() or getline() using string[strcspn(string, "\n")] = '\0'; — this works reliably.