[c][explained] Problems with scanf
HTML-код
- Опубликовано: 13 окт 2020
- I do my best to credit the sources and people that helped me with the content. For this one, I did get help from people on Reddit and Discord. :D
Some of the articles that I read to make this:
/ fun-with-scanf-in-c
stackoverflow.com/a/22902085
I do know about the places where some of the lines are not consistent with the opacity, but meh, didn't do a retake, I apologize.
%s does not consume the whitespace (
). It stops at one, and appends the null terminator. That explains why a space in a string doesn't get read into the buffer supplied to scanf. So, it's actually %d that discards the leading whitespace.
Thanks to the redditor who pointed this out.
does float and double date types also discards the leading whitespace? please tell me......
and where is the reddit you are talking about?
@@maharunYes. They also discard the white space.
The subreddit is C_Programming.
Wish I knew this years ago. When doing uni assignments which involved command line I/O this stuff was such a headache. Everybody in my class found a different way to reinvent the wheel and deal with this behavior.
You can use [^
] to consume the '
', like this: scanf("%[^
]s", my_string);
it reads: read everything that it's not '
'.
the trick is that italso matches '
' and consume it. So you can interpret it as "read eveything until new line, excluding the new line"
this is great to read more than one word in a single sentence
I usually just `fgets` into a temporary buffer and then parse the value of that buffer. I don't like scanf's spurious behavior
@@shadamethyst1258 or just use a getline
@@abhishek.rathore getline is not a C standard library function, it’s a POSIX extension
Regex?
@@lembranaodesistaissonaoimp5762 meio que isso mesmo, o scanf aceita certas funcionalidades de regex.
A good option also is to select what would be the maximum number of characters that scanf will read.
char name[10];
scanf("%9s",name);
So if the user writes more characters than 10, only the first 10 would be taken. Avoiding any buffer overflow.
Thanks
maybe only read 10-1 characters, and keep last one for guaranteed /0
Actually it **WILL** overflow the buffer for 10-letter input. It will place byte `0` at `name[10]` that does not exist overflowing a buffer. To fix it use "%9s" specifier
@@tomaszstanislawski457 I haven't programmed in c for a long time, I appreciate the correction if I wrote something wrong. Happy hacking!
@@diegoenriqueoviedollanes453 I'd advice you to edit your original comment to %9s because many people don't delve deeper into the replies.
Dude thank you so much. Every other solution I found online was crap. This is well explained and your editing is great. Very well made.
it's been 3 years and your video is still saving lives. thank you very much! ❤
thanks for this, keep doing it, i found the video super helpful and it taught great things, the illustrations are amazing thank you.
You're so cool, I love your "C explained" series
Thank you for making this video you help me so much to understand problems with code you've made a really good job
I always used the space in the scanf, just because it works, thanks for explain that, now everything makes sense.
Thank you so much. You were very clear in the explanation. Keep it up. U will reach the sky for sure.
This is an amazingly insightful video. Thankyou smmmm
Thanks for tge video! I programming on C a lot of time and I never faced this problem, I sure that this knowledge will help me in the future.
I was banging my head against the wall trying to figure this out. Thank you for the great explanation!
I've been looking for info on why this happens in scanf for ages, thanks man
Really nice quality, keep that good work
Thanks for that useful way of asking for input, my programs were full of fflush, not anymore
how am i just finding this!? thank you commandah
This video is beautiful! May i ask what you used to animate it?
Thanks! It’s Keynote.
very good explanation! helped me a lot
Best explanation for the scanf issue.
A good solution is using fgets in combination with another parsing method (strtol etc.)
Me who only uses getline when reading input from user:
*What is going on here ?*
thank you so much, saved my time
Excellent video, thank you for the explanation.
What font is being used here?
DM Mono, iirc.
Great explanation!
I am pretty sure that this is the same problem as Java's scanner. Just write two scanner .nextLine() inputs one after the other and it skips the 2nd one when executed.
Yep, it suffers from the same thing.
You could also use %*c to clean the buffer
Can you please tell me from where you learnt this
Any book, website, playlist
2:01 actually the
is still in stdin, however when you read the %d it consumes the
looking for an integer
Addressed in the pinned comment with a little more detail.
Thanks Dude!!! u r great!
One lovely trick that I have against this is literally a single macro which is
#define CINFLUSH scanf("%*[^
]");scanf("%*c");
Works every time, all the time.
Great video! What software did you use for editing this video?
Keynote :D
This is from my little "test" library (simplified):
```
void get_str(char *s, int n) {
if (s != NULL && n > 0) {
int len = 0, maxlen = n - 1;
int c = getchar();
while (c != '
' && c != EOF) {
if (len < maxlen) {
s[len] = c;
len++;
}
c = getchar();
}
s[len] = '\0';
}
}
```
`s` is the storage and `n` is the storage capacity. The loop extracts all characters from `stdin` until a delimiter newline or `EOF` is found. The condition inside the loop makes sure that only the first `maxlen` characters (excluding the delimiter) are written to `s`. `maxlen` is `n - 1` because at least one element must be reserved for the null character.
If you give the right arguments, you can type as much as you want without having to worry about buffer overflow. The function will get rid of the excess characters, including the delimiter. I think this is a nice little "training wheel" for beginners.
This is exactly what fgets does :)
@@shadamethyst1258 Not exactly. My function gets rid of the the other characters not stored in the array, including the delimiter newline. `fgets()` does not do this. Please read the description again carefully.
very enlightening
Thanks it helps a lot
C is such a mess from a developer experience perspective (understandable, considering when it was introduced). I work as a software engineer for several years and have some C/C++ background, but I still watch the video open-eyed. Very good content and nice visuals.
Yeah C is really starting to show its age now. It’s been a good run but more modern languages are probably a better choice for most tasks. And with Rust being just as quick, capable, suitable as a systems programming language and becoming more and more mature, C and C++ probably will have to fight for its right to exist.
@@CrippleX89 Maybe C, but the new C++ standards have everything you'd want in a good language. Smart pointers, threading, softer typing, modular packages, among others...
@@bva0 C also supports threading
get good
@@bva0 maybe but all of the backwards compatibility in C++ makes the language very complicated and a horrible mess to deal with
Nice presentation
Man I wasted so much time because of this problem! Thanks for the explanation
Thank you sir
That's awesome.....👌👌
thank you
you made a mistake... %s doesn't consume new line.. it leaves the
in the stdin buffer..
try taking a string
then take a char1 input
then take char2 input
when you will run it
1. you enter the string
2. it SKIPS char1 input
3. goes to char2 input
so %s never consumes new line
I address this in my comment.
@@theteachr "I address this in my comment" 🤓 screw off
Now I like C even more
Nice
Thanks😊
Thanks for the explanation, but i coud't get the problem solved. is there any other way to get out of this?
Having `while (getchar() != '
');` before scanning a sequence of characters should work just fine. Join the Discord and post the query for a more elaborate explanation specifically tailored to your use case. discord.gg/ANUEGSZPvn
what software did you use to edit the video?
Apparently it was made using keynote
im amazed this dude called noob to everyone that uses scanf lol
This random youtuber succeeded where teachers have failed, thx. Although I just use C++ instead
Thank you so much i am new to coding and this was soo annoying to see even when i write the code correctly it will just stop. Thak you
thnks
+10 social creit score ⬆
std::cout
can smn explain the while (getchar() != '
'; part i dont get it
I shall.
char str[101];
scanf("%100[^
]", str);
while(getchar() != '
');
This solves some of the problems but not all of them.
But why adding that weird space before %c would make it work ?
A space in the format string for `scanf` means any amount of whitespace (newlines, spaces, tabs, ...). `scanf("%c %d", &gender, &age)` would read the input `m 45` and assign `m` to `gender` and `45` to `age`.
@@theteachr Appreciate the reply. Thanks alot
cin cout one love 🦊💖
If you do a cin on an int, but the user entered something that could not be parsed as one, the variable would be set to 0. I had no idea how to differentiate between a valid input of 0 and an invalid input, as in both the cases the variable would have the same value.
It sets some global error flag (I think). IMO, it should have been something that the programmer couldn’t skip.
@@theteachr for int you can use atoi( ) and there will be no errors )
scanf("%[^
]
", name);
Read everything til new line into name then consume new line.
I tried this! The function scanf(_s) never returns. It's an infinity loop for string input.
Although, it works for anyting that is NOT a string. For example,
scanf_s("%c
", &gender, 1u); // WORKS AND RETURNS
You would think that after all this time something as simple as this would have been "fixed". I wonder why they haven't changed that
Pretty sure Scanner.nextLine() and Scanner.nextInt() in Java have exactly the same problem xD
Yes, it does.
does this problem have a name?
I wouldn’t think so. It’s expected behavior after all. The programmer is expected to know of the subtlety and that’s what is the problem.
and we have problems with like python/java/lua/etc this is worse
Bisqwit brought me here.
This sent me to Bisqwit.
Name: Genie
Age: six
Age: Age: Age: Age: Age: Age: Age: Age:....
These fixes are not effective. You should test input at each input. You can even write a small input check function to consolidate your code.
I recommend Hacking the Art of Exploitation by Jon Erickson. The chapter on programming is strictly C programming and has numerous examples of input and error checks.
Thanks for the input and the recommendation!
Your first problem was only having two genders lol
I want more reactions than just being able to ❤️ the comments.
VERY NICE explaining and work , great. But It is not working in Eclipse. First Scanf processes, the second to last not, And it would only print PRintfs. All correct
include
int main()
{
char name[20];
float greutate;
int ziua;
int luna;
int an;
//scanf("specificatori de format", adresele_din_memorie);//
printf("Name of sir:
:");
fflush(stdout);
scanf(" s", nume);
printf("Cat este de greu domnul:[kg]
");
fflush(stdout);
scanf(" %f", &greutate);
printf("Dati ziua:
");
fflush(stdout);
scanf(" %d", &ziua);
printf("Dati luna:
");
// windows
fflush(stdout);
scanf(" %d", &luna);
// afisare ziua si luna
an = 2020;
printf("Astazi este %d/%d/%d!", ziua, luna, an);
return 0;
scanf("%s", nume);
I think the missing % is causing you an issue.
so unnecessary
What exactly?
its pronounced char as in charcoal not care........ 👎👎👎 boo
" %[^
]s " worked for me.
printf("
Name: ");
scanf(" %[^
]s ", vec[i].name);