How to make two dimensional array

Hi

I'm trying to learn the programming language. Coming from a scripting language, I understand the concepts but I need to learn the syntax :slight_smile:

I'm trying to get my head around a two dimensional array.

How would I write this for the arduino:

var language = array(

    'EN'=> array(
        'STATUS_XX'=>'Alert: xx',
        'STATUS_YY'=>'Alert: yy',
    ),

    'DA'=> array(
        'STATUS_XX'=>'Alert: xx',
        'STATUS_YY'=>'Alert: yy',
    ),

);

Thanks

example 2D array

int tictactoe[3][3];

// clear tictactoe
for (int i=0; i<3 i++)
{
  for (int j = 0; j< 3; j++)
  {
    tictactoe[i][j] = 0;
  }
}

On the basis that a program is worth a thousand words, try this and amend it to suit your requirements.

char *language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };

void setup() 
{
  Serial.begin(115200);
  for (int row = 0; row < 2; row++)
  {
    for (int col = 0; col < 4; col++)
    {
      Serial.print(language[row][col]);
      Serial.print("\t");
    }
    Serial.println();
  }
}

void loop() 
{
}

Output

A	B	C	D	
1	2	3	4

why
char *language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };
and not
char language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };
?

what does the asterisk (*) do?

what does the asterisk (*) do?

It makes language a pointer to the array.

It could just as well have been

char * language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };

Look at the contents in the array. Is it using single quotes indicating a char, or double quotes indicating a char array (string)?

char * language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };

as opposed to

char  language [][4] = { {'A','B','C','D'},{'1','2','3','4'} };

Pointers (*) are VERY important and are Need-To-Know when writing code.

darkroomsource:
why
char *language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };
and not
char language [][4] = { {"A","B","C","D"},{"1","2","3","4"} };
?

what does the asterisk (*) do?

The letters in double quotes are 1 dimension char arrays themselves, that's what C strings are.

So you have a 2 dimension array of 1 dimension arrays there which is a 3D array.

Serial.print() will print a char like 'A' or a string like "A" or "A string" depending on what it is passed.

These are equivalent:

char *myCstring = "a string";
char myCstring[] = "a string";

I just found something interesting that I don't remember from before!
That might be because I only declared string arrays one way or it might not.

The sketch showing what I'm talking about:

void setup( void )
{
  Serial.begin( 115200 );
  Serial.println( "\n Arrays!\n" );

  Serial.println( "char myArray[][3][7]" );
  // declaring a char array, all but the first index must be given
  char myArray[][3][7] = // note that [7] is for the max string length
  { 
    "A", "BC", "DEF", "GHIJ", "KLMNO", "PQRSTU"         
  };

  byte row, col;
  for ( row = 0; row < 2; row++ )
  {
    for ( col = 0; col < 3; col++ )
    {
      Serial.print( myArray[ row ][ col ] );
      Serial.print( '\t' );
    }
    Serial.println();
  }

  Serial.println( "\n Lets see what's in myArray.\n" );

  char *ch = myArray[ 0 ][ 0 ]; // pointer to the start of the array
  byte flg = 1, cnt = 6;

  while ( cnt )
  {
    if ( !( *ch )) // reducing cnt whenever a first zero char is found
    {
      if ( flg )
      {
        cnt--;
      }
      flg = 0;
      
      Serial.print( '0' );
    }
    else
    {
      if ( !flg )
      {
        Serial.println();
      }
      flg = 1;
    }
    Serial.print( *ch++, HEX );
    Serial.print( " " ); 
  } 
  Serial.println( "\n\nFixed length C strings!" );
  Serial.println( "These make known length buffers you can change later." );

  Serial.println( '\n' );

  Serial.println( "char *myCstrings[][3]" );
  // trickier than it looks
  char *myCstrings[][3] =  // note that you don't set max string length
  { 
    "1", "22", "333", "4444", "55555", "67890" 
  };

  for ( row = 0; row < 2; row++ )
  {
    for ( col = 0; col < 3; col++ )
    {
      Serial.print( myCstrings[ row ][ col ] );
      Serial.print( '\t' );
    }
    Serial.println();
  }

  Serial.println( "\n Lets see what's in myCstrings.\n" );

  ch = myCstrings[ 0 ][ 0 ]; // pointer to the start of the array
  cnt = 6;
  flg = 1;

  while ( cnt )
  {
    if ( !( *ch )) // reducing cnt whenever a first zero char is found
    {
      if ( flg )
      {
        cnt--;
      }
      flg = 0;
      
      Serial.print( '0' );
    }
    else
    {
      if ( !flg )
      {
        Serial.println();
      }
      flg = 1;
    }
    Serial.print( *ch++, HEX );
    Serial.print( " " ); 
  } 
  Serial.println( "\n\nDifferent length C strings!" );
  Serial.println( "If you buffer with these, know all the lengths!" );
  Serial.println( "I dunno how you could PROGMEM char *str[][ 8 ]" );
}

