Splitting 2d char array into 1d constituents

file:///usr/share/arduino/reference/String.html

char* myStrings[]={"This is string 1", "This is string 2", "This is string 3",
"This is string 4", "This is string 5","This is string 6"};

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

void loop(){
for (int i = 0; i < 6; i++){
Serial.println(myStrings[i]);
delay(500);
}
}

--

hello people, be gentle
taking that example from the reference
I can Serial print the strings one at a time as above
and can lcd.print to 20x4 screen
but my strings are more than 20 chars and of course wrap to the next line plus one
I don't want to use String object/type, or String.substring, I hit some upper size limit with 20 40 character strings,
and it uses lots of memory

I'm only interested in a single member of the array, take say myStrings[5]
containing 'This is string 5'.

I don't want to serial or lcd print it yet.
I want to assign it to a variable, another character array containing the individual letters
through which I can then loop
for (byte i=0 ; i<20 ; i++) {lcd.print otherVar[i]}

and at the start of the subsequent screen line after setting cursor
for (byte i=20 ; i<39 ; i++) {lcd.print otherVar[i]}

I can do Serial.println(myStrings[i], or mylcd.println(myStrings[i]
but how to simply do like char otherVar[]=myStrings[i] (doesn't work for me) and get the equivalent of {'T', 'h', 'i', 's', ' ', 'i', 's' ...}

I'm sure I had this working before in an earlier edit of something but must have just got lucky. I've discovered some stuff in 'you topic is similar too' that might have an answer, but as I'm here might as well say hi

anyone help, thanks, tom

Something like this maybe ?

char* myStrings[] = {"This is string zero", "This is string one", "This is string two",
                     "This is string three", "This is string four", "This is string five"
                    };

void setup()
{
  Serial.begin(115200);
  for (int x = 0; x < 6; x++)
  {
    printString(x);
    Serial.println();
  }
}

void loop()
{
}

void printString(int number)
{
  for (int c = 0; c < strlen(myStrings[number]); c++)
  {
    Serial.print(myStrings[number][c]);
  }
}

Or, just ...

Serial.print(myStrings[number]);

Your only/main problem is that otherVar isn't a char but a char*.

char* singleText = myStrings[5];
if (strlen(singleText) > 20) {
   Serial.write(singleText,20);  // first 20 characters
   Serial.println();
   Serial.println(singleText+20);  // second part
}

Aditionally:
Of course you should get used to avoiding this warning:
warning: ISO C++ forbids converting a string constant to 'char*' [-Wwrite-strings]
by working with const char*

thanks
UKHeliBob and gfvalvo, for quick replies

Bob, I'm trying something like yours just now. I know I need to worry about bounds, strlen() will be part of it, each myStrings[number] could be from 0, an empy string "", to 40 chars long max , I could pad all out to 40 chars like so:

const char* myStrings[] =
  {
 "0123456789012345678901234567890123456789",   //0 //40 chars
 "0123456789012345678901234567890123456789",  //1
 "", //2
...
 "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG" //20
];

gfvalvo
that's what is in the example, it works but gives me the whole string in one, I want to split one array element into its individual letters, determine the length and on lcd display the string on two consecutive lines if it exceeds 20 chars or just first line if less than 20 chars.

I'm close, but just not there yet. without displaying anything just yet, want to create a char array thisString[] from myStrings[number], that -using 20th element in as above, looks like ['A', 'B', 'C', ...]. Can do strlen I think on your myStrings[number], strlen(myStrings[number]) before splitting so know the length already. Next time in function 'number' will be a different number.

I'll have to get back to the IDE and try some of the suggestions, read up a bit more on this aspect and pointers etc., it's do-able and the goal is simply to provide long user-friendly names for things rather than being terse and cryptic on-screen, as much as is possible on a 20x4 LCD.=#

Thank you Michael. That looks like it will work, all the replies helpful.
Think I was doing

char* singleText[] = myStrings[5], spot the difference, and it was failing to complile, wanted size initialising or worse, or it worked but I only got the first char.

I'll now vanish for years into the ether, humbled, no I won't this was fun!

thank you, tom

hanks
UKHeliBob and gfvalvo, for quick replies

Bob, I'm trying something like yours just now. I know I need to worry about bounds, strlen() will be part of it, each myStrings[number] could be from 0, an empy string "", to 40 chars long max , I could pad all out to 40 chars like so:

const char* myStrings[] =
  {
 "0123456789012345678901234567890123456789",   //0 //40 chars
 "0123456789012345678901234567890123456789",  //1
...
 "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG" //20
];

gfvalvo
that's what is in the example, it works but gives me the whole string in one, I want to split one array element into its individual letters, determine the length and on lcd display the string on two consecutive lines if it exceeds 20 chars or just first line if less than 20 chars.

I'm close, but just not there yet. without displaying anything just yet, want to create a char array thisString[] from myStrings[number], that -using 20th element in as above, looks like ['A', 'B', 'C', ...]. Can do strlen I think on your myStrings[number], strlen(myStrings[number]) before splitting so know the length already. Next time in function 'number' will be a different number.

I'll have to get back to the IDE and try some of the suggestions, read up a bit more on this aspect and pointers etc., it's do-able and the goal is simply to provide long user-friendly names for things rather than being terse and cryptic on-screen, as much as is possible on a 20x4 LCD.

I don't know why this reply won't post, just keeps rejecting it.
thanks
UKHeliBob and gfvalvo, for quick replies

Bob, I'm trying something like yours just now. I know I need to worry about bounds, strlen() will be part of it, each myStrings[number] could be from 0, an empy string "", to 40 chars long max , I could pad all out to 40 chars like so:

const char* myStrings[] =
  {
 "0123456789012345678901234567890123456789",   //0 //40 chars
 "0123456789012345678901234567890123456789",  //1
...
 "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFG" //20
];

gfvalvo
that's what is in the example, it works but gives me the whole string in one, I want to split one array element into its individual letters, determine the length and on lcd display the string on two consecutive lines if it exceeds 20 chars or just first line if less than 20 chars.

I'm close, but just not there yet. without displaying anything just yet, want to create a char array thisString[] from myStrings[number], that -using 20th element in as above, looks like ['A', 'B', 'C', ...]. Can do strlen I think on your myStrings[number], strlen(myStrings[number]) before splitting so know the length already. Next time in function 'number' will be a different number.

I'll have to get back to the IDE and try some of the suggestions, read up a bit more on this aspect and pointers etc., it's do-able and the goal is simply to provide long user-friendly names for things rather than being terse and cryptic on-screen, as much as is possible on a 20x4 LCD.

There is no need to 'split one array element into its individual letters'. You can skip right to 'determine the length':

int length = strlen(myStrings[i]);

Then you can decide what to do:

  lcd.setCursor(0,1);  // Start of the top line
  lcd.print(myStrings[i]);
  if (length > 20)
  {
    lcd.setCursor(0,2);  // Start of the second line
    lcd.print(myStrings[i] + 20);  // Start 20 characters in
  }

But @othertom wants to read the string character by character so that he/she can manage how long strings are displayed on an LCD screen of limited width, hence my character by character approach

Yea, but the 'for' loop in that code used c < strlen(myStrings[number]) as the test condition. So it's the same thing.

It was an example of how to access each character in the string which means that it becomes easy to split the string at any point that you choose, like this

char* myStrings[] = {"This is string zero", "This is string one", "This is string two",
                     "This is string three", "This is string four", "This is string five"
                    };

void setup()
{
  Serial.begin(115200);
  for (int x = 0; x < 6; x++)
  {
    printString(x);
    Serial.println();
  }
}

void loop()
{
}

void printString(int number)
{
  for (int c = 0; c < strlen(myStrings[number]); c++)
  {
    if (c == 5) //new line part way through the string
    {
      Serial.println();
    }
    Serial.print(myStrings[number][c]);
  }
}

You could, of course, make the point at which the split occurred a variable calculated on how much space was remaining on the LCD screen. I deliberately did not include the LCD setup and output and the calculation of remaining space so as not to obscure the technique that I was suggesting and also to give @othertom something to do

Guys and Gals, with your help I've cracked a nutty prblem that has foxed me for a few days. I need to read some of the new replies, I'm overwhelmed with the response and quality of the suggestions and help.

Here's what I have, all seems good, more testing to follow.

static const char* progNames[] =
  {
 // "0123456789012345678901234567890123456789"  //40 chars
    "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMN", //0
    "BCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNO",  //1
    "CDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOP",  //2
    "", //3
    " ", //4
    "PPG + TL + LOOP", //5
    "Tom's settings.   Tom's settings. Tom's settings.", //6
    "Special for x", //7
    "For Marina", //8 
    "ü$%£é+=-_ quick brown fox", //9
    "Tests of four obx", //10
    "eleven", //11
    "twelve boiled beef andcarrots                     ", //12
    "thirteen    thirteen     thirteen", //13
    "", //14
    "0123456789012345678901234567890123456789", //15
    "sixteen", //16
    "seventeen", //17
    "eighteen eighteen eighteen eighteen eighteen", //18
    "nineteen   nineteen" //19
    };

  char* thisProg = progNames[encoderPos];
                                  
  clearLCDline(LINE02); clearLCDline(LINE03);  

  if (strlen(progNames[encoderPos]) >= 20)
  { 
    lcd01.setCursor(0,LINE02);
    
    for (byte i=0; i < 20; i++)
    {
      lcd01.print(thisProg[i]);
    }
    
    lcd01.setCursor(0,LINE03); 
    
    for (byte i=20; i < (strlen(progNames[encoderPos])); i++)
    {
     lcd01.print(thisProg[i]);
    }
  }
  else
  {
    lcd01.setCursor(0,LINE02); 
    
    for (byte i=0; i < (strlen(progNames[encoderPos])); i++)
      {
        lcd01.print(thisProg[i]);
      }
  }

I found both:
(strlen(progNames[encoderPos]));
and
strlen(thisProg));
both gave the same correct result, one is probably better than the other in some respects.

Have to catch up, some substantial replies unread,
thanks, tom

I am glad that you got it working but what is the point of copying the string from the array to a second string ?

@UKHeliBob : He's just copying a char*, not the string itself.

And sure, after his

const char* thisProg = progNames[encoderPos];

he does not need to refer to progNames[encoderPos] any more in his strlen functions.

BTW: doing the character by character print is not required, as there's a write(buf,len) method, and adding an offset to a pointer is a very convenient way to start printing somewhere later.

It is.
Working code is good code. Polishing is only good to get used to doing it simpler next time.

I'm with you Bob, If I spot these things at all, it's long after.
You're right and I don't need it again, am throwing it away once displayed. Taking baby-steps first. That was the difficulty before, I could display on LCD or Serial, but couldn't use it in strlen() and similar functions and chop it to pieces.

Done it now, it's beautiful, what I was aiming at, and missing.

//  char* thisProg = progNames[encoderPos];
                                  
  clearLCDline(LINE02); clearLCDline(LINE03);  

  if (strlen(progNames[encoderPos]) >= 20)
  { 
    lcd01.setCursor(0,LINE02);
    
    for (byte i=0; i < 20; i++)
    {
      lcd01.print(progNames[encoderPos][i]);
    }
    
    lcd01.setCursor(0,LINE03); 
    
    for (byte i=20; i < (strlen(progNames[encoderPos])); i++)
    {
     lcd01.print(progNames[encoderPos][i]);
    }
  }
  else
  {
    lcd01.setCursor(0,LINE02); 
    
    for (byte i=0; i < (strlen(progNames[encoderPos])); i++)
      {
        lcd01.print(progNames[encoderPos][i]);
      }
  }
    

nopped out the intermediate var thisProg, it's gone

Sorted another little wrinkle in case it's over 40 characters length such as element 6 in the code pasted.

Protection against innumerate programmer, that being me.

The whole 'if' is a bit daunting, see below, but it works. It'll make no sense tomorrow, if I don't add some comments now.

if (strlen(progNames[encoderPos]) > 20)
  { 
    lcd01.setCursor(0,LINE02);
    
    for (byte i=0; i < 20; i++)
    {
      lcd01.print(progNames[encoderPos][i]);
    }
    
    lcd01.setCursor(0,LINE03); 
    
    if ((strlen(progNames[encoderPos])) < 40)
      {
        for (byte i=20; i < (strlen(progNames[encoderPos])); i++)
        {
          lcd01.print(progNames[encoderPos][i]);
        } 
     }
    else
      {
        for (byte i=20; i < 40; i++)
        {
          lcd01.print(progNames[encoderPos][i]);
        }
      }
  }
  else
  {
    lcd01.setCursor(0,LINE02); 
    
    for (byte i=0; i < (strlen(progNames[encoderPos])); i++)
      {
        lcd01.print(progNames[encoderPos][i]);
      }
  }

Thank you, bob, gfvalvo, Michael, john -this: lcd.print(myStrings[i] + 20) was nice too, useful, a wee note made of that.

thank you all, Tom

Ok, I will put my question another way

What is the point of copying the pointer of the string in array to a second pointer

Of course it's not. Once you have grasped the fact that you can access each character in the string, as I demonstrated, there are a number of ways to do what @othertom wants to do to format the LCD display

What many contributors here fail to understand is that what they think is obvious based on their experience is like black magic to a newcomer, hence my simple example of accessing each character in a string held in an array rather than proposing adding an offset to a pointer as an initial suggestion

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.