When do i have to add a null terminator? - c

I know that i C , you always have to add a null terminator \0 so that the processor knows when a word was ended .
But i get hard time to understand when you have to do it . so for example this code works for me without it :
char connectcmd[50]={0};
sprintf(connectcmd,"AT+CWJAP=\"%s\",\"%s\"",MYSSID,MYPASS);
How is that possible ?
When do you really have to add them ?

sprintf always terminates it with null character , so no need to mannually add it.
From C99 standard -
7.21.6.6 The sprintf function
[...]A null character is written at the end of the characters written; it is not counted as part of the returned value. If copying takes place between objects that overlap, the behavior is undefined.

sprintf writes a null terminated string connectcmd, regardless of its initial contents. This works as long as you don't try to write beyond the bounds of the buffer.
On top of that, when you say this:
char connectcmd[50]={0};
you initialize all 50 elements of connectcmd to zero, which is the value of the null-terminator \0. So it would be null-terminated even if you wrote characters to it manually, as long as you write less than 50 non-null characters.

for example this code works for me without it
It does not (work without it).
The string literal "AT+CWJAP=\"%s\",\"%s\"" has a null terminator at the end (like every string literal). sprintf copies that null terminator to connectcmd as well.
When do you really have to add them ?
When you're manually building a string, or using a library function whose documentation explicitly states that it isn't going to add a terminating null.

Related

Properties of strcpy()

I have a global definition as following:
#define globalstring "example1"
typedef struct
{
char key[100];
char trail[10][100];
bson_value_t value;
} ObjectInfo;
typedef struct
{
ObjectInfo CurrentOrderInfoSet[5];
} DataPackage;
DataPackage GlobalDataPackage[10];
And I would like to use the strcpy() function in some of my functions as following:
strcpy(GlobalDataPackage[2].CurrentOrderInfoSet[0].key, "example2");
char string[100] = "example3";
strcpy(GlobalDataPackage[2].CurrentOrderInfoSet[0].key, string);
strcpy(GlobalDataPackage[2].CurrentOrderInfoSet[0].key, globalstring);
First question: Are the global defined strings all initiated with 100 times '\0'?
Second qestion: I am a bit confused as to how exactly strcpy() works. Does it only overwrite the characters necessary to place the source string into the destination string plus a \0 at the end and leave the rest as it is or does it fully delete any content of the destination string prior to that?
Third question: All my strings are fixed length of 100. If I use the 3 examples of strcpy() above, with my strings not exceeding 99 characters, does strcpy() properly overwrite the destination string and NULL terminate it? Meaning do I run into problems when using functions like strlen(), printf() later?
Fourth question: What happens when I strcpy() empty strings?
I plan to overwrite these strings in loops various times and would like to know if it would be safer to use memset() to fully "empty" the strings prior to strcpy() on every iteration.
Thx.
Are the global defined strings all initiated with 100 times '\0'?
Yes. Global char arrays will be initilizated to all zeros.
I am a bit confused as to how exactly strcpy() works. Does it only overwrite the characters necessary to place the source string into the destination string plus a \0 at the end and leave the rest as it
Exactly. It copies the characters up until and including '\0' and does not care about the rest.
If I use ... my strings not exceeding 99 characters, does strcpy() properly overwrite the destination string and NULL terminate it?
Yes, but NULL is a pointer, it's terminated with zero byte, sometimes called NUL. You might want to see What is the difference between NUL and NULL? .
Meaning do I run into problems when using functions like strlen(), printf() later?
Not if your string lengths are less than or equal to 99.
What happens when I strcpy() empty strings?
It just copies one zero byte.
would like to know if it would be safer to use memset() to fully "empty" the strings prior to strcpy() on every iteration.
Safety is a broad concept. As far as safety as in if the program will execute properly, there is no point in caring about anything after zero byte, so just strcpy it.
But you should check if your strings are less than 99 characters and handle what to do it they are longer. You might be interested in strnlen, but the interface is confusing - I recommend to use memcpy + explicitly manually set zero byte.

A little query, String in C