void loop( void )
{
}

And these are the results:

 Arrays!

char myArray[][3][7]
A	BC	DEF	
GHIJ	KLMNO	PQRSTU	

 Lets see what's in myArray.

41 00 00 00 00 00 00 
42 43 00 00 00 00 00 
44 45 46 00 00 00 00 
47 48 49 4A 00 00 00 
4B 4C 4D 4E 4F 00 00 
50 51 52 53 54 55 00 

Fixed length C strings!
These make known length buffers you can change later.


char *myCstrings[][3]
1	22	333	
4444	55555	67890	

 Lets see what's in myCstrings.

31 00 
32 32 00 
33 33 33 00 
34 34 34 34 00 
35 35 35 35 35 00 
36 37 38 39 30 00 

Different length C strings!
If you buffer with these, know all the lengths!
I dunno how you could PROGMEM char *str[][ 8 ]

I thought I understood pointers. Now I'm getting confused.
I get GoForSmoke's example and understand about character arrays vs string arrays, and referencing the array using a pointer.

What I don't quite comprehend is why use a pointer to define a "variable".
ie.

char * language [][4] = {{"A","B","C","D"},{"1","2","3","4"}};
// .vs.
char language[][4] = {{'A','B','C','D'},{'1','2','3','4'}};

Don't both of these give me the same results? I can reference language in my code the same way independent of whether I made it a pointer or not, no?
And I can create a pointer to language either way also, no?

Is there an advantage to defining it as a pointer in the first place?

darkroomsource:
What I don't quite comprehend is why use a pointer to define a "variable".
ie.

char * language [][4] = {{"A","B","C","D"},{"1","2","3","4"}};

// .vs.
char language[][4] = {{'A','B','C','D'},{'1','2','3','4'}};



Don't both of these give me the same results? I can reference language in my code the same way independent of whether I made it a pointer or not, no?
And I can create a pointer to language either way also, no?

Is there an advantage to defining it as a pointer in the first place?

You should have paid more attention to HazardsMind's post: the second declaration uses single quotes during initialization, which is an indication of the fact your two dimensional array is going to contain a character in each position, the first declaration instead uses double quotes in the initialization section and double quotes are delimiters for strings.
In C (and many other languages) the two delimiters are not interchangeable, single quotes can be used for chars only, double quotes for strings only. In C strings are array of characters, which means the first declaration is going to create a 2 dimensions array where each position will contain an array of characters... this is equivalent to a 3 dimensions array of character.

To put it in another format, by using the first notation you are adding an additional dimension and gaining the capability to store strings instead of single chars.

When you declare a variable as a pointer you are getting the ability to access the variable memory location, which is something I will not illustrate here as it might be confusing.

For comparison:

int numbersArray[];
int * numbersPointer;

are equivalent and they can both represent an array.

To get back to the example above, how would you represent language D as 10? You can if you use the first notation, but try doing it using the second one....

