Functions - a few questions

Hi,

I’m learning how to use functions with Arduino and I have a few questions. I modified the code below from a text I’m learning from, and while I feel I simplified it a bit, there are a few areas of the code I’m unsure how it’s actually being used.

 /*   Goals:  
 *      1. (done) Enter data into serial monitor
 *      2. (done) Print it back out on serial monitor 
 *      3. (done) Perform math on the data which was entered
 *
 * 
 *    Notes:
 *      1.  referencing p. 104 - 107+ in text
 */


/***** FUNCTION PROTOTYPES *****/
int ReadLine(char);


/***** SETUP *****/
void setup() 
{
  Serial.begin(9600);
}


/***** LOOP *****/
void loop() 
{
  if (Serial.available() > 0) /* looks for the number of data bytes in the serial buffer.  
                                 If any bytes are there (e.g. information), the code will then create 
                                 several local variables and call function ReadLine() 
                              */
    {
       char myData[20]; // create an array size of 20 elements, 
                         /*  If Arduino rec. only use the data type char for storing characters, then it follows
                          *     to only use a data type char for an array if holding the characters
                         */
                            
       int bufferCount = ReadLine(myData);   /* Pass the parameter, char array 'myData' into the arguements of function ReadLine() for the following:
       
                                                (1) counts the characters in the array which is returned to variable 'bufferCount'
                                                    in case there's some value in using it
  
                                                (2) MOST IMPT:  allows array myData to store info. from the serial buffer, 
                                                    which will then be converted into a number using the function, atoi()
                                             */
      
      
       int number = atoi(myData);  // converts contents of char array (which is a string) to int data type
                            /* In C, atoi() converts a string to an integer. The atoi function skips 
                             * all white-space characters at the beginning of the string, converts 
                             * subsequent characters as part of the number, and then stops when it 
                             * encounters the first character that isn't a number.
                             * 
                             * If the string does not represent an integer at all, atoi will return 0
                             * 
                             * This line is executed once the Enter key has be pressed
                             */
                             
      // print number entered
      Serial.print("number entered: ");
      Serial.println(number);

     // perform math on number which was entered
      Serial.println();
      Serial.print("  number entered / 2 = "); Serial.println(number / 2);  // odd number will have decimal truncated
      Serial.println();     

      // print number of characters in array (character count)
      Serial.print("bufferCount = ");  Serial.println(bufferCount);      
    }

}



/***** FUNCTIONS *****/

/*****
 * Purpose:  Read data from serial port until newline characater is read ('\n')
 * 
 * 2 Parameters:
 *     Character Array, which will strore contents entered from serial monitor
 *         char myData[]  // the character array, 'myData', and will be treated it as a nul-terminating string
 *  
 *     Return value:
 *         int   // the number of characters read for the string, using int index
 *    
 *  CAUTION:  This method will sit here forever if no input is read from the serial monitor port and no newline character is entered. (if that a bad thing?)
 *  
 *****/ 

 int ReadLine(char myData[])  // passes parameter array, 'myData[]' into the arguement of the function, 'Readline()'
 {
    char new_character;    /* stores each character as entered into the serial monitor, which gets passed, one by one, into the buffer
                              It’s recommended to only use char for storing characters. source: https://www.arduino.cc/reference/en/language/variables/data-types/char/
                           */
  
    
    int index = 0;        /*  counter for storing incoming characters entered into array 'myData[]'
                              
                              Each new var 'c' entered will increase the position 
                              of the array which the new character is entered in. This will con't until a '\n' is read via the while loop,
                              as long as there is data in the buffer (hence the statement, Serial.available() > 0)
                          */
  
    while (true)
    {
      if (Serial.available() > 0)
        {
          new_character = Serial.read(); // all data entered into the serial monitor by default is a char
          
          if (new_character != '\n')    // \n is C programmning code for indicating that the Enter button was pressed
            {
              myData[index++] = new_character;  // place character into char array myData at +1 element position
            }
  
           else
             {
               myData[index] = '\0';  // add a null termination character to the string
                     
               break;              /* Used to break out of the while loop (even if nesting occurs), hence ending reading from the serial buffer
                                      That occurs is that the break returns a "false" paramtere to the while() function, which ends the loop
                                      The code will then con't to next line of code after the while loop, which here is "return index"
                                   */                                
           }
      }
  }

  return index;            // returns the counter value of var index to var bufferCount
 }