Recently I was programming in my Code Blocks and I did a little program only for hobby in C.
char littleString[1];
fflush( stdin );
scanf( "%s", littleString );
printf( "\n%s", littleString);
If I created a string of one character, why does the CodeBlocks allow me to save 13 characters?
C have no bounds-checking, writing out of bounds of arrays or dynamically allocated memory can't be checked by the compiler. Instead it will lead to undefined behavior.
To prevent buffer overflow with scanf you can tell it to only read a specific number of characters, and nothing more. So to tell it to read only one character you use the format "%1s".
As a small side-note: Remember that strings in C have an extra character in them, the terminator (character '\0'). So if you have a string that should contain one character, the size actually needs to be two characters.
LittleString is not a string. It is a char array of length one. In order for a char array to be a string, it must be null terminated with an \0. You are writing past the memory you have allotted for littleString. This is undefined behavior.Scanf just reads user input from the console and assigns it to the variable specified, in this case littleString. If you would like to control the length of user input which is assigned to the variable, I would suggest using scanf_s. Please note that scanf_s is not a C99 standard
Many functions in C is implemented without any checks for correctness of use. In other words, it is the callers responsibility that the arguments fulfill some rules set by the function.
Example: For strcpy the Linux man page says
The strcpy() function copies the string pointed to by src,
including the terminating null byte ('\0'), to the buffer
pointed to by dest. The strings may not overlap, and the
destination string dest must be large enough to receive the copy.
If you as a caller break that contract by passing a too small buffer, you'll have undefined behavior and anything can happen.
The program may crash or even do exactly what you expected in 99 out of 100 times and do something strange in 1 out of 100 times.

Is this a valid way to add two strings together in c?

I have a function taking two strings string_one and string_two both a pointer to a character.
I thought of a way to add them together:
while (*string_one){
string_one++;
}
*string_one = *string_two;
but I can't see the second string in the output!
How do I add two strings toghether? did I go any close?
When you write
*string_one = *string_two;
you are just copying one character since you are de-referencing a char pointer
to add two strings to one another you need to overwrite the \0 on the first string and then append the characters from the second string (provided you have space enough to do so).
so this
while (*string_one) {
string_one++;
}
*string_one = *string_two;
will only overwrite the \0 with the first character from string_two which will result in the first string will not be null terminated any longer.
instead you should so do something similar again like
while (*string_one) {
string_one++;
}
while (*string_two) {
*string_one++ = *string_two++;
}
*string_one = '\0';
again with the premise that string_one originally pointed to a character string large enough to hold both strings.
Did you try your code at all?
First, you need to make sure that there is enough space for both strings. Concatenating strings and not checking that there is enough space for both is probably the cause of 50% of all hacked computers in the world.
Second, a C string is an array of char with a zero byte as the last char. Your code overwrites the zero byte at the end of string_one with the first char of string_two.
Third, there is a function named strcat in the standard C library doing exactly what you want to do. It doesn't check whether there is enough space, you have to do that before the call.
I'm afraid, your code is not valid.
*string_one = *string_two;
will copy the first element of string_two to string_one. This never adds anything. Moreover, you need to append the complete string, not only one element.
What you need is strcat(). You can find more on that here.
The general description :
The strcat() function appends the src string to the dest string, overwriting the terminating null byte (\0) at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable.

ANSI C strncpy messing up screen output and other variables' values

Using ANSI C, screen is messing up after the strncpy. Also if I try to print any int variable values become incorrect. However if I move the print line before strncpy everything is fine.
Does anybody know why?
#define TICKET_NAME_LEN 40
struct stock_data
{
char ticket_name[TICKET_NAME_LEN+1];
};
struct stock_data user_input;
char tname[TICKET_NAME_LEN+1] = "testing it";
strncpy(user_input.ticket_name, tname, TICKET_NAME_LEN);
The symptoms you are describing are the classic ones for a copy that is out of control. However, the real source of your problem is almost certainly not in the code you show.
The only possible issue with the code you show is that strncpy() does not guarantee that the output (target) string is null terminated. This won't hurt with the code shown (it doesn't do anything untoward), but other code that expects the string to be null terminated that blithely copies it without ensuring that there's space may go trampling other memory because the string is not null terminated.
If the input (source) string is longer than the space specified (in this case more than TICKET_NAME_LEN bytes long), then user_input.ticket_name will not be null terminated except by accident. If it is shorter, then user_input.ticket_name will be null padded to the length TICKET_NAME_LEN bytes.
If this is the problem, a very simple fix is to add the line:
user_input.ticket_name[TICKET_NAME_LEN] = '\0';
after (or even before, but it is more conventional to do it after) the strncpy().
However, to run into this problem, you'd have to be trying to copy a name of 41 or more characters into the ticket name member of the structure.
It is much more likely that something else is the cause of your trouble.
ISO/IEC 9899:2011 §7.24.2.4 The strncpy function
¶2 The strncpy function copies not more than n characters (characters that follow a null
character are not copied) from the array pointed to by s2 to the array pointed to by
s1.308) If copying takes place between objects that overlap, the behavior is undefined.
¶3 If the array pointed to by s2 is a string that is shorter than n characters, null characters
are appended to the copy in the array pointed to by s1, until n characters in all have been
written.
308) Thus, if there is no null character in the first n characters of the array pointed to by s2, the result will not be null-terminated.

