Char and Char* - strings strange behaviour again

Strings with Arduino are a little crazy and I know I’m not and expert programmer.
But I noticed that 70% of programming time I’ve lost is to manage and understand strings and their sometimes impredicable behaviour.
I decided to avoid as much as possible to use “string” command and its flexibility and use
whenever possible only char and char* commands, but again…

Try this simple sketch, I defined 4 strings with char*, in the same way but different content for chararA and chararB,
THEN I changed just 1 character of 1 element of the array,
in the first case it works properly, only that 1 element changed,
in the second case you will find changed the same character but for ALL elements of the array.

Could someone explain me why it happens?
Why char chararB[4][7] always works correctly?
Thank you!

// This won't work for chararB:
char* chararA[]= {"1     ","2     ","3     ","4     "};  
char* chararB[]= {"      ","      ","      ","      "};  

// This always work properly:
// char chararA[4][7];//{"1     ","2     ","3     ","4     "};  
// char chararB[4][7];//{"      ","      ","      ","      "};  


void setup() {
 
Serial.begin(9600);

chararA[2][2] = 'X';

Serial.println("1st sequence");
  for (int i=0 ; i<4 ; i++ )
  { Serial.print("-");
    for (int c=0; c<6; c++)  {Serial.print (chararA[i][c]);}
    Serial.println("-");
  }

Serial.println();
 
chararB[2][2] = 'X';

Serial.println("2nd sequence");
  for (int i=0 ; i<4 ; i++ )
  { Serial.print("-");
    for (int c=0; c<6; c++)  {Serial.print (chararB[i][c]);}
    Serial.println("-");
  }  
}

void loop() {
}

In the "non-working" example, you created an array of pointers to string constants. Since string constants are not modifiable, the compiler was perfectly free to re-use the constants. I would not be surprised if your arrays all point to the same location in memory - a good thing on the arduino.

The other example is what you want if you are creating an array of string buffers. The compiler will allocate writeable store for each sub array.

This also explains it: http://c-faq.com/decl/strlitinit.html

KeithRB: In the "non-working" example, you created an array of pointers to string constants. Since string constants are not modifiable, the compiler was perfectly free to re-use the constants. I would not be surprised if your arrays all point to the same location in memory - a good thing on the arduino.

The other example is what you want if you are creating an array of string buffers. The compiler will allocate writeable store for each sub array.

Thank you KeithRB for letting me improve my understanding. :-) This explains why of this strange behaviour, so: Arduino compiler automatically "optimizes" constants of same value to save memory, and if I try to change one obviously the changes is reflected to all of them. Anyway in my opinion the compiler should advise that I changed a constant or even stop with an error... :-/

QUESTION: - WHEN does the compiler consider my declaration as "contants" ? I didn't use the "const" identifier...

"This is a string constant" We aren't talking about variables here but initialization strings.

You told the compiler to create an array of pointers to strings, which it did. You told it to make that string point to a certain value, which it did. You did not tell the compiler to set aside any general storage for a string.

char array[] = "This is a string constant";

creates an array of contiguous bytes. The 'T' will be at the location &array, or array[0]. The compiler will count the characters in the initializer and set aside enough storage for the characters in the string and the trailing '\0'.

char *array[] = {"string1", "string2"}

creates an array of pointers only enough storage will be set aside to store the pointers. array[0] points to the pointer which points to the 's'. The initialized strings can be anywhere, even flash if the compiler was that smart, since string constants can be in ROM.

Just one more point, these are constants in the sense of:

x = 10;

where '10' is an integer constant. You wouldn't expect to be able to change that, right?