Yah, you can use what I posted to see what bytes are in the array, or write a hex dump of your own to know the difference. Hardest part is getting the pointers straight but IMO that means knowing or learning something of value.

I probably muddied the waters by asking why " was different than ', I know that " is for string and ' is for char, I got confused by HazardsMind statement thinking that he was correcting my 2nd line. And I got a bit confused about the " and '. It is clear to me that " is used for strings, and that strings are null terminated and not fixed length, etc. Sorry about that.

why would I want
char *language[][4]={{"A","B","C","D"},{"1","2","3","4"}};
instead of
char language[][4]={{"A","B","C","D"},{"1","2","3","4"}};
?

why would I want
int *iAbc = 123;
instead of
int iAbc = 123;

The first one is a pointer that you set to the RAM address 123. The pointer is for variable type int.

The second one makes space for an int in RAM that the name iABC in your code locates and sets that int to the value 123.

They are not the same at all. You would use one instead of the other to do something different.

why would I want
char *language[][4]={{"A","B","C","D"},{"1","2","3","4"}};
instead of
char language[][4]={{"A","B","C","D"},{"1","2","3","4"}};
?

The second one won't work. If you experimented with the code it would tell you and you wouldn't understand.

The second line should be
char language[][4][2]={{"A","B","C","D"},{"1","2","3","4"}};

The [2] is the number of characters allowed per string (double quotes makes string) which can be > 2.
Why 2 for 1 letter? Because all C strings must end with a zero byte to mark the end.

C string "A" is 2 bytes. One byte for 'A' (ASCII code 65, the byte value is 65) and one byte for the 0.

The [4] is for sets of 4 strings.

The [] is for however many sets there are but you can put a number there.

Between your lack of understanding variables and strings and pointers, you are confused.

This is a good time to not just read but work out simple sketches to find out every last little part that you are not completely sure of. Whatever you suspect, try. Even a fail provides some information.

The information is great! Now to when i have and array in this form -- char *message[] = {"Message 0", "Message 1", "Message 3"};

How can i recall its lenght?

char novelName[][13] = {"one.txt", "two.txt", "three.txt"};
char *message[] = {"Message 0", "Message 1", "Message 3"};

void setup() {

Serial.begin(9600);
randomSeed(analogRead(0));

}

void loop() {
int lengthLib = message.length(); //This is the command in question
int novel_num = random(3);
Serial.println (novel_num);

Serial.println(novelName[novel_num]);
Serial.println(message[novel_num]);

delay (1000);

}

Thank you

g

 #define novelLength = 13;  // hope you included 1 for terminating zero.

 char novelName[][novelLength] = {"one.txt", "two.txt", "three.txt"};
  char *message[] = {"Message 0", "Message 1", "Message 3"};

The length is novelLength.

char * language [][4] = {{"A","B","C","D"},{"1","2","3","4"}};

rlogiacco:
In C strings are array of characters, which means the first declaration is going to create a 2 dimensions array where each position will contain an array of characters... this is equivalent to a 3 dimensions array of character.

More precisely, each "position" (element) of the 2-dim array will contain a pointer to a character (char *). Because of the initialization used, those pointers will point to the first character of each c-string. Consecutive bytes after that first char will contain the rest of each c-string. Because, in this case, each c-string is only 1 character long, the second byte of each one will contain the '\0' character.

galomoncayo:
The information is great! Now to when i have and array in this form -- char *message[] = {"Message 0", "Message 1", "Message 3"};

How can i recall its lenght?

  char novelName[][13] = {"one.txt", "two.txt", "three.txt"};

char *message[] = {"Message 0", "Message 1", "Message 3"};

Whoops, you want the length of message[] strings!

You made an array of pointers to strings and the compiler put the strings in storage. So in RAM there is each message with a character 0 at the end (how you find the end) and the start address is a char pointer in the message char * array. You can simply pass the char pointer to Serial.print() and it will print correctly so why do you need the length? The string.h library has a function strlen() that will give you the length of any string not including the terminating 0 if you need the length.