About the problem with losing the last character:
As already said in the comments, the toCharArray()
method is only an alias for the getBytes()
method of string objects. We can see it's implementation in the IDEs folder under hardware/arduino/avr/cores/arduino/WString.cpp
:
void String::getBytes(unsigned char *buf, unsigned int bufsize, unsigned int index) const
{
if (!bufsize || !buf) return;
if (index >= len) {
buf[0] = 0;
return;
}
unsigned int n = bufsize - 1;
if (n > len - index) n = len - index;
strncpy((char *)buf, buffer + index, n);
buf[n] = 0;
}
We give the length as parameter, which is then reduced by 1. The function strncpy()
, that is used here, will only copy n = bufsize - 1
bytes. In the end, the n
th byte will be set to 0
as the terminating null character.
This means, that the length, that we give as parameter, already includes the space for the null character. But the method String::length()
will not include the null character in length calculation (in most cases this is not wanted). So you can simply add 1 to the length before giving it to toCharArray()
.
About the overwriting problem:
As stated in this question's answer and in several other discussions about C/C++ (for example here), string literals are meant to be immutable. The mentioned sources say, it is different, if you define a string variable as
char *str = "test";
or
char str[] = "test";
In the second case a normal mutable array is created. In the first case the string will be placed in read only memory. From your problem I read, that on Arduino this is placed in RAM, thus technically mutable. But the compiler thinks of it as immutable. A common optimization, when dealing with immutable strings, is to let every used string literal with the same content be saved at the same memory address.
In your code you are initializing 2 strings with only the terminating null character in them. The compiler thinks "Oh, wait, these two string literals are immutable and equal, so I can save memory by only saving it once and let both pointers point to this memory address". When writing to the strings in Arduino the behavior doesn't seem to be defined. As the Arduino cannot throw an exception it will most likely do the write. Since both pointers are pointing to the same memory address, they show both the same content. Also, when writing a string longer than the initialized value, memory space outside from the original string will be written. If other variables are saved there, they will get overwritten. This is the reason, by you should always explicitely allocate the memory (static or dynamic) for a string, until another function does it for you. When using a dynamic allocation of memory, you should also consider heap fragmentation, which can easily lead to strange behavior.
If you turn on verbose output for compilation, the compiler also warns you, that you try to convert a constant string literal to a non-constant char pointer:
sketch_jul09a.ino:3:15: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
To conclude, you should not declare string variables like this. If you have a variable string buffer with initialized values, you should use
char str[]="test";
If you want to define a constant string, use the keyword const
:
const char *str = "test";
Then writing to it will result in a compiler error, so that you sense, if you are doing this.
txt.toCharArray(ss1, txt.length());
.... think about itlength()
and that doinglength() + 1
works. ifstring = 'abc'
, thenstring.length ()
should be 3, isn't it? But I insist: So is this an IDE problem? About the second problem, the pointers, why are they overwriting the contents?