writing to 2d array?

Hey guys. i am having some trouble writing from Serial.read() to a 2d array.

Code is as follows:

char inData[17][19]; 
char inChar; 
byte index = 0; 

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

void loop() {

  while(Serial.available() > 0) //only read if there is any data
  {
    if(index < 16) 
    {
      inChar = Serial.read(); //read from Serial
      inData[index] = inChar; //store it in inData
      index++; //make ready for next time - Next array "downwards"
    }
  }
}

which gives me "incompatible types in assignment of 'char' to 'char [19]"
What i believe is that i might need to index in the 2nd []. that would be inChar[][here] i just don't know how to do it.
I have been putting google into overdrive, but i can't seem to find anything about it that i understand.

so what i want is to be able to fill this 2d array with a line of text from the Serial monitor.

EG.

If i send
"bob" enter
"bert" enter
"tim" enter

i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"

i hope you understand. :slight_smile:
how would i go about doing this?

try this:

char inData[17][19]; 
char inChar; 
byte index = 0; 
byte linenumber=0;

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

void loop() {

  while(Serial.available() > 0) //only read if there is any data
  {
    if ((linenumber<17) && (index < 19))
    {
      inChar = Serial.read(); //read from Serial

      if (inChar==13)
      {
        linenumber++;
        index=0;
      }

      inData[linenumber][index] = inChar; //store it in inData
      index++; //make ready for next time - Next array "downwards"
    }
  }
}

Hi kasperhangard!

In your example:

If i send
"bob" enter
"bert" enter
"tim" enter

i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"

you only need to read the enter, and pass to the next row of the array. I don't if it makes sense for you?

int row;
(...)
  while(Serial.available() > 0) //only read if there is any data
  {
      inChar = Serial.read(); //read from Serial
      if (inChar == 13) {   // NEW LINE
         row++;
         inData[row][index] = '\0';
         index=0;
      }
      else if (inChar >= 32) {   // SAVE if it is a PRINTABLE char
         inData[row][index] = inChar; //store it in inData
         index++; //make ready for next time - Next array "downwards"
      }

  }

Maybe you need to take a look at this.

What I did was detect if the incoming char is a char with ASCII code 13 (Carriage Return), and if is I change the line by incrementing the "row" variable and return to the first "index". I only save the characters if they are greater or equal than the ASCII 32 (the space). Usually this character marks the beginning of the "printable" characters area. An character with an ASCII less than 32 is an character for control purposes (like the Carriage Return). When you press "enter", normally they are sent 2 characters the Line Feed (ASCII 10 - change to the next line) and the Carriage Return (ASCII 13 - return to the begin of the new line). So as I don't want to save the ASCII 10 I need the second if. This line:

inData[row][index] = '\0';

marks the end of the string.

I hope you understand this.

Regards.

EDIT: as j514 don't explain what he did I spend more time writing my reply :slight_smile: but if you note is more or less the same.

EDIT2: as j514 don't have inData[row][index] = '\0'; you will not be able to print each line with some function to print data (for example to the serial port).

j514:
try this:

char inData[17][19]; 

char inChar;
byte index = 0;
byte linenumber=0;

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

void loop() {

while(Serial.available() > 0) //only read if there is any data
 {
   if ((linenumber<17) && (index < 19))
   {
     inChar = Serial.read(); //read from Serial

if (inChar==13)
      {
       linenumber++;
        index=0;
      }

inData[linenumber][index] = inChar; //store it in inData
     index++; //make ready for next time - Next array "downwards"
   }
 }
}

Hello. thanks a bunch for your help. i got some questions.

if (inChar==13) why do you want inChar to be 13?
And how would i be able to Serial.print() this? :slight_smile:

Thanks alot for your help :slight_smile:

luisilva:
Hi kasperhangard!

In your example:

If i send
"bob" enter
"bert" enter
"tim" enter

i will be able to just call the array lines like so
inData[0] would be "bob"
inData[1] would be "bert"
inData[2] would be "tim"

you only need to read the enter, and pass to the next row of the array. I don't if it makes sense for you?

