[try Beta version]
Not logged in

 
array of char without '\0' terminated

May 4, 2019 at 11:11am
Hello,

from previously asking on here I've understood that the << operator has been overloaded for C-strings (char arrays that are 0 terminated), to print it as a std::string. But what happens if you do not allocate the 0?

1
2
3
4
5
6
char arr3[4] = { 'b', 'a', 'd' };
cout << arr3; //prints bad, as expected.

char arr3[3] = { 'b', 'a', 'd' };
    
    cout << arr3; //weird output 
May 4, 2019 at 11:48am
Well if there is no room for a \0, then you don't have a \0, and therefore you see "bad" plus whatever is in memory until
- a \0 is found
- you run out of memory and the OS kills the program with a segfault.
May 4, 2019 at 12:20pm
this program runs fine even without null termination
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <cstring>
using namespace std; 

int main(){
	char ar[10] = {'a','b','c'}; // ar[3] runs fine also
	cout << sizeof(ar) << endl;
	for(auto x:ar) cout<< x;
	cout << endl;
	cout<< strlen(ar) << endl;
return 0; 
} 
May 4, 2019 at 12:34pm
> this program runs fine even without null termination
> char ar[10] = {'a','b','c'};
Except it does have \0
Seven of them to be precise.

As soon as you have at least ONE initialiser in an array, all the remainder elements you don't specify are filled with 0,0.0,'\0',nullptr (depending on the type).
May 4, 2019 at 1:02pm
what about this one
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>
#include <cstring>
using namespace std; 

int main(){
	char ar[3] = {'a','b','c'};
	cout << sizeof(ar) << endl;
	for(auto x:ar) cout<< x;
	cout << endl;
	cout<< strlen(ar) << endl;
return 0; 
} 
May 4, 2019 at 1:40pm
> what about this one
That will blow up as soon as you try to do strlen().
May 4, 2019 at 2:46pm
Unfortunately, it probably won't. Quite often these errors are silent and appear to be working fine until they don't and then debugging it becomes a huge ordeal.

one thing that can happen, is say you had this:
int y = 42;
char oops[3];
int x = 10;
sprintf(oops, "oh noes"); //it has a terminal zero, but its out of bounds.
cout << x << oops << y; //good chance x is damaged, as the sprintf overflow would run the bytes into the integer, silently changing its value. Or it could crash. Crashing here is great, you can go fix it. Silently changing x's value will drive you nuts trying to find the problem in a big program. It may also change y's value, on some systems, depending on which way the stack goes on your compiler. And changing x's value can damage the string too. Its a mess when it 'works fine'. To test these things compile in release not debug settings or the padding between variables for debugging hides this issue.

Last edited on May 4, 2019 at 2:49pm
May 4, 2019 at 5:11pm
i wonder how strlen() is working there without null termination
May 4, 2019 at 6:53pm
That's the thing about undefined behavior; it's undefined. Your program could crash for going out of bounds, or work just fine. Or order you a pizza. Avoid it!
May 4, 2019 at 7:13pm
ya, surely i will use '\0' if i use c strings, although i prefer std string. i made the program to show that what op wrote "weird output " is actually working, it worked on gcc, clang and visual studio compiler.(i'm not telling to program that way). so how op get that weird output?
maybe for declaring arr3 twice.
May 4, 2019 at 8:16pm
Well that's the whole thing about undefined behaviour.

Sometimes you can make the most horrendous screw-ups and the thing will still do exactly what you expect, and you declare success.

Other times, the tiniest infraction of the rules gets you your ass handed to you on a plate.

Testing on multiple compilers helps to flush out false assumptions, but as you've seen, it's no a fool-proof way of finding problems.

A particular issue with this test might be that it's only 3 characters long, which is just short enough to fit inside a machine word - and you're going to get a free \0 in the right place completely by accident. With a longer string, different compilers might do different things.

Ultimately, the only way to proceed is to know what the language is supposed to do, as specified by the ISO committee in the various language standards.

Trying to reverse engineer the language spec from observing the corner cases of what a compiler does (or doesn't) is not the way to go.


May 4, 2019 at 10:33pm
@salem c, you are getting me wrong. we must definitely try to program the standard way.
the intention of my above code is to show that i didn't see the "weird output" as kyrresc, that's all. you must keep 1 space for '\0' no doubt about that.
Topic archived. No new replies allowed.