Strings without a '\0' char?

If by mistake,I define a char array with no \0 as its last character, what happens then?
I'm asking this because I noticed that if I try to iterate through the array with while(cnt!='\0'), where cnt is an int variable used as an index to the array, and simultaneously print the cnt values to monitor what's happening the iteration stops at the last character +2.The extra characters are of course random but I can't get it why it has to stop after 2.Does the compiler automatically inserts a \0 character? Links to relevant documentation would be appreciated.
To make it clear I give an example. Let's say that the array str contains the word doh(with no '\0'). Printing the cnt variable at every loop would give me this:
doh+
or doh^
and so on.
EDIT (undefined behaviour)
Accessing array elements outside of the array boundaries is undefined behaviour.
Calling string functions with anything other than a C string is undefined behaviour.
Don't do it!
A C string is a sequence of bytes terminated by and including a '\0' (NUL terminator). All the bytes must belong to the same object.
Anyway, what you see is a coincidence!
But it might happen like this
,------------------ garbage
| ,---------------- str[cnt] (when cnt == 4, no bounds-checking)
memory ----> [...|d|o|h|*|0|0|0|4|...]
| | \_____/ -------- cnt (big-endian, properly 4-byte aligned)
\___/ ------------------ str
If you define a char array without the terminating \0 (called a "null terminator"), then your string, well, won't have that terminator. You would do that like so:
char strings[] = {'h', 'e', 'l', 'l', 'o'};
The compiler never automatically inserts a null terminator in this case. The fact that your code stops after "+2" is a coincidence; it could just as easily stopped at +50 or anywhere else, depending on whether there happened to be \0 character in the memory following your string.
If you define a string as:
char strings[] = "hello";
Then that will indeed be null-terminated. When you use quotation marks like that in C, then even though you can't physically see it in the text editor, there is a null terminator at the end of the string.
There are some C string-related functions that will automatically append a null-terminator. This isn't something the compiler does, but part of the function's specification itself. For example, strncat(), which concatenates one string to another, will add the null terminator at the end.
However, if one of the strings you use doesn't already have that terminator, then that function will not know where the string ends and you'll end up with garbage values (or a segmentation fault.)
In C language the term string refers to a zero-terminated array of characters. So, pedantically speaking there's no such thing as "strings without a '\0' char". If it is not zero-terminated, it is not a string.
Now, there's nothing wrong with having a mere array of characters without any zeros in it, as long as you understand that it is not a string. If you ever attempt to work with such character array as if it is a string, the behavior of your program is undefined. Anything can happen. It might appear to "work" for some magical reasons. Or it might crash all the time. It doesn't really matter what such a program will actually do, since if the behavior is undefined, the program is useless.
This would happen if, by coincidence, the byte at *(str + 5) is 0 (as a number, not ASCII)
As far as most string-handling functions are concerned, strings always stop at a '\0' character. If you miss this null-terminator somewhere, one of three things will usually happen:
Your program will continue reading past the end of the string until it finds a '\0' that just happened to be there. There are several ways for such a character to be there, but none of them is usually predictable beforehand: it could be part of another variable, part of the executable code or even part of a larger string that was previously stored in the same buffer. Of course by the time that happens, the program may have processed a significant amount of garbage. If you see lots of garbage produced by a printf(), an unterminated string is a common cause.
Your program will continue reading past the end of the string until it tries to read an address outside its address space, causing a memory error (e.g. the dreaded "Segmentation fault" in Linux systems).
Your program will run out of space when copying over the string and will, again, cause a memory error.
And, no, the C compiler will not normally do anything but what you specify in your program - for example it won't terminate a string on its own. This is what makes C so powerful and also so hard to code for.
I bet that an int is defined just after your string and that this int takes only small values such that at least one byte is 0.

Resources