int row;

(...)
  while(Serial.available() > 0) //only read if there is any data
  {
      inChar = Serial.read(); //read from Serial
      if (inChar == 13) {   // NEW LINE
         row++;
         inData[row][index] = '\0';
         index=0;
      }
      else if (inChar >= 32) {   // SAVE if it is a PRINTABLE char
         inData[row][index] = inChar; //store it in inData
         index++; //make ready for next time - Next array "downwards"
      }

}




Maybe you need to take a look at [this](http://benborowiec.com/wp-content/uploads/2011/07/better_ascii_table.jpg).

What I did was detect if the incoming char is a char with ASCII code 13 (Carriage Return), and if is I change the line by incrementing the "row" variable and return to the first "index". I only save the characters if they are greater or equal than the ASCII 32 (the space). Usually this character marks the beginning of the "printable" characters area. An character with an ASCII less than 32 is an character for control purposes (like the Carriage Return). When you press "enter", normally they are sent 2 characters the Line Feed (ASCII 10 - change to the next line) and the Carriage Return (ASCII 13 - return to the begin of the new line). So as I don't want to save the ASCII 10 I need the second `if`. This line:


inData[row][index] = '\0';




marks the end of the string.

I hope you understand this.

Regards.

EDIT: as j514 don't explain what he did I spend more time writing my reply :) but if you note is more or less the same.

EDIT2: as j514 don't have `inData[row][index] = '\0';` you will not be able to print each line with some function to print data (for example to the serial port).

Well, nevermind my other post. you explained it very well, and i am pretty sure i understand how it works, though i still have questions.

When i send a line from Serial monitor, it will still "catch" the enter right? i just wanna make sure i understand.

Also, how would i go about printing this? i should be able to print it like inData[1][4] right? though this would only give me one char.

Thanks alot for your time :slight_smile:

here's a revised version with consideration for the trailing null and serial output.

Hope that helps!

char inData[17][19]; 
char inChar; 
byte index = 0; 
byte linenumber=0;

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

void loop() {

  while(Serial.available() > 0) //only read if there is any data
  {
    if ((linenumber<17) && (index < 19))
    {
      inChar = Serial.read(); //read from Serial

      if (inChar==13) // if character is the enter key
      {
        inData[linenumber][index] = 0; // trailing null
        serial.println(inData[linenumber]); // show received line
        linenumber++;
        index=0;
      } else
      {
         inData[linenumber][index] = inChar; //store it in inData
         index++; //make ready for next time - Next array "downwards"
      }
    }
  }
}

To send the data back to the serial line, you can use this:

char inData[17][19]; 
char inChar; 
byte index = 0; 

int row=0;

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

void loop() {

  while(Serial.available() > 0) //only read if there is any data
  {
      inChar = Serial.read(); //read from Serial
      if (inChar == 13) {   // NEW LINE
         inData[row][index] = '\0';
         Serial.println(inData[row]);
         row++;
         index=0;
      }
      else if (inChar >= 32) {   // SAVE if it is a PRINTABLE char
         inData[row][index] = inChar; //store it in inData
         index++; //make ready for next time - Next array "downwards"
      }

  }

}

I had one error in my last post. The line:

         inData[row][index] = '\0';

must be before we increment the row number. Sorry about that.

Take a look to the line that sends back the string:

         Serial.println(inData[row]);

You don't need the "second dimension". You may think that you what to send all the string and not only the character [n].

i should be able to print it like inData[1][4] right? though this would only give me one char.

Your guess is right. If you try to send "inData[1][4]" you only send the 5th character of the 2nd string. (remember that the arrays starts at zero)

About you other question:

When i send a line from Serial monitor, it will still "catch" the enter right? i just wanna make sure i understand.

You can chose in a drop box at the bottom of the serial monitor if you want to send only the char 13, or only the 10 or the 2 or none.

Whichever approach you take, remember to apply a bounds check to both dimensions of the array.

Aight, so my eyes are getting itchy, and i haven't got much hair left. let the stress commence! :slight_smile:

So i wanna try to make a system to check if whatever i enter, is already on the list. for that i made this:

char namecheck[19];
byte namecheckindex = 0;
char inChar; 


void namechecker()
{
  while(Serial.available() > 0) //only read if there is any data
  {
  inChar = Serial.read(); //read from Serial
  if (inChar==13) // if character is the enter key
      {
        namecheck[namecheckindex] = 0; // trailing null
        Serial.println(namecheck[namecheckindex]); // show received line
        namecheckindex=0;
      } else
      {
         namecheck[namecheckindex] = inChar; //store it in inData
         namecheckindex++; //make ready for next time - Next array "downwards"
      }
  }
}

it should essentially just be a copy of the code you gave me, but with names changed, and the namecheck only being a standard array instead of 2d array.
i want this, so that i can unload inChar to namecheck, namecheck will then somehow go through the inData array and check if the entry is already there somewhere. if it is, it will delete the entry, if it isn't then it will enter it on the first open space.

Like this
i enter
"bob"
"bert"
"alice"
namecheck will go through inData and find that these names ins't there.
this will fill the first 3 "lines" in my char inData[17][19]; from the other code.
then i enter "bert" again, namecheck will go through inData and find that "bert is already there.
it will then delete "bert"

though i can't even get the code for printing out my array, working.
i have been staring at it for 1 hour now, and i think i am getting tunnel vision. what am i doing wrong?
also, any tips on my namecheck system, and how to create it ? :slight_smile:

Thank you PeterH. Maybe this comment have something to do with the arge of the other day.(BTW you never answer me)

I don't forgot, but I let some work to kasperhangard do. In my code I only take care about the correct way to read (and check the new line), and not about the dimensions. (as kasperhangard have the dimension check in the "original" code, I believe that he knows how and why do it)

PeterH:
Whichever approach you take, remember to apply a bounds check to both dimensions of the array.

Here you are thinking about ensuring that i do not overflow it right?
like this

if ((linenumber<17) && (index < 19))
//do stuff

kasperhangard:

        namecheck[namecheckindex] = 0; // trailing null

Serial.println(namecheck[namecheckindex]); // show received line

This doesn't print the received buffer, it just 'prints' the null terminator. To print the buffer, you need to remove the [ namecheckindex ] so that you pass the whole buffer to println.

You still need to do bounds checking on both indices of the array.

To add the extra logic you describe, you will need to be able to detect whether the string held in namecheck is already in the inData array. A for loop to call strcmp() on each element in the inData array would do that. To remove an entry, you would just null the first character of the string. To add an entry you would just find an empty entry and then use strncpy() to copy the string from namecheck to the empty entry. You can know whether a given entry is empty, because the first char of the string will be null.

PeterH:

kasperhangard:

        namecheck[namecheckindex] = 0; // trailing null

Serial.println(namecheck[namecheckindex]); // show received line

This doesn't print the received buffer, it just 'prints' the null terminator. To print the buffer, you need to remove the [ namecheckindex ] so that you pass the whole buffer to println.

You still need to do bounds checking on both indices of the array.

To add the extra logic you describe, you will need to be able to detect whether the string held in namecheck is already in the inData array. A for loop to call strcmp() on each element in the inData array would do that. To remove an entry, you would just null the first character of the string. To add an entry you would just find an empty entry and then use strncpy() to copy the string from namecheck to the empty entry. You can know whether a given entry is empty, because the first char of the string will be null.

Oh ty. i didn't realise the fact that it wasn't a 2d array.
i will try to look into for loops. i haven't done any of those before.
:slight_smile:

void namechecker()
{
  while(Serial.available() > 0) //only read if there is any data
  {
    inChar = Serial.read(); //read from Serial
    if (namecheckindex < 16)
    {
      if (inChar==13) // if character is the enter key
      {
        namecheck[namecheckindex] = 0; // trailing null
        Serial.println(namecheck); // show received line
        namecheckindex=0;
      } 
      else
      {
        namecheck[namecheckindex] = inChar; //store it in inData
        namecheckindex++; //make ready for next time - Next array "downwards"
      }
    }
  }
}

won't this do the boundries?
i mean, if the index gets too high, it can't go any further, can it?

You're in good hand now. So I let you with him.

Good work.

kasperhangard:
won't this do the boundries?
i mean, if the index gets too high, it can't go any further, can it?

Sort of, but not quite. As it stands, if the namecheck array ever filled up then you would stop processing any new characters, so you would never know when to process the buffer. It will work better if you put the 'if(namecheckindex < 16)' condition around the two lines of code that append the character to namecheck. I recommend that you append the null character to the array after each character added rather than just append it before you decide to process the array. It isn't essential, but will save you from bugs later on - perhaps in some other project down the road - where you decide to pass the incomplete buffer to any function that expects it to be terminated.

I don't see where the 16 comes from but you would be safer to define a const value which is the maximum number of characters that the array can hold, and to define this next to / as part of the array declaration so that they stay consistent with each other as your code evolves. Remember that this will be one less than the size of the array since you need one byte at the end to hold the null terminator. You could declare it like this:

const byte MAX_INPUT_LENGTH 16;
char namecheck[MAX_INPUT_LENGTH+1]; // allow space for the null terminator

PeterH:

kasperhangard:
won't this do the boundries?
i mean, if the index gets too high, it can't go any further, can it?

const byte MAX_INPUT_LENGTH 16;

char namecheck[MAX_INPUT_LENGTH+1]; // allow space for the null terminator

Ah! thanks alot man! :slight_smile:
Have i misunderstood something, or shouldn't it be char namecheck[MAX_INPUT_LENGTH**-**1];
to save that 1 last space ? :slight_smile:

The array needs to be one char bigger than the string it contains, to hold the null terminator. Your "-1" would make it one byte smaller.

PeterH:
The array needs to be one char bigger than the string it contains, to hold the null terminator. Your "-1" would make it one byte smaller.

oooh you were declaring it! i totally missed that. maybe it isn't the best idea to code at 4am..

I am trying to get the namechecker to compare the two strings, but i can't really seem to get it to work.

char inData[17][19]; 
const byte MAX_INPUT_LENGTH = 16;
char namecheck[MAX_INPUT_LENGTH+1];
byte namecheckindex = 0;
byte index = 0; 



void namechecker()
{
  if(strcmp(inData, namecheck) == 0)
  {
    Serial.println("is already here");
  }
  else
  {
    if ( index < MAX_INPUT_LENGTH )
    {
   index = 0;
   inData[index] = namecheck[index];
   index++; 
  }
}
}

this gives me

BareMinimum.ino: In function 'void namechecker()':
BareMinimum:64: error: cannot convert 'char ()[19]' to 'const char' for argument '1' to 'int strcmp(const char*, const char*)'
BareMinimum:73: error: incompatible types in assignment of 'char' to 'char [19]'

So i obviously messed up big time, i just can't seem to graps how the strcmp works. also, i don't know how to append the null after namecheck has been moved over to inData.
Also, is this what you had in mind with the boundries? :slight_smile:

inData is an array of string buffers. To check whether it contains a given string you need to loop through each element in the array comparing the string at that position against your candidate string.

for(byte i = 0; i < NAME_COUNT; i++)
{
    if(strcmp(inData[i], namecheck) == 0)
   {
      Serial.print("is already here at position ");
      Serial.println(i);
      break; // bail out of the for loop; presumably there's no point searching the rest of the array
   }
}

PeterH:
inData is an array of string buffers. To check whether it contains a given string you need to loop through each element in the array comparing the string at that position against your candidate string.

for(byte i = 0; i < NAME_COUNT; i++)

{
    if(strcmp(inData[i], namecheck) == 0)
   {
      Serial.print("is already here at position ");
      Serial.println(i);
      break; // bail out of the for loop; presumably there's no point searching the rest of the array
   }
}

Oh ofcourse.. what is namecount? the amount of lines, where names can be written?
I mean, the index for the "height" of the 2d array? :slight_smile: