I have tried to read all this, honestly. But I may have missed something. So if this information is all old to you Ludo, please ignore it
But I really did read the posts!
The reason you have to zero terminate strings has actually nothing to do with the string object itself. A string containing "ludo" obviously contains ludo just fine and there it is stored in memory. The problem lays with dbText() and other outputting routines which need to read that variable.
Pointers, as we know, are just memory addresses of locations in the RAM. When you have a char *myVar containing "ludo" and you pass it to a function like dbText() your pointer tells the function where to begin reading. It then continues to read single characters until it hits a null terminator (which you assign using the escape sequence \0 - ie, myVar = "myString\0"). If the null terminator is not present it continues reading from the RAM until it hits a byte of memory that just happens to contain a value equal to \0.
If you're lucky then your program will crash. If you are unlucky then your program will tinker on like normal treating some bad block of memory as if it was legit and anything could happen - bad news because its real hard to debug when your program doesnt think there is anything wrong! You could end up overwriting other variables (that may not even belong to your program) or reading it strange values.
So its especially important when you are dealing with memory directly and convering it into displayable text (or just passing it to a text display function) that you ensure the string is null terminated at the point it should be - you cannot assume it just will be.
Now let me quickly deal with your comment on arrays and pointers. They are, in many ways, exactally the same thing. The index of an array provides a memory offset to a pointer. Imagine:
int myInt[5];
The variable myInt is now, for all intents and purposes, a pointer. Using in your code myInt[0] passes the value at the exact address of that pointer. However, if you used say myInt[2] then what its actually doing is:
location of myInt + (sizeof(int) * index) bytes;
So, as an int is 4 bytes then myInt[2] is location of myInt offset by 8 bytes. Its just pointer maths done on your behalf! This is why you must be so careful with array sizes and error checking the index value of arrays. If you try and index an array past its actual size then, if your lucky, again you get the crash. If you're unlucky then it pulls a random value out of the ram at a location of the intended variables start point + index * sizeof(type) and you could get /anything/
and finally, for those very reasons you can never assume that something that works once will work again if its not written correctly. I can see why you would draw that conclusion, but its a flawed logic. It only works if you assume that the only factors are those provided by your program. But unfortunately its not just your program running - windows is running all the while too as well as any number of other programs and services running along side your program which each could be doing different things at different times - which in turn could change depending on machine and again change after a simple reboot!
If you read the wrong peice of memory you might get the value "5" today which happens to not crash your program. But tomorrow your user may have left a new program running which uses that address in ram to store "24" and your program will die.
Bottom line - take extra special care when dealing with memory! and ALWAYS zero terminate strings that you have created manually!
Hope that helps in some way