Null Terminated String Safety Issues | C Programming Tutorial
Вставка
- Опубліковано 22 сер 2024
- An introduction to why null terminated strings are considered unsafe in C, including some common errors and solutions. Source code: github.com/por.... Check out www.portfolioc... to build a portfolio that will impress employers!
Great video! That's one of the beauties of using a small and efficient language like C. When you choose to use C, you take responsibility for your own decisions, and there's no "nanny" to take care of you. Yes, it can be frustrating to hunt down errors that can take hours to eliminate, but there are also moments of great satisfaction when everything seems to work perfectly.
For learning purposes, I have created my own string library, and although it doesn't always perform operations without errors, I consider it as part of the learning process.
I often use calloc, so strings are automatically terminated.
In the end, I find that the code always does exactly what I programmed it to do, not necessarily what I intended it to do. It's all part of the learning journey.
Honestly as a hobbyist. I have to say that the moment pointers and memory started to click...was when i was struggling with working with strings. Coming from python a string was an object on it's own, while in C a string is just an array....and underneath it all it's even just an uint array. Making something akin to a simple string library was a great teacher for how the core of C works....memory, arrays, memory addresses, the heap, the stack....heck even scope.
@@NikolaNevenov86 Totally agreed. I'm using CodeBlocks and the debugger really tells me, what going on, when I'm not sure whats going on. Especially the single step feature, where I can follow the values and memory dump.
@@grimvian yeah debuggers help a lot with this. However when i started with C, I was using VScode and the C setup was a total pain for me, and it never worked. In the end I ended up using neovim but I never managed to get it's debugger working as well. So I was basically in the dark. Until someone recommended to me remedyBG. Only then I started noticing why were my strings messing things up.
But until then it was 2-3 weeks of trying this and that, reading, asking....
So a good debugging service saves a lot of headaches.
@@NikolaNevenov86 remedyBG looks much more advanced that Codeblocks, but until now I'm satisfied although I'm always curious about other debuggers or anything else that helps a hobby coder like me. I think I'm at a intermediate level.
Graphics is a tremendous help for me, maybe because I’m a kind of dyslectic non academic person. I started and did a lot with graphics.h with C++ and now I’ using Raylib and it’s great.
Inspired by the video I made this a bit more complicated code and I think it’s might be ok...
#include
#include
void print(char *);
void print(char *str) {
int max = 5;
char *ptr = calloc(max, sizeof(char));
char *tmp = ptr;
int i = 0;
while (*str != '\0' && i++ < max)
*tmp++ = *str++;
printf(">%s
The basic behavior of strings in C , being arrays that are null terminated , got me pulling my hair(as a beginner) for weeks. Until I found that I wasn't adding the null terminator. So the string buffers were either incorrect in some cases, but in others doing a simple writing to them went off and overwrote other structs(memory regions) that weren't part of the array, simply because there was no null at the end of these. So the first 6min of the video brought back bad memory of days of frustration.
Null terminated strings are one of those features that 'modern languages' gave up for a reason. :-)
as an embedded designer, I can't emphasize how critical it is to master the application and structures of strings and character (char) manipulation. In serial communication applications, such as asyncronous data transfer (no clock pulses are used) in Bluetooth, WiFi and ATM machines; characters are transmitted one at a time and received one at a time. When the end of string is reached and you fail to concatinate the NULL character at the end then your system will be screwed up. Very important video for all serious programmers, like you and me. Thank you Kevin.
Would be interesting, if have a small example code, how you ensure termination do as expected...
@@grimvian static bool radio.filter(void)
{
static bool lockSync = false;
uint8_t readChar = radio.IN();
if(lockSync == true)
{
if(readChar == '$')
{
lockSync = false;
*pHeader = '\0';
radio.locked(radioMessage);
}
else if (pHeader < radioMessage + 40)
{
*pHeader++ = readChar;
}
}
else
{
if (readChar == '$')
{
lockSync = true;
pHeader = radioMessage;
}
else
{
dataIsReady = true;
peek = readChar;
}
}
return dataIsReady;
}
@@grimvian look in this section if(readChar == '$')
{
lockSync = false;
*pHeader = '\0';
@@grimvian if you dont include '\0' the radio goes unstable.
@@grimvian The function radio.locked(radioMessage); takes the received radio messgae and acts on it, if the remote function doesnt see the NULL at the end then it produces similar error as Kevin produced. This is because in that function I am also using String Operations to take different actions based on the string received from the mobile device.
@18:48 Even if the memory today is very cheap, I wouldnt take the risk and "not" limit the use of memory as per project requirements. This is very risky: ATM machine TranCeive (transmit-Receive) data from user interface to data base, if the user aske the ATM machine to withdraw $100 and the 'NULL" got lost because of thunderstorm electromagnetic interferrence or error in data exchange then the machine will accidently dispose $1000 (of say $1005) instead of $100 and register it as $100 only. Those mistakes get very serious in areas of medical, military, financial and other critical applications.
Thank you for sharing this! :-)
It is a bit the same, isn't it? What protects against passing the wrong number of charactes?
That's a good point, I agree to an extent, it's not like passing a bound/limit/max argument somehow eliminates the possibility of an error. It alters the way in which an error can occur. That said, I suspect it is much less error prone than relying on the null terminator alone. Something like a preprocessor constant can define a buffer size once, and then the preprocessor constant can be used everywhere it's needed consistently, for example.
I remember pascal storing the size of the string in index 0. But pascal string where limited to 255chars....
@6:32 Can we cast those valuse as characters (char) so we get an error because a decimal was used, instead of character? Getting an error is to our advantage, or else the code will take it as NULL if decimal is used. Casting as character will caution us that there is something wrong going on and it needs our attention.
But when declaring a char array like char array[] = "Hello"; does it add a \0 automatically?
Yes :-)
I'm using gcc in Ubuntu and I can strcpy an char source[100] int a char coda[8] and do not get even a warning (I am using -Wall and -g in the compilation)! I understand it is likely written into memory it should not but.
7:21 - This shouldn't compile in proper C. You declare a variable after calling printf().
There are different standards of C, the language has been revised over the decades. Very old standards of C like C89 required variable declarations at the top of the scope/function. Newer variations such as C99 do not require this, you can declare variables elsewhere and it is considered "proper C". The source code for some applications is still written to conform to the C89 standard, but much of the C world no longer expects this.