As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
I know that every string in C ends with '\0' character. It is very useful in cases when we need to know when the string ends. However, I am unable to comprehend its use in printing a string and printing a string without it. I have the following code:-
/* Printing out an array of characters */
#include<stdio.h>
#include<conio.h>
int main()
{
char a[7]={'h','e','l','l','o','!','\0'};
int i;
/* Loop where we do not care about the '\0' */
for(i=0;i<7;i++)
{
printf("%c",a[i]);
}
printf("\n");
/* Part which prints the entire character array as string */
printf("%s",a);
printf("\n");
/* Loop where we care about the '\0' */
for(i=0;i<7&&a[i]!='\0';i++)
{
printf("%c",a[i]);
}
}
The output is:-
hello!
hello!
hello!
I am unable to understand the difference. any explanations?
In this case:
for(i=0;i<7;i++)
{
printf("%c",a[i]);
}
You loop for a number of times (7) and then quit. That is the end condition of the loop. It terminates, no matter anything else.
In the other case, you also loop for 7 times and no more and you just added another condition, which really serves no function as you already keeping a count of things. If you did the following:
int index = 0;
while (a[index] != '\0') { printf("%c", a[index]); index++; }
now you would depend on the zero termination character being there, if it wasn't in the string, you while loop would go on forever until the program crashed or something terminated it forcedly. Probably printing garbage on your screen.
\0 is not part of data in character string. It is indicator of end of string. If length of string is not known, look for this indicator. With its help you can replace your cycle of:
for(i=0;i<7&&a[i]!='\0';i++) { ...
with:
for(int i=0; a[i]; ++i) { ...
So, for-loops and printf are displaying the same string. The only difference how you print it.
'\0' does not correspond to a displayable character; that's why the first and last versions appear to be the same.
The second version is the same because under the hood, printf is just iterating until it hits the '\0'.
The purpose of the terminating zero character is to terminate the string, i.e. to indirectly encode the string length information in the string itself. If you somehow already know the length of your string, you can write code that works correctly without relying on that terminating zero character. That's basically all.
Now, in your code sample the first cycle does something that does not make much sense. It prints 7 characters from a string that actually has length 6. I.e. it attempts to print the terminating zero as well.
When you want to print a string from first character until end. Knowing the length of that string is not necessary when the string ends with \0 (Print characters until \0). So you don't need any extra variable to store the length of string.
In fact a string can have many various representations but minimizing the consumed memory (which it was important to C designers) leads designers to define zero-terminated strings.
Each string representation has its trade off between speed, memory and flexibility. For example you can have your string definition same as Pascal string which stores length of the string at first element of array but it causes that string to have limited length, but retrieving the length of string is faster that zero-terminated strings (Counting each character until \0).
I am unable to comprehend its use in printing a string and printing a string without it
Normally you don't print a string character by character like that. You print the whole string. In such cases, your C library will print until it finds a zero.
When printing a string of variable length, there has to be some 'signal' to indicate that you have reached the end. Generally, this is the '\0' character. Most C standard calls, like strcpy, strcat, printf, etc. depend on the string being zero-terminated, thus ending in a '\0' character. This corresponds to your second example.
The first example is printing a string of fixed length, which is simply a far less common occurence.
The third example combines both, it looks for a zero-terminator ('\0' character) ór 7 characters maximum. This corresponds to calls like strncpy, for example.
The purpose of the terminating zero character is to terminate the string, i.e. to indirectly encode the string length information in the string itself. If you somehow already know the length of your string, you can write code that works correctly without relying on that terminating zero character. That's basically all.
Now, in your code sample the first cycle does something that does not make much sense. It prints 7 characters from a string that actually has length 6. I.e. it attempts to print the terminating zero as well. Why it is doing that - I don't know. In other words, the first output generated by your code is formally different from the rest, since it includes the effect of printing a zero character right after the ! sign. On your platform that effect just happened to be "invisible" on the screen, which is why you probably assumed that the first output is the same as the other ones. However, if you redirect the output to a file, you will be able to see that it is actually quite different.
The other output methods in your code simply output the string up to (and not including) the terminating zero character. The last cycle has redundant condition checking, since you know that the cycle will stop at zero character, before i will have a chance to hit 7.
Other than that, I don't know what "difference" you might be asking about. Please, clarify your question, if this doesn't answer it.
In your loop, you actually print the nul character. Generally this has no effect since it is a non-printing, non-control character. However printf("%s",a); will not output the nul at all - it uses it as a sentinel value. So you loop is not equivalent to %s formatted output.
If you try say:
char a[] = "123456" ;
char b[]={'h','e','l','l','o','!' } ; // No terminator
char c[] = "ABCDEF" ;
printf( "%s", a ) ;
printf( "%s", b ) ;
printf( "%s", c ) ;
You might clearly see why the nul terminator is essential. In my case it output:
123456
hello!╠╠╠╠╠╠╠╠╠╠123456
ABCDEF
Your mileage may vary - the result is undefined behaviour, but in this case the output is running through to the adjacent string, but the compiler has inserted some unused space between them with "junk" in it. I packed a string either side of the un-terminated string because there is no way of telling how a particular compiler orders data in memory. Incidentally when I declared the strings static if the strings, the string b was output with no "run-on". Sometimes the surrounding "junk" may happen to already be zero.
Related
I have a strange problem when using string function in C.
Currently I have a function that sends string to UART port.
When I give to it a string like
char buf[32];
strcpy(buf, "AT+CPMS=\"SM");
strcat(buf, "\"");
uart0_putstr(buf);
//or
uart0_putstr("AT+CPMS=SM"); //not a valid AT command, but without quotes just for test
it works well and sends string to UART. But when I use such call:
char buf[32];
strcpy(buf, "AT+CPMS=\"SM\"");
uart0_putstr(buf);
//or
uart0_putstr("AT+CPMS=\"SM\"");
it doesn't print to UART anything.
Maybe you can explain me what the difference between strings in first and second/third cases?
First the C language part:
String literals: All C string literals include an implicit null byte at the end; the C string literal "123" defines a 4 byte array with the values 49,50,51,0. The null byte is always there even if it is never mentioned and enables strlen, strcat etc. to find the end of the string. The suggestion strcpy(buf, "AT+CPMS=\"SM\"\0"); is nonsensical: The character array produced by "AT+CPMS=\"SM\"\0" now ends in two consecutive zero bytes; strcpy will stop at the first one already. "" is a 1 byte array whose single element has the value 0. There is no need to append another 0 byte.
strcat, strcpy: Both functions always add a null byte at the end of the string. There is no need to add a second one.
Escaping: As you know, a C string literal consists of characters book-ended by double quotes: "abc". This makes it impossible to have simple double quotes as part of the string because that would end the string. We have to "escape" them. The C language uses the backslash to give certain characters a special meaning, or, in this case, suppress the special meaning. The entire combination of backslash and subsequent source code character are transformed into a single character, or byte, in the compiled program. The combination \n is transformed into a single byte with the value 13 (usually interpreted as a newline by output devices), \r is 10 (usually carriage return), and \" is transformed into the byte 34, usually printed as the " glyph. The string Between the arrows is a double quote: ->"<- must be coded as "Between the arrows is a double quote: ->\"<-" in C. The middle double quote doesn't end the string literal because it is "escaped".
Then the UART part: The internet makes me believe that the command you want to send over the UART looks like AT+CPMS="SM", followed by a carriage return. The corresponding C string literal would be "AT+CPMS=\"SM\"\r".
The page I linked also inserts a delay between sending commands. Sending too quickly may cause errors that appear only sometimes.
The things to note are :
The AT command syntax probably demands that SM be surrounded by quotes on both sides.
Additionally, the protocol probably demands that a command end in a carriage return.
This ...
char buf[32];
strcpy(buf, "AT+CPMS=\"SM");
strcat(buf, "\"");
... produces the same contents in buf as this ...
char buf[32];
strcpy(buf, "AT+CPMS=\"SM\"");
... does, up to and including the string terminator at index 12. I fully expect an immediately following call to ...
uart0_putstr(buf);
... to have the same effect in each case unless uart0_putstr() looks at bytes past the terminator or its behavior is sensitive to factors other than its argument.
If it does look past the terminator, however, then that might explain not only a difference between those two, but also a difference with ...
uart0_putstr("AT+CPMS=\"SM\"");
... because in this last case, looking past the string terminator would overrun the bounds of the array, producing undefined behavior.
Thanks all. Finally It was resolved with adding NULL char to the end of string.
This question already has an answer here:
Is printf()'s string width safe with unterminated strings?
(1 answer)
Closed 5 years ago.
I stumbled upon this behavior that I am curious to understand.
I mistakenly wrote the following at the end of a program to print the elements in an array of char :
printf("output: %s",outputText[]);
when I should have (and ultimately did) iterate over the array and printed each element like so:
for(int i = 0; i < textLength; i++){
printf("%c",outputText[i]);
}
What prompted me to implement the latter was the output I was getting. Despite initializing the array to limit the characters to outputText[textLength], ensuring that there were no unexpected elements in the array, my output when implementing the former code would always be littered with additional spooky elements, like below:
I've just run the same program three times in a row and got three random characters appended to the end of my array.
(Edit to replace outputText[] --> outputText in first example.)
%s is for strings; a string is a array of chars ending with NUL (0x00 in hex, or '\0' as character), so the printf() will print until it finds a NUL!
If you set the last element of the array to NUL, printf will finish there.
You are probably missing the '\0' character as the element of the character array that marks the end of the string.
You are missing string terminating character \0 end of the string. So, make your string is \0 terminated. Like:
outputText[textLength-1] = '\0';
When the character array substring[#] is set as [64], the file outputs an additional character. The additional character varies with each compile. Sometimes es?, sometimes esx among others.
If I change the [64] to any other number (at least the ones I've tried: 65, 256,1..) it outputs correctly as es.
Even more strange, if I leave the unused/undeclared character array char newString[64] in this file, it outputs the correct substring es even with the 64.
How does the seemingly arbitrary size of 64 affect the out?
How does a completely unrelated character array (newString) influence how another character array is output?
.
int main () {
char string[64];
char newString[64];
char substring[64];
fgets(string,64,stdin);
strncpy(substring, string+1, 1);
printf("%s\n", substring);
return 0;
}
The problem is, strncpy() will not copy the null terminator because you've asked it not to.
Using strncpy() is safe and dangerous at the same time, because it will not always copy the null terminator, also using it for a single byte is pointless, instead do this
substring[0] = string[1];
substring[1] = '\0';
and it shall work.
You should read the manual page strncpy(3) to understand what I mean correctly, if you read the manual carefully every time you would become a better programmer in a shorter time.
Char arrays have continuously confused me in C.
Here is the following code:
char tcp_port[100], udp_port[6];
tcp_port[99] = '\0'; udp_port[5] = '\0';
fscanf(fp, " tcp_port=%s", tcp_port);
fscanf(fp, " udp_port=%s", udp_port);
printf("%s\n", tcp_port); printf("%s\n", udp_port);
This works and prints out the right number. However, since tcp_port has 100 elements, how do those just disappear when printing? The port is only 5 characters long and the last element is null terminated. Does printf just ignore those unintialized elements, and do those uninitialized elements contain random data?
Yes, printf() only prints the characters up to the first \0 character. All C string functions do this. They also automatically append that \0 character when necessary, like the scanf() function there. That's why it's called a "0-terminated string".
The other elements can contain anything and they will be completely ignored. In practice, they usually contain random junk, but it depends on a variety of factors.
Note that when you allocate memory you must keep that \0 character in mind. Your tcp_port string can only at most 99 characters, because the last one must be 0.
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.