Q1. In the code, I have a line with a comment next to it that I’m not sure is correct:

char myData[20];  // create an array size of 20 elements

But the size of the array appears irrelevant. When I replace 20 by 0, the program works the same. Why?

Q2: Why is the max number of characters I’m able to type into the serial 27? At 28+ nothing appears when you hit enter?
As I understand it, Arduino’s buffer has a max size of 64 bytes, and 27 characters is 27*8 bytes = 224 bytes. The reason this appears odd is that in my code ‘bufferCount’ will correctly return 27 if you enter that many characters into the serial monitor, but if I try 28, nothing happens.
This seems even odder since bufferCount is of type ‘int’, and thus, only 5 characters can accurately get recorded (so long as the number entered into the serial monitor is <32,768)

project_science:
Q1. In the code, I have a line with a comment next to it that I’m not sure is correct:

char myData[20];  // create an array size of 20 elements

But the size of the array appears irrelevant. When I replace 20 by 0, the program works the same. Why?

Because C / C++ does not do run-time checking of array indices. When you set the size to zero but still access elements, you're using memory that you don't own. It will come back and bite you.

And 27 characters is 27*8 bytes = 224 bytes.

I'd love to know why you think a character takes 8 bytes. A character takes 1 byte, so 27 characters takes 27 bytes.

Are you getting confused with bits, of which there are 8 in a byte?

gfvalvo:
Because C / C++ does not do run-time checking of array indices. When you set the size to zero but still access elements, you're using memory that you don't own. It will come back and bite you.

Thanks gfvalvo! So if I understand this correctly, I should only set the size of the array to the number of elements I plan on using, which then allocates the appropriate amount of program space I'll need. But, if I declare a small array size, and then use a larger array actually in my code, I could run into unforeseen problems during the use of the program, even if the compiler doesn't complain?

PerryBebbington:
I'd love to know why you think a character takes 8 bytes. A character takes 1 byte, so 27 characters takes 27 bytes.

Are you getting confused with bits, of which there are 8 in a byte?

Perry, good catch! I think I did make that mistake. So I meant 27 characters (27 bytes) is 27*8 bits = 224 bits, which is less than the max. buffer size of 64 bytes (64 * 8 bits = 512 bits).

So then why is the 28th character not showing in the serial monitor when I hit enter?

But, if I declare a small array size, and then use a larger array actually in my code, I could run into unforeseen problems during the use of the program, even if the compiler doesn't complain?

That is right. It is called a buffer overflow and can be a very hard to find bug. Always declare arrays with a size that can hold the largest number of elements that will ever be needed.

So then why is the 28th character not showing in the serial monitor when I hit enter?

Please post your code. In the original posting you were trying to read 28 characters into a 20 byte buffer. What are you entering, and what do you expect to see in the monitor?

Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R

So I meant 27 characters (27 bytes) is 27*8 bits = 224 bits, which is less than the max. buffer size of 64 bytes (64 * 8 bits = 512 bits).

Most of the time, in most circumstances, it is not necessary to be concerned about the number of bits, and certainly not in this situation. Keep to thinking about how many bytes are needed, don't be concerned with how many bits that is.

cattledog:
Please post your code. In the original posting you were trying to read 28 characters into a 20 byte buffer. What are you entering, and what do you expect to see in the monitor?

I was using that code, and testing the following chars at one time:

this worked: 123456789012345678901234567
didn't work: 1234567890123456789012345678

However, when I changed the line,

 char myData[20]; // create an array size of 20 elements

to

 char myData[28]; // create an array size of 28 elements,

I was able to get the chars that didn't work to successfully go through on the serial monitor.

But that doesn't explain why 27 chars worked originally

Robin2:
Have a look at the examples in Serial Input Basics - simple reliable non-blocking ways to receive data. There is also a parse example to illustrate how to extract numbers from the received text.

...R

Thanks, this was helpful!

A 28 element char array can’t hold a C string of 28 characters - you need an extra element for the terminator.
If you’re writing into memory you don’t own, sometimes it’ll “work”, and other times, it’ll appear to work, and then blow up in your face.

You were writing beyond the bounds of your array. Depending on how the compiler has arranged things in memory, you may get away with it.

If you really care about what specifically happened in this case, you would need to look at the code the compiler generated for you to send to the Arduino, which is non-trivial.

Rather than bother with that, I'd suggest that you just take it as a lesson to be mindful of your array sizes in future.