I've lost the bubble on character arrays. My code generates the non-fatal warning "C++ forbids converting a string constant to 'char*'" for this code:
char* days[] = {
"OFF ",
"All ", // Every day
"Odd ",
"Even ",
"2-Day", // Mon and Thurs
"3-Day" // Mon, Wed, and Fri
} ;
but it works as I intend, eg, I can use the print method to print text out of the array and the text string always prints as the intended 5 characters. Serial.print(days[3]) ;
It's a C++ thing I believe - you could have done that in plain old C, but C++ wants string literals like that to be immutable. They're not, because C, but gcc is warning you that you're doing something potentially unsafe.
When you write something in double quotes you are defining a string literal which content can’t change (the compiler is free to store it in flash for example or regroup it with another string if there is an overlap), and the keyword to say something can’t change is const
If you declare it without const you are entitled to make changes later on - which could lead to unexpected behavior, hence the compiler barking
As you access those only as read only when you print, it’s not an issue for you but better take a good habit and respect the types
Good news for several places in my code, but not here. I wanted to have an addressable/indexed array that I could write to. If I take "const" away, I get the warning, of course. The rows in the array will contain only text, and I want the print() method to know it's a delimited string of text, not values/numbers. For now I can just remove "const" and put up with the warning, but "getting good habits" is not a bad idea.
just as an example of why this could be bad to mess around with the data
char* test[] = {
"X",
"XX",
"XXX",
"XXXX",
"XXXXX",
"XXXXXX",
"XXXXXXXX",
};
void setup() {
Serial.begin(115200); Serial.println();
Serial.println(F("Before messing around with the data"));
for (byte i = 0; i < 7; i++) Serial.println(test[i]);
//!!! this is not legit. modifying one byte that is supposed to be const
test[6][7] = 'Y';
Serial.println(F("After messing around with only one byte the data"));
for (byte i = 0; i < 7; i++) Serial.println(test[i]);
}
void loop() {}
the code prints the array and then just changes the last X of the longest string for an Y test[6][7] = 'Y';
Serial Monitor (@ 115200 bauds) will show
Before messing around with the data
X
XX
XXX
XXXX
XXXXX
XXXXXX
XXXXXXXX
After messing around with only one byte the data Y
XY
XXY
XXXY
XXXXY
XXXXXY
XXXXXXXY
➜ so you can see the compiler had optimised the memory storage and reused the longest string to represent all the others.
if the array had been declared as const char * then the compiler would have refused the modification and told us
error: assignment of read-only location '*(test[6] + 7)'
test[6][7] = 'Y';
^~~
Error during build: exit status 1
so if you want to be able to modify the data and be legit you need to allocate memory and have a 2D array for example: char rows[4][20];
Me, I'd put the constants in flash and only text-manipulate 1 string in 1 buffer at a time unless I had to compare just-made strings but no way to process-then-print-them-all --- serial chars stack up in the print buffer incredibly faster than they transmit at even 115200 baud (11520 chars/sec... serial byte is start bit, 8 data and stop bit).
But me.. only buffers strings when I have to. I work char by char when I can.
I know that the Compiler is free to choose either RAM or register to store variables as a part of optimization. Now, I have learnt that the Compiler may store string in Program Memory/flash Memory even without being requested by the user. The Arduino Reference Manual does use PROGMEM keyword to request the Compiler to store string in flash memory:
That was to make a point in general.. Our compiler doesn’t use flash unless instructed because of the Harvard architecture and thus consequences / change on how you can use the pointer to access the data but in theory could choose to do whatever works without breaking programming rules that the data can be read accessed using the pointer in any way..
In practice on other architectures it generally would put the string literals in a non modifiable data segment that would trigger a fault if trying to get modified. That’s often part of security
The example above shows that even on a UNO the string literals memory hais been shared between the instances and thus it’s really a bad thing to ignore the compiler warning
The 89S52 MCU (belongs to the family of CISC 8051), is not of Harvard Architecture and the architecture still allows to use some of the flash area as data memory.
Now, I remember that I used Keil's C Compiler occasionally as free stuff. The professional one had to be bought and I did not do that as I was so much addicted with ASM Programming that I could do almost everything with assembly ranging from developing ROM-based Monitor Program for 6802, 8085, 80x86, ATmega32A, and 89S52 Trainers to building Taxi Meter, Weighing Scale, and Prepaid Electrical Energy Meter.
I had good time as well with assembly languages (6502/6800,…) but it’s been a long time back. C or C++ are doing the job for me as I don’t have the constraints that would require going to assembly in my personal projects
You seem to ignore the fact that * means it is a pointer. You create array of pointers to static data that should not be changed (and a good compiler won’t let you change it). What you need is to allocate space for your char strings that could be written into, that would be