How to handle arrays of char arrays

As will be obvious from my question -- I'm pretty new to this! Please excuse any ignorance.

I can't understand how to pull this off from within a function I'm writing. Here is my goal:

  1. Create a static array (of length X) of char arrays (all of equal length Y). It should be static because I'll be accessing it from outside the function. The array will look like something like: items = {"abc123", "def456", "ghi789"}
  2. Then I'd like to make changes to the array (according to a number of conditions that aren't important now) in the following manner: items[0][2] = "z";. This would change "abc123" to "abz123".
  3. Finally, the function this is all happening in will return a pointer to the array items so that it can be referenced from the main loop.

Here are the problems I'm facing for each point:
(1) I'm not sure how to properly initialize the array of char arrays. Currently I'm doing:

// Create array
static char items[X];

// Initialize array values by filling with char arrays of equal length
for (int i=0; i<X; i++) {
    items[i] = "000000";
    }

But I'm seeing warning: invalid conversion from 'const char*' to 'char'. What am I doing wrong here?


(2) When I try to change the contents of the char arrays within items I see the following error: error: invalid types 'char[int]' for array subscript. I'm coming from Python so my instinct is that items[i][j] should let me access individual characters within the sub-arrays of items, but apparently this isn't how it's done in C++.


(3) Actually not having issues with this yet. I'm doing the following and it seems to be working:

char *handle_items() {
// Create items array and do a bunch of stuff to it
return items;
}

If anyone has insight as to points 1 & 2 I'd love to hear! Thanks in advance.

strcpy

I can't see your code for point 2

I can't see your code for point 2

items[0][2] = "z"

Fixed

you want 2 dimensional array, start googling how to

"static" means only accessible within a function or ile. i believe you mean "global"

code below produces

abc123
def456
ghi789

abz123
def456
ghi789
char * items [] = {
    (char*) "abc123",
    (char*) "def456",
    (char*) "ghi789"
};
#define N_ITEMS     (sizeof(items)/sizeof(char *))

void
disp ()
{
    for (unsigned n = 0; n < N_ITEMS; n++)
        Serial.println (items [n]);
    Serial.println ();
}

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

    disp ();

    items [0][2] = 'z';
    disp ();
}

void
loop (void)
{
}

A two-dimensional char array will use less memory, because it does not produce the separate array of char pointers.

char items[][7] = {
  "abc123",
  "def456",
  "ghi789"
};

Casting a text constant to char* avoids the compiler warning/error messages, but not the effects of later altering the text. If you ever use an identical text constant in the code you will get some unexpected results:

char * items [] = {
    (char*) "abc123",
    (char*) "def456",
    (char*) "ghi789"
};
#define N_ITEMS     (sizeof(items)/sizeof(char *))

void
disp ()
{
    for (unsigned n = 0; n < N_ITEMS; n++)
        Serial.println (items [n]);
    Serial.println ();
}

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

    disp ();
    Serial.print("text constant: ");
    Serial.println("abc123");

    items [0][2] = 'z';
    disp ();
    Serial.print("text constant: ");
    Serial.println("abc123");
}
abc123
def456
ghi789

text constant: abc123
abz123
def456
ghi789

text constant: abz123
1 Like

thanks for pointing that out

You can’t be serious

Why not ?
It sets the second character of string zero to 'z' as the subsequent call to disp() shows

Because there is a reason when you do this

char *str = "12345";

You get warning, so you won’t do something stupid like this

Actually, as has been pointed out, you don't get a warning because of the cast to a char , but I have always found it amusing that without the case the the compiler tells you that

ISO C++ forbids converting a string constant to 'char*

which in my mind makes it an error

This is why C++ is so great it doesn’t stop users from hanging themselves if they wish to do so

i can initialize a variable to a constant, why shouldn't i "need" to initialize a string variable to a constant?

it allows more knowledgeable developers to fully utilize the capabilities of the machine.

some do need that protection. Kernighan said C doesn't have the "guard rails" that C++ has that very large applications need.

Feel free to declare a constant string, using a pointer or not, but that is not what is happening here

Here is my understanding of the problem

When you declare a pointer to a string then the pointer has to be stored somewhere as does the actual string. Now suppose that you make a change to that string such that it may get longer, then how can the longer string be stored in the same place as the original one ?

This I believe is the cause of the warning that is given if you try to change the contents of the string. Other members with more knowledge than me may know better and can comment, but I am still bemused by something that is forbidden is allowed

as you said, it make sense to warn/prevent operations that change the length of a constant char string; what if you make it longer

i often get this warning when i define a function that takes a const char * argument which doesn't modify that string (e.g. print()). but that function may be called with both const or non-const argument.

so it seems the compiler just wants the developer to explicitly indicate what the compiler should do. the developer has some control over the "guard rails"

(i usually enable -Wall -Werror)

Are you sure about that? You shouldn't. Please post an example.

you're correct, for the example i described.

perhaps a more valid example is defining a char * variable that may be set to a char * or const char* which is then used as a argument to a function.

const char * msg = "some msg";

void
func (
    const char *s )
{
}

main ()
{
    char s [80];
    char *t;

    t = (char*) msg;
    func (t);

    t = s;
    func (t);

    return 0;
}

Hmmmm ..... odd, not seeing it:

const char * msg = "some msg";

void func (const char *s) {
}

void setup() {
  char s [80];
  char *t;

  t = (char*) msg;
  func (t);

  t = s;
  func (t);
}

void loop() {
}

Compiled for Teensy, ESP32, and Uno. Only warning was about 's' being unused parameter in func().

Please post the warning you're getting.

i posted the code with the cast that compiles

g++  -I ../Include -I /tools/Arduino/hardware/arduino/avr/variants/standard -I DS3231-1.0.2   main.cpp   -o main
main.cpp: In function ‘int main()’:
main.cpp:14:10: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
   14 |     t =  msg;
      |          ^~~
      |          |
      |          const char*
make: *** [<builtin>: main] Error 1
const char * msg = "some msg";

void
func (
    const char *s )
{
}

main ()
{
    char s [80];
    char *t;

    t =  msg;
    func (t);

    t = s;
    func (t);

    return 0;
}