Тёмный

Why Printf is Magically Breaking Your Program. 

Jacob Sorber
Подписаться 167 тыс.
Просмотров 28 тыс.
50% 1

Опубликовано:

 

27 окт 2024

Поделиться:

Ссылка:

Скачать:

Готовим ссылку...

Добавить в:

Мой плейлист
Посмотреть позже
Комментарии : 145   
@theondono
@theondono 2 года назад
One of my colleagues found a scary version of this. He was using a MCU and was using the last page in the flash memory to keep some permanent variables (a common enough hack). He was changing some printfs and suddenly the board started to reset at random points. Turns out that by making small changes on those printfs, he was shifting code *into the last page of the flash memory*, and since flash can only be erased by page, writing to the permanent variables erased part of his code and creating havoc. The moral of the story, if you decide to use the last page of flash as permanent storage *remove it from your linker map*.
@timovandrey
@timovandrey Год назад
Very insightful!
@abdullaalmosalami
@abdullaalmosalami Год назад
Yeah that probably has less to do with the printfs and more to do with you last point haha. I mean the same thing would have happened if the programmer had just added a bunch of code or pulled in additional library functions that needed to get linked and located.
@ahmadhadwan
@ahmadhadwan 2 года назад
Good Video Dr. Sorber. I have encountered this issue before, when corrupting the heap, some standard C functions will cause a seg fault. Using valgrind is always helpful when having these types of issues.
@mCoding
@mCoding Год назад
Gratz on 100k!
@luz_reyes_676
@luz_reyes_676 Год назад
Nice check mark you got there!
@JacobSorber
@JacobSorber Год назад
Thanks!
@Marco-yj6gg
@Marco-yj6gg Год назад
Thank you for this video! I think (and that's unfortunately not the case ; at least where I was taught C) it's very important to teach beginners that memory (especially in C) is one contiguous block, so if you overwrite any "variable" then you're ultimately changing some other variable in the process (except when you're accessing unmapped memory of course). I had this happen some time, and knowing that memory is just one big block of data really helps debugging code that is behaving in "mysterious" ways :)
@JacobSorber
@JacobSorber Год назад
I couldn't agree more. Thanks!
@SimGunther
@SimGunther 2 года назад
The real "bug" was the malloc of "values" when you thought that it's allocated enough memory for the struct (1028 bytes) when it actually allocated 8 bytes. That confusion in what size is calculated is what makes mallocs tricky. Using sizeof (struct myvalues) should do the trick.
@quadric_
@quadric_ 2 года назад
sizeof (*values) is also usable
@monochromeart7311
@monochromeart7311 2 года назад
Using sizeof on the type directly is dangerous, because the type of the variable may change without changing the malloc() call. It's recommended to do sizeof on the variable. If you want to be safer, you do: #define ALLOC(type) (type*)malloc(sizeof (type)) int *p = ALLOC(int); This way you will get errors on type mismatch when assigning.
@filips7158
@filips7158 2 года назад
@@monochromeart7311 casting malloc return value in C is useless, as it returns a void pointer. In C++ it is required, not that you should use malloc in a C++ program.
@monochromeart7311
@monochromeart7311 2 года назад
@@filips7158 you missed the point. If we do use #define Alloc(type) (type*)malloc(sizeof (type)) And then do: int *p = Alloc(double); The program won't compile, the type is safer. It's basically C++'s `new` operator (without the constructor call) which returns a type-correct pointer. It's an alternative to doing the following (which can be a victim to code changes): int *p = malloc(sizeof (*p)); It we mistype the variable used with sizeof, and it's still a valid variable, it can still give "incorrect" results.
@sparow2121
@sparow2121 2 года назад
I had a fun version of this bug. My program crashed whenever I freed a certain pointer. If I didn't call free, it worked perfectly fine. Turned out, I had written off of the end of an array by just a byte or so, enough to corrupt the meta data of the pointer so that free didn't know how big it was, but the pointer could still be used.
@riccardob9026
@riccardob9026 Год назад
That's a classic. In my experience, bugs like this can take *days* of debugging because the crash happens in a place that is totally unrelated with the real bug (the buffer overflow).
@smartkorean1
@smartkorean1 2 года назад
Thank you Mr Sorber for uploading these videos despite your busy schedule. I recently switched majors to Computer Engineering and have taken an interest in embedded systems. Looking for guidance and I found this channel. Currently working on the Arduino and just started with a TI. I look forward to your uploads!
@darylh8657
@darylh8657 Год назад
We used to call this kind of bug, "Heisenbugs". For the longest time, they were hard to debug, but once you recognize its character, you could identify it and immediately look for the cause - either an uninitialized variable or buffer overrun.
@riccardob9026
@riccardob9026 Год назад
Yes, although with experience you learn to recognize the bug type, sometimes the problem is to find where you did the buffer overflow. Especially with fairly complex software, you could overrun the buffer in a completely different place. Been there...
@darylh8657
@darylh8657 Год назад
@@riccardob9026 The worst one was when I neglected to set the direction bit in an interrupt routine. Many exciting hours trying to track that bugger down.
@inertia_dagger
@inertia_dagger Год назад
I like these videos, they allow me to learn more about how programs actually work, and also make me appreciate modern programming languages
@jdeleca
@jdeleca 8 месяцев назад
This line: *struct myvalues *values = malloc(sizeof values);* if you test to see the size: *int size = sizeof(values);* it will give you *8* (on 64-bit), that's is the size of the pointer, since you are declaring **values* as a pointer, *malloc* is allocating only 8 bytes for the *values* variable, you either change it to: *malloc(sizeof struct values);* or *malloc(sizeof *values);* this last one it just dereferencing the variable to get the type of the variable and that's what sizeof needs
@HoloTheDrunk
@HoloTheDrunk 2 года назад
And then people act surprised when I say I stopped using C... Great video though!
@DatBoi_TheGudBIAS
@DatBoi_TheGudBIAS Месяц назад
C is great, never stop using it! Just don't have skill issue, accidents happen. Just fix them
@keykeyjean2003
@keykeyjean2003 2 года назад
Congrats on 100k subs!
@neerajkale
@neerajkale Год назад
Congratulations for 100k subscribers! 🥳
@JacobSorber
@JacobSorber Год назад
Thanks! 😃
@zyghom
@zyghom 2 года назад
printf (actually: Serial.printf) is the cause of 80% my segfaults on ESP32 ;-) - and I still use it instead of i.e. simpler Serial.println() from Arduino. I simply love the way printf formats the arguments ;-) And it also helps me program better (I think)
@user-mr3mf8lo7y
@user-mr3mf8lo7y 2 года назад
Thanks for saving my day.. Wondering if you could make a video about static llinking, next. Cheers,.
@Ryan-xq3kl
@Ryan-xq3kl Год назад
another similar mistake I make is assuming i have argv[1] in the program without checking for it first which results in the segfault
@unperrier5998
@unperrier5998 2 года назад
And it doesn't mean that Mac is safer than Linux :)
@supernovaw39
@supernovaw39 2 года назад
It's weird to me to judge that based on such unpredictable behaviour. You could also look at it as Linux hepling you detect a serious flaw faster instead of helping you ignore the problem for longer.
@unperrier5998
@unperrier5998 Год назад
@@supernovaw39 you could look at it any way you want, it doesn't change the fact that the underlying is merely random.
@supernovaw39
@supernovaw39 Год назад
@@unperrier5998 yup
@icoudntfindaname
@icoudntfindaname 6 месяцев назад
I experienced a bug where a printf was changing the value of a function pointer on the STACK... I hadn't allocated anything on the heap
@DatBoi_TheGudBIAS
@DatBoi_TheGudBIAS Месяц назад
That's very weird, Cuz afaik, printf doesn't write a single variable on memory. Well, other than the return
@snipzmattio5887
@snipzmattio5887 2 года назад
100k subs, congrats!
@kevincozens6837
@kevincozens6837 Год назад
It is situations like this where valgrind becomes extremely useful as it helps find errors in memory usage.
@andreasthiemke9520
@andreasthiemke9520 Год назад
Feel like the video was a bit long for explaining things. But once we got around to it, you explained it really well.
@HansLemurson
@HansLemurson Год назад
So printf will just sometimes make invisible malloc problems visible?
@thearmyofiron
@thearmyofiron Год назад
I had this code that would get error without printf and after I added the printf in, it ran well, is this black magic explainable?
@easyTarget2000
@easyTarget2000 2 года назад
I don't understand the explanation with the heap diagram. To me, it sounds like you're describing how printf may move the struct outside of the allocated memory space, causing the program to crash. The opposite of what happens in the example.
@kirlian5399
@kirlian5399 2 года назад
The drawing is in the wrong order, I suppose. Imagine the purple rectangle on the right, shifting the blue one a little to the left. The blue rectangle still spills to its right, overwriting the purple but without going out the page.
@bm1259
@bm1259 Год назад
Does it work ok on Mac since they use dynamic paging?
@metal571
@metal571 Год назад
Hopefully AddressSanitizer would catch that
@CaptainWumbo
@CaptainWumbo Год назад
Side effects! This is definitely one of those things you stare at for way too long when you're new to a language. The importance of fundamental understanding is highlighted by bugs like this, and it's even worse when you're in a high level language and the bug is underneath you. It's also one of the things that makes C really fun and interesting to learn for me, when you realise yes you can just read past what you actually allocated into garbage memory until the OS eventually complains you read an address you don't have its permission to read. A good habit for beginners is probably to print the number representing the memory you think you're requesting and see if it sounds as big as it should be.
@Wassim971
@Wassim971 Год назад
Wait so printf allocated a new page, therefore the struct my values overflow had some more memory to work with and that's why it didn't segfault?
@sadhlife
@sadhlife Год назад
yup
@jaimeduncan6167
@jaimeduncan6167 Год назад
What this really means is C is broken. For the current generation, thinking about that kind of detail is crazy. I learned by myself working in a machine with less than 1MB and had a portable machine with less than 64 when I was a kid, so clearly, I learned to think of memory, registers, reordering, and that kind of stuff. Today devoting yourself to learning that kind of stuff makes no sense. Today the compiler is better than most ASM code, all modern computers are superscalar and someone is better speding the time to truly understand functional or dynamic programming.
@your-mom-irl
@your-mom-irl Год назад
go play with your javascript kid
@andrewsquest628
@andrewsquest628 Год назад
Well, I've got something similar, but not exactly the same. Still, thanks a lot, for it helped me to get a better grasp on what might be going on under the hood.
@minhajsixbyte
@minhajsixbyte Год назад
how do you jump back and forth your vm and mac? initially i assumed it was an ssh but then how do the files sync only plausible answer comes to mind is the vm has a shared folder. please show your dev environment setup some day
@JacobSorber
@JacobSorber Год назад
Yeah, I use vagrant with a shared folder.
@1over137
@1over137 Год назад
Coming from MCU land I laughed when he said printf() allocates 1K-8K. I used printf() on an MCU with 4K of RAM. The issues in that space with printf and all it's buddies is the stack allocation. If you are tight up against it with your heap and stack closing on each other printf and it's friends will happily tramp on through your heap... or trip the ARM fault handler trying to write to program memory.
@greg4367
@greg4367 2 года назад
Greetings from San Francisco. Good job, well done
@freshtauwaka7958
@freshtauwaka7958 Год назад
If I am not mistaken the "values" data is also not initialized to zeroes, which might even cause another segfault when printing with %s
@vytah
@vytah Год назад
In general, you're right. It happens to work in this case, because the memory is fresh from the OS, and I think all OS's fill the newly allocated pages with zeroes.
@jwbowen
@jwbowen Год назад
Could you do a video showing how to track this down with a debugger?
@malithperera2764
@malithperera2764 Год назад
Will Rust replace C???
@Victor_Marius
@Victor_Marius Год назад
I was wondering why that bug isn't actually a compilation error. I wouldn't use the same variable on the same line when creating it in any language.
@descalsotajames1838
@descalsotajames1838 2 года назад
Hi guys, I need advice. I'm going to make an application. What is the best language to make an activity recommendation app and how can I implement the collaborative filtering algorithm? im newbie. advance thankyou for the answer
@ngwanamama1572
@ngwanamama1572 Год назад
Can this memory corruption be caused by input functions like getchar ?
@SolomonUcko
@SolomonUcko Год назад
For values, shouldn't you use calloc instead of malloc to make sure the memory is zero-initialized?
@DatBoi_TheGudBIAS
@DatBoi_TheGudBIAS Месяц назад
U don't need to zero initialize the struct when ure reading directly into it Normally U zero initialize variables when their initial state matters. The fgets will read into each buffer and will work fine
@KangJangkrik
@KangJangkrik Год назад
The most magical moment is when your program causes BSOD accidentally
@wlcrutch
@wlcrutch Год назад
Wtf…was just reading about this on SO after valgrind is complaining about all of my printf…and this is the first suggestion that comes up? 😮
@mlg_quintus4361
@mlg_quintus4361 Год назад
it would probably be better to allocate like this: malloc(sizeof(*values)) this way you don't have to duplicate information
@JacobSorber
@JacobSorber Год назад
Good point. Thanks.
@chrissaltmarsh6777
@chrissaltmarsh6777 2 года назад
Brill. Being ancient, I have fallen into such traps. There was one really good one in HPUX, where their malloc - the contract is no guarantee of content - had the first few bytes loaded by malloc itself. Perfectly allowable. I had to debug a bit of C that worked, mostly, but sometimes seg faulted. Took a bit of time to find that.
@turtle421
@turtle421 Год назад
Which IDE should I be using for C programs? I am programming in Java currently and use *Eclipse* at my personal laptop and *Intellij Idea* at office.
@Eva-tf5ud
@Eva-tf5ud Год назад
It doesn't matter at all. You may use Notepad or even Word. C != Java, there is not IDE or anything, that, for instance, can automatically write setters and getters. Just use Codeblock or Visual Code, but overall it does not matter
@turtle421
@turtle421 Год назад
@@Eva-tf5ud helpful.
@Eva-tf5ud
@Eva-tf5ud Год назад
@@turtle421 I mean setters and getters for C structures, sorry
@Eva-tf5ud
@Eva-tf5ud Год назад
@@turtle421 you're welclme
@d.sherman8563
@d.sherman8563 Год назад
@@Eva-tf5udI think word would give you a world of pain with it’s binary format 😂
@jaimeduncan6167
@jaimeduncan6167 Год назад
Great video.
@ALTracer
@ALTracer Год назад
But when I wrote short helloworlds like this one, printf("literal") call was optimized by gcc to a puts() call, and the literal is either on the stack or in .data, which doesn't explain heap usage. Maybe something to do with stdout or stdio buffering? Additionally, why didn't you show -fsanitize=address (or =undefined) and valgrind analysis on this example? This would be very helpful and educational.
@ivanscottw
@ivanscottw Год назад
I bet if you had used gcc you would have had a different result because it is also related to the fact that LLVM is using its own memory allocator (not glibc's).
@Filaxsan
@Filaxsan 2 года назад
Ahah amazing!! Thanks for this video, really insightful!
@JacobSorber
@JacobSorber 2 года назад
Glad you enjoyed it!
@justinrand678
@justinrand678 Год назад
Really helpful 😎
@alexrossouw7702
@alexrossouw7702 2 года назад
printf, and memcpy, are always my first suspects
@sadhlife
@sadhlife Год назад
printf wasn't the real problem here though
@loc4725
@loc4725 Год назад
"Works on *my* machine". 😏
@talhaibnemahmud
@talhaibnemahmud Год назад
Pretty interesting video
@katiagalkina4607
@katiagalkina4607 Год назад
Thank you so much for this interesting video! I certainly learn something new with each one! can you please make one for dealing with fundamental inaccuracy of floating point numbers? as far as I know, they're never 100% accurate, so how to overcome that if it's possible? the worst thing about the program is an unreliable output.
@AbelShields
@AbelShields Год назад
The only way to "overcome" that is not to use them 😂 Jokes aside, they're 100% accurate at representing sums of powers of two (including e.g. 3/4 = 2^-1 + 2^-2) as long as the difference in range is less than 53 bits (for float64/double) - so representing 2^53+2^-1 will lose the 2^-1. If you need to be 100% accurate, I think most banks/financial institutions work with fixed point numbers - they use an int/long, and say that each 1 represents a cent, or a thousandth of a cent, or whatever.
@katiagalkina4607
@katiagalkina4607 Год назад
@@AbelShields if every 1 represents 1 cent, there must be 13 bytes room for the cents only? or using like 7 bits I guess? The problem I'm facing is that output depends on input but of course it's not just powers of 2 so some inputs might not even be representable at all like Pi, but some can be calculated exactly but may need just a big amount of length for the precision. so I wonder how i.e. scientific calculations are done in this situation. (financial ones was a good example but it's not as vast as scientific ones)
@AbelShields
@AbelShields Год назад
@@katiagalkina4607 ahh, there is another approach used by python and other scientific applications. You can use "bigint" types, which dynamically grow in size as the numbers you store grow. You can use these to create rational datatypes (fractions), which should cover almost anything you need. If you have a function that produces an irrational output (such as hyperbolic functions), you can store an "accuracy", keeping track of how accurate the result is as you perform the computation, and you can trade more memory and higher compute time for a more accurate rational approximation.
@AbelShields
@AbelShields Год назад
@@katiagalkina4607 and no, you'd still use a uint64 for the whole balance, but a value of 1 means 1 cent. 100 means a dollar, 256 means 2 dollars 56 cents etc.
@affegpus4195
@affegpus4195 Год назад
Mostly we deal with it by math'ing out how much the error of our calculations have, so we can be sure to how precise our results are. Thats called error propagation. That is something a lot of fields that use math in the real world have to deal with. statistics, engineering, economy, etc. And is just a side effect of the reality and math having infinite precision while our measurements dont. In programming thou it only becomes a issue if doing scientific research, where you either accept some inaccuracy in the numbers in order to be fast. Or do it in a slow way that will assure the amount the precision you need. Or when you doing something very wrong, like accumulating the result of way too many operations in the same floating point number over a long period of time.
@shahzadakhtar1186
@shahzadakhtar1186 Год назад
I've have a question that is completely unrelated but i will ask it anyways Can we overwrite stack with heap allocations?
@taragnor
@taragnor Год назад
Not sure what you mean here. Malloc should never allocate you bad memory. The errors come in you either not allocating enough, or screwing up your pointer arithmetic to make a pointer point to the wrong place. It is possible to overwrite the stack, but it's not your allocation that's doing that.
@shahzadakhtar1186
@shahzadakhtar1186 Год назад
@@taragnor i meant that the stack is in the higher memory address and heap is in lower memory address in virtual memory. Theoretically if we have enough ram can we overwrite stack with heap?
@JacobSorber
@JacobSorber Год назад
Interesting topic for a future video. Thanks. Short answer: On most machines, you can't. The address space is too large. On small microcontrollers with only a few KB of RAM, yes, it's possible. Stack/heap collisions can produce some of the most terrible bugs you've ever tried to track down.
@jimschneider799
@jimschneider799 Год назад
Everybody reading this probably already knows, but ... valgrind would pick this up, whether it segfaults or not.
@Interpause
@Interpause Год назад
so printf isnt functionally pure; it has the side effect of allocating memory.
@JacobSorber
@JacobSorber Год назад
yep, and the side effect of writing to stdout.
@alexwang007
@alexwang007 Год назад
Stupid sprintf breaks my microcontroller program and my cube programmer says there's an access violation every time this happens. Edit: yes I literally thought my code was possessed by demons and this problem has been plaguing my project for the past 4 month, every time I change something else in my program this will resolve itself by random chance and come back to haunt me later...
@nickgennady
@nickgennady Год назад
I know printf is so slow. Running 3 per frame causes my gpa to drop from 120 to 90 lol
@JohnDlugosz
@JohnDlugosz Год назад
Why do you need to dynamically allocate values?????? Just declare it on the stack: struct myvalues values; /* not a pointer! */
@JacobSorber
@JacobSorber Год назад
You don't, in this case. This is just an illustration of how a seemingly-unrelated printf call could cause/uncause a crash.
@starc0w
@starc0w 2 года назад
Hey Jacob, great content! Thank you so much! 🙃 would: struct myvalues* values = malloc(sizeof *values); working instead? Would that be legal code?
@JA-in3hw
@JA-in3hw Год назад
That's the way I always do it. Makes it auto update the malloc if you change the type of the struct. I do sizeof(*values); even though sizeof *values is completely legal. I get confused without the parentheses if there is a * count or something extra after. Works great.
@Marco-yj6gg
@Marco-yj6gg Год назад
struct myvalues* values = malloc(sizeof *values); is valid and legal code. It's the best way of allocating memory IMO, I also prefer to use parentheses like the previous commenter: struct myvalues *values = malloc(sizeof(*values)); Note that you don't cast the return value of malloc in C.
@greg77389
@greg77389 Год назад
Moral of the story: Don't use malloc.
@31Uluberlu
@31Uluberlu 2 года назад
There's another issue in this code: line 35 in the 1st and 2nd iterations, all three members haven't been initialized yet. Not to mention, you don't free() the allocated memory.
@user-mr3mf8lo7y
@user-mr3mf8lo7y 2 года назад
Even though it is a good practice, you don't need to free, as it is being taken care of OS at exit.
@ALTracer
@ALTracer Год назад
@@user-mr3mf8lo7y This works only for helloworlds of a sole main() under an OS. What if I did this in a function in a loop? What if I happen to use a freestanding/unhosted implementation on an MCU without an RTOS (which happens frequently in embedded)? I am dissatisfied with this presentation and lack of valgrind/-fsanitize=address/UBSan, as that would help catch such naive bugs.
@alandecowski5945
@alandecowski5945 Год назад
This is why I've never touched C with a 12 foot pole
@JacobSorber
@JacobSorber Год назад
You need a longer pole, or you will eventually be drawn in by C's beauty and elegance.
@HweolRidda
@HweolRidda Год назад
@@JacobSorber C is like juggling shiney knives. Java is like trying to juggle bricks. You never get cut by java but the result is ugly and slow. Of course, C++ is like juggling silver balls. Beautiful but less impressive than C.
@dogdog5994
@dogdog5994 2 года назад
It would be interesting for you to make a series of videos about how to create GUI applications in C such as Win32 apps. Videos about the event loop, handles, window procedures, etc. in win32 apps. I did see a library for creating cross platform GUI apps in C that is named IUP and the documentation for IUP appears to be really good. There's GTK as well which is clumsy on Windows. You can go from embedded stuff all the way up to GUIs in C. Videos about testing (unit testing and such?) in C would be nice too. Perhaps create a custom library and test it?
@cleightthejw2202
@cleightthejw2202 2 года назад
@Jacob Hey, I have the codeblocks IDE and downloaded the MinGW v10. The thing is that there is no /bin or gcc.exe in it. How does this get remedied? Have you heard of others having this issue? I truly don't understand why that/bin/gcc.exe isn't in the MinGW download
@KeinNiemand
@KeinNiemand Год назад
The solution is to stop using C and use a memory safe language.
@monochromeart7311
@monochromeart7311 2 года назад
It would be great if you didn't use dangerous functions like atoi() (replace with strtol()) and strtok() (replace with strchr() and length calculations). Beginners would end up using them, when better alternatives exist. It's bad enough that many teachers use scanf() to teach, when it's so problematic. Also, another thing, fgets() takes the size of the buffer including a nul-terminator. So if you allocate BUFSIZE+1 characters for a buffer, you should pass BUFSIZE+1 to the 2nd parameter of fgets(). From the man pages: " _char* fgets(char* s, int size, FILE* stream)_ reads in at most _one less_ than *size* characters from *stream* and stores them into the buffer pointed to by *s* ."
@lef1970
@lef1970 2 года назад
What a load - using scanf you have students taking input and doing something that they feel somewhat productive on day 1. Get them up and running and motivated on day 1 - teach them proper ways later after they have some competency. If profs did what you want students wouldn’t be doing anything productive for about a month or more.
@monochromeart7311
@monochromeart7311 2 года назад
@@lef1970 or, even better, provide them with a small header file containing a simple get_int() function, so they wouldn't use the dreaded scanf(). Then the curious can look inside and see the fgets()+strtol() combo, but later on the teacher will explain it as they study C strings. Currently, many students end up doing the following: scanf("%d", buff); scanf("%d"); //failed to get 2nd number because of newline scanf("%s", buff); //get a single word but not entire line? What happened? scanf("^[ ", buff) //solution! Get entire line! But buffer may still overflow But if they avoid learning scanf(), they will use fgets() to take input. fgets() will help teach them about buffers and overflows.
@lef1970
@lef1970 2 года назад
@@monochromeart7311 I think that’s what that cs50 does actually, provides a library with wrapper functions to get the students up and running quickly. Not 100% sure on that as I’ve only seen code snippets from people using that library on stackoverflow. Personally I like a pure approach of standard c, ie: when I was school I was in my second year before I learned that conio.h wasn’t standard c. I don’t see the pitfalls of scanf as terrible, you have to understand streams to be able to visualize the newline being left in the buffer - and it students to read - it’s scan format - when c says format it means format ;) it doesn’t mean it’s going to read to the new line, it says it’s going scan the format you provide. Good for students to learn right away that c does what it says it’s going to do ;)
@monochromeart7311
@monochromeart7311 2 года назад
@@lef1970 I disagree, scanf() is a mess, and is also almost always the wrong tool for the job, especially for reading strings. You use "%s" to get a word, not an arbitrary string, but to get a line you need the ugly "[^ ]" format which still doesn't handle buffer overflow and other issues. It's best to learn not to use scanf() and its family.
@lef1970
@lef1970 2 года назад
@@monochromeart7311 then how else would you get a student to write a chunk of code that asks for their name and says hello name on day 1? With fgets youd confuse more than motivate on day 1.
@raul_ribeiro_bonifacio
@raul_ribeiro_bonifacio Год назад
I would NEVER found out. Lol.
@doc0core
@doc0core Год назад
This is why I don't do C
@dexter9313
@dexter9313 Год назад
Wow, I've never thought about this kind of bug. Good thing I use C++ which shouldn't allow this to happen. (I mean using C++ paradigm, malloc can be called in C++ of course... But who does that ?)
@blockmath_2048
@blockmath_2048 Год назад
i do
@StinkySkunk100
@StinkySkunk100 Год назад
I’d watch your video but you’re not using vim so you must not know what you’re talking about
@tinutom810
@tinutom810 2 года назад
3rd
@satyajeetjena6758
@satyajeetjena6758 2 года назад
You are 123 years old 😳😳
@andrewnorris5415
@andrewnorris5415 2 года назад
😲
@sudonim116
@sudonim116 Год назад
😟😧
@blockmath_2048
@blockmath_2048 Год назад
It doesn't say years he's 123 millenia old
@pajeetsingh
@pajeetsingh 2 года назад
How did it even compile? sizeof expression, is not a legal C syntax. Vscode might be the culprit. Try compiling from shell using gcc.
@monochromeart7311
@monochromeart7311 2 года назад
"sizeof expression" and "sizeof (expression)" are equivalent in trivial cases, it is legal C syntax. sizeof is an operator, not a function. Also, VScode uses whatever compiler you set it to, which is probably Clang if he's on Mac.
@tiagobecerrapaolini3812
@tiagobecerrapaolini3812 2 года назад
_sizeof_ is an operator (not a function or macro), it doesn't necessarily need to have its operand between brackets. It's a matter of taste whether to use brackets, some people prefer to not to so _sizeof_ doesn't get mistaken as a function.
@pajeetsingh
@pajeetsingh 2 года назад
@@monochromeart7311 Yeah. GCC says you have to use parenthesis if your operand is a type name. Both my gcc and clang complained without parenthesis.
@monochromeart7311
@monochromeart7311 2 года назад
@@pajeetsingh it's because of the use of a typename, not a requirement of "sizeof". In the video he uses "sizeof" on a variable, which can be done without parentheses.
@HansBezemer
@HansBezemer 2 года назад
Another brain teaser for you (gcc version 9.4.0 (Ubuntu 9.4.0-1ubuntu1~20.04.1)). Sometimes it does, sometimes it doesn't. I can't reproduce it consistently (e.g. a certain optimization level): $ cat bang.c #include #include int main (void) { long x = LONG_MIN; long y = -1L; x /= y; printf ("%ld ", x); } $ gcc -Wall -o bang bang.c $ ./bang Floating point exception (core dumped) In any case: the answer is always wrong (obviously).
@dolomighty74
@dolomighty74 2 года назад
The wrong result is because -LONG_MIN != LONG_MAX Also -LONG_MIN does not fit into a long
@HansBezemer
@HansBezemer 2 года назад
@@dolomighty74 I know - that's why I stated: "obviously". BTW, it returns LONG_MIN. -LONG_MIN can't be done for the same reason - although that could be calculated under 2 compliment as (~LONG_MIN)+1.
@dolomighty74
@dolomighty74 Год назад
@@HansBezemer yes, i should have added "in case anyone wondering why the result is claimed to be always wrong"
@dolomighty74
@dolomighty74 Год назад
played around a bit (gcc version 11.3.0 (Ubuntu 11.3.0-1ubuntu1~22.04) here) the exception gets triggered by the integer division overflow, in fact commenting the printf doesn't change that, but setting y anything else than -1 fixes it... good to know. but now i seem to recall of something similar happening ages ago with watcom c and fixed-point math code sometime... have to check
@HansBezemer
@HansBezemer Год назад
@@dolomighty74 I know why it's triggered. And yeah - like "DIV by ZERO" if you change the denominator it's fixed. It's baffling though. In some cases the optimizer catches it, but without optimization (possible) it just plainly bombs out.
@BaneDestabapillado
@BaneDestabapillado Год назад
Guys i have a solution, make ur own ft_printf, it would be cool they say. . .
Далее
How to Resize an Array in C/C++? Is there a best way?
12:16
Pulling Back the Curtain on the Heap
21:38
Просмотров 37 тыс.
Только ЕМУ это удалось
01:00
Просмотров 2,5 млн
Always Help the Needy
00:28
Просмотров 7 млн
A const int is not a constant.
9:16
Просмотров 69 тыс.
Be Careful When Using scanf() in C
12:22
Просмотров 129 тыс.
How do I access a single bit?
11:07
Просмотров 22 тыс.
How different are C and C++? Can I still say C/C++?
10:25
The IBM 1401 compiles and runs FORTRAN II
23:41
Просмотров 1,2 млн
The Unreasonable Effectiveness Of Plain Text
14:37
Просмотров 610 тыс.