Комментарии:
Regarding the last question, at least , because C doesn't have C++ style references... In C++ you should always use std::cin (or std::ifstream for places where you would use fscanf) partially because of the aforementioned pointer issues...
ОтветитьI am really glad I found your channel, very useful information and well presented. Thank you!
ОтветитьSo I should better stop using scanf in favor of fgets? at least for strings, in case of numbers I guess I'm stuck with scanf
ОтветитьYet another great video ❤
ОтветитьTyping in letter when program expects a number:
Python - throws an error and ends 😎
Pascal - throws an error and ends 😎
Commodore 64 basic - just asks again 😎
Go - assigns 0 to the variable 😎
C - infinite loop until your CPU is on fire🤬
(yes, I know I can walk around this using char array and fgets and sscanf functions, but still...)
Just one note, fflush has an undefined behaviour when it is being used for stdin because it is originally was made for stdout
ОтветитьWhere can I buy this t shirt ?
ОтветитьThis explain so well why I love C. I initially had all the problems you described here with using scanf(). But when I read up on the function details, I found a solution which you described here (with the nextchar , buffer flush, and while loop). Now, some would say that's a lot of work for such a simple thing. Well, I've never written a C program that only use scanf(). SO there's a little bit of setup, putting this in a functio and call it from the rest of your code. What it gives you a the building blocks to read an input. Let's say my input a huge file and I've pre-checked and data is clean, then it's faster to use scanf() without all the error checking. And it makes sense why scanf() works the way it does, not some kind of magic. And the buffer overflow, again put it your custom "input function" or something. LOL modern programmers.. (err developers rather). At least with my experience, it takes some time to figure out C.. it's not Python where you can't just slurp an entire text file into an array, even if the file is 10gb. LOL
ОтветитьTokenizing free knowledge.
No
Newbie to C here but I think I would try and use the isdigit function, it only checks a char at a time, but you can write a new function using isdigit, or just copy the one on stackoverflow. So if (0 == (isdigits(result))) or something like that.
Ответитьhi jacob can u make a video about register level programming in embedded systems would be a nice topic. love so much your content
Ответить>write my own scanf
thats the first thing that came to my mind
why not just use "read (1, buff, buffsize)"?
A way to workaround buffer overflows is to use "%ms" and provide the address of the string variable. scanf will allocate the string for you (similar to asprintf)
It is part of the POSIX standard so not a problem on Linux, but not available on Windows (which is compliant with the old POSIX-1 standard) and likely not on embedded.
Note that it used to be "%as" (very old compilers/libc)
Hey, can you maybe make a video about filesystems?
Ответитьthanks jacob. i now understand why my scanfs didnt work in college days... <3
ОтветитьScanf is full of amazing stuff when you consider it, especially when you consider its behavior when treating non-format specifier. For example something like:
result = scanf(" %*dinput%d%c", &x, &trailing_char);
Which is probably the closest thing standard C got to regex.
When starting with C, I tought that the best part of printf and scanf was print and scan but when I started to understand what they did, I realized that the best part of it is actually the f.
fgets master race
Ответитьreally love someone who addresses scanf and printf as function and further explain pass by value n pass by reference , as many tutorials just call them this is the way to get input and display output ! ,!!
ОтветитьThis video on Scanf Basics is an absolute game-changer! It's exactly the type of content I've been searching for. I'm so glad I stumbled upon this video. It has inspired me to create more programming content on my channel. Thank you for sharing your knowledge, I can't wait to see more from you! 🦾
Ответитьfflush(stdin) on an input stream, is undefined behavior. It works on WIndows, where there's poor standards compliance. But MSYS2, Cygwin, BSD, and Apple all should use fpurge(stdin) and Linux uses __fpurge(stdin) from Solaris, defined in stdio-ext.h. They really need to ISO standardize fpurge(), or even POSIX, but neither board likes moving too quickly and it hasn't yet been 40 years yet 🤣. It's a bit of a mess. I just took the time to write my own header, so I can use a fpurge() macro that'll select the correct function for the system, that can be dropped in and used everywhere, when I need to write portable code. Or there's also the minimally flawed alternative: while((getc(stdin) != '\n'));
Ответитьscanf() has the ability to take length as a parameter.
ОтветитьThere's also the bounds checked scanf_s from C11.
ОтветитьCan avoid the whole pointer issue and verify input by just making a custom function:
uintmax_t parseju( FILE *file, char *stopped )
{
uintmax_t value = 0;
unsigned int c = 0;
int was = 0;
while (1)
{
was = fgetc();
c = was - '0';
if ( c > 9 )
break;
value *= 10;
value += c;
}
if ( stopped ) *stopped = was;
return value;
}
Don't remember how to "put back" the read character but you get the gist
Why doesn't it skip the second scanf when there's apparently still the '\n' in the buffer?
ОтветитьThis is cool. I can think of several instances where I want mixed input say like the value then units like 13' 4" or 37F.
ОтветитьI've been programming in C since 1987 and I can honestly say I NEVER used scanf() in any of my programs. Its behavior is simply too murky for my taste. Like you said, I'd rather read in the whole shebang using fgets() and tokenize the whole bunch myself (not necessarily using strtok() for that).
Just for fun, I've been doing a sscanf() like routine for my own Forth compiler - and still: some behavior of scanf() was baffling me. A few changes I made:
(1) My ”SSCANF” really doesn't like whitespace - neither in the buffer nor in the format string. When it encounters it, it will vehemently look for the first ”non-white space” character and resume parsing from there. Which means that these format strings are equivalent: "%c %c %c" and "%c%c%c".
(2) When parsing it takes a real good look at the delimiters you defined in the format string. If you define: "%s" and your buffer contains ”Hans Bezemer”, it will parse the entire string. However, if you define: "%s ", it will only parse ”Hans” and leave the rest of the buffer unparsed.
The upside of all this is, is that strings in the buffer are not automatically delimited by whitespace. Take "Invoice issued by [%s] on %u-%u-%u". If we feed ”SSCANF” this buffer: "Invoice issued by [Hans Bezemer] on 2022-04-03", it will happily read the entire ”Hans Bezemer” - and not just ”Hans”.
Still - although it was lots of fun to develop, I've never used it (yet) in my own Forth programs. I still don't trust it with real world data ;-)
using FORTIFY_SOURCE with gcc prevents some simple buffer overflows, This would be a cool trick to show
ОтветитьI use fgets compined with sscanf to read user input.
Ответитьas far as i know, fflush(stdin) has undefined behavior and it doesn't work with GCC on Linux.
You're living dangerously there.
Do you Rust?
ОтветитьAwesome ❤️❤️❤️
Could you tell us the name of font you are using in vs code?
Jacob, these 'deeper look at the basics of C' kind of videos are really useful. Great stuff.
ОтветитьYour videos are awesome
Huge thanks