Doubts about the strings and pointers

Go To Last Post
12 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello all!

 

I am doing a sketch to communicate wil a GSM modem to control 2 relays and see their status. I use a lot of string function like strstr(), strtok(), strcpy(), etc.

 

To read the response commands and sms's I use the   SoftwareSerial where I changed in the SoftwareSerial.h the buffer size to 100 characters because the sms header has more than 60 characters. I read the SofwareSerial buffer to a buffer also with 100 characters.

 

I have seen in the Arduino Tutorials some sketches where they use functions with several string functions like strstr(), strtok(), strcpy(), and didn't passe the pointer of the buffer read from the softwareSerial like the example below:

void loop() {
        // this is necessary because strtok() alters the array
        //   in this case replacing commas with \0
    strcpy(tempChars, receivedChars);
    parseData();
    showParsedData();
    delay(2000);
}
    
void parseData() {

    // split the data into its parts
 
  char * strtokIndx; // this is used by strtok() as an index
  strtokIndx = strtok(tempChars,",");      // get the first part - the string
  strcpy(messageFromPC, strtokIndx); // copy it to messageFromPC
  strtokIndx = strtok(NULL, ","); // this continues where the previous call left off
  integerFromPC = atoi(strtokIndx);     // convert this part to an integer
  strtokIndx = strtok(NULL, ","); 
  floatFromPC = atof(strtokIndx);     // convert this part to a float
}

void showParsedData() {
    Serial.print("Message ");
    Serial.println(messageFromPC);
    Serial.print("Integer ");
    Serial.println(integerFromPC);
    Serial.print("Float ");
    Serial.println(floatFromPC);
}

 

I have an Arduino book "Beguinning  Arduino" where they pass the buffer pointer to the functios, like below:

void loop() 
{ 
   if (Serial.available() > 0) {
      int index=0;
      delay(100); // let the buffer fill up
      int numChar = Serial.available();
      if (numChar>15) {
         numChar=15;
      }
      while (numChar--) {
         buffer[index++] = Serial.read();
      }
      splitString(buffer);
   }
}

void splitString(char* data) {
   Serial.print("Data entered: ");
   Serial.println(data);
   char* parameter; 
   parameter = strtok (data, " ,");
   while (parameter != NULL) {
      setLED(parameter);
      parameter = strtok (NULL, " ,");
}

 

 

I would like to know what is the correct approach. I am asking this because I have several functions using string functions and in 2 of them I do not pass the buffer string pointer and they work OK, but, After reading the book I passed the string buffer pointer and some times I have in the string buffer inside of the functions.

 

I would like to have your suggestions about this procedure/problem.

 

Thanks in advance.

Manuel

 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To be honest I've read that and I still don't really understand what you are asking (and the lack of other replies perhaps suggests that is true of others). Can you be more specific about what is/isn't working or what it is you are unsure about?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks Clawson for your reply,

 

What i am not sure is: when we read the (mySerial.read()) to a buffer string and later we need to use this string in another function to make a  strstr(), strtok(), strcpy(),

do we need to use a pointer like the code below?

 

I am confused because l also see sketchs in Arduino tutorials where the string buffer is used in another functions without the use of pointer  (you can see in the above examples). What is the correct way to do it? I have some times problems of printing erratic characters, I thought that the problem may be due to not use pointers in the functions as i follow the example above.

 

Thanks in advance.

Manuel 

void loop() 
{ 
   if (Serial.available() > 0) {
      int index=0;
      delay(100); // let the buffer fill up
      int numChar = Serial.available();
      if (numChar>15) {
         numChar=15;
      }
      while (numChar--) {
         buffer[index++] = Serial.read();
      }
      splitString(buffer);
   }
}

void splitString(char* data) {
   Serial.print("Data entered: ");
   Serial.println(data);
   char* parameter; 
   parameter = strtok (data, " ,");
   while (parameter != NULL) {
      setLED(parameter);
      parameter = strtok (NULL, " ,");
}

 

like

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If SoftwareSerial uses circular buffer you have to set buffer sizes as a power of 2 eg. 64 , 128 , 256(problematic with masking 8 bit 'pointers', but as i know arduino serials are using retarded 16 bit signed integers, so you are welcome)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JnK0le, thanks for your inputs.

 

I am going to change it for 128 and see what happens.

 

I continue to have doubts about pointers. I have seen in Arduino Tutorials some sketchs where is a string with characters received and it is used after in others functions without any pointer at the function cal like in the first post first example the function  void parseData(), in the second example of the first post you can see the function void splitString(char* data) using a pointer.

 

My question is are both correct? In the Arduino IDE environment are not needed the pointers?

 

Thanks and regards,

Manuel

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ManuelSilva wrote:
I continue to have doubts about pointers

See my previous reply about that: https://www.avrfreaks.net/comment...

 

Quote:
My question is are both correct? In the Arduino IDE environment are not needed the pointers?

You still haven't grasped the fact that an array name acts as a pointer to its first element.

 

Again, I illustrated this for you in my previous reply on the subject.

 

This is standard 'C' stuff - nothing specifically to do with Arduino.

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
Last Edited: Mon. Jun 8, 2015 - 09:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Awneil, thanks.

 

I understood it and I know that the name of array is the memory address of array[0]. What confused me was the example I read in an Arduino book.

 

I apologize to bother and thank you for being patient with me and remember me again the array name is the pointer, so, now I know I am writing the code correctly.

 

Regards,

Manuel

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is standard 'C' stuff - nothing specifically to do with Arduino.

One of the primary problems with Arduino as a "starter system" is that they are REALLY BAD at identifying which parts are "standard C stuff"; a lot of people end up thinking that they're using some new language, "based on C/C++"...

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

ManuelSilva wrote:
What confused me was the example I read in an Arduino book.

What book, exactly?

 

Can you show an actual example of where your confusion arises?

 

In software - as in any other form of engineering - there is often more than one way to do a thing; there is seldom a single "right" answer.

 

The fact that a certain book or tutorial chose to illustrate one way does not mean that other ways are "wrong".

 

The key difference between an actual pointer and an array name is that you can change what a pointer points to; but an array name will always and only ever point to element zero of the array.

 

char a_char;
char another_char;

char * a_pointer;

a_pointer = & a_char;        // The pointer now points to the first char variable

a_pointer = & another_char;  // The pointer now points to the other char variable

 

In other words, a pointer can appear on the left-hand side of an assignment.

 

 

Thus, if you want to be able to point to a number of different arrays (buffers), then a pointer might be needed. But, if you only have one array (buffer), you can just use its name.

 

 

 

 

 

 

To put it another 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

westfw wrote:
a lot of people end up thinking that they're using some new language, "based on C/C++"...

Indeed - that was my initial impression when I first came across it.

 

IMO, the whole thing of using special, non-standard terminology - "shields", "sketches", etc - is unhelpful; as you say, it gives the impression that there is something special and different from other "boards"/"modules" and normal "programs".

 

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

awneil wrote:
In other words, a pointer can appear on the left-hand side of an assignment.

In 'C' technical terms, it can be an lvalue; ie, something that can be assigned to.

 

But an array name can only ever be an rvalue; ie, something that can never be assigned to.

 

http://c-faq.com/misc/lvalue.html

 

http://c-faq.com/aryptr/aryptreq...

 

Top Tips:

  1. How to properly post source code - see: https://www.avrfreaks.net/comment... - also how to properly include images/pictures
  2. "Garbage" characters on a serial terminal are (almost?) invariably due to wrong baud rate - see: https://learn.sparkfun.com/tutorials/serial-communication
  3. Wrong baud rate is usually due to not running at the speed you thought; check by blinking a LED to see if you get the speed you expected
  4. Difference between a crystal, and a crystal oscillatorhttps://www.avrfreaks.net/comment...
  5. When your question is resolved, mark the solution: https://www.avrfreaks.net/comment...
  6. Beginner's "Getting Started" tips: https://www.avrfreaks.net/comment...
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

JnK0le, thanks for your inputs.

 

I am going to change it for 128 and see what happens.

Don't do that (in fact I'm pretty sure you won't know where/how anyway - as it happens it is "#define _SS_MAX_RX_BUFF 64 // RX buffer size"). The fact is that the Serial classes in Arduino have their own internal buffers and, if necessary, they are already suitably binary sized to easily handle the buffer wrap. That's hardly the point here is it?

 

The fact is that you should treat the serial class as a "black box" that just delivers characters to you (like getchar() in stdio). Sure, behind the scenes it's using interrupts and buffers for the implementation but the whole point of C++ is that you, the consumer is isolated from such details. In fact you cannot even "see" the buffers that are involved. That's all hidden behind the scenes.

 

Now on your side of the fence as a user of the class you may well be allocating your own strings or other arrays to receive the characters that are returned by the class - but as they are not "circular" there is no requirement that they be a multiple of 2 in length.

 

One thing I don't understand about the code you present in this thread is that your loop() consists of simply:

void loop() {
    strcpy(tempChars, receivedChars);
    parseData();
    showParsedData();
    delay(2000);
}

yet there is nothing in that interacting with the software serial class to actually populate the receivedChars array? Surely somewhere you have a function to use the instance.read() method to populate your own array? As I say that array can be whatever length you like as long as it can contain a complete "sentence".

 

As others have said once you have an array of chars you can treat it in whatever way you like. Use array or pointer notation depending on which you prefer. In C you can do all of this:

char text[] = "hello";
volatile char dest;

void fn1(char * data) {
  dest = *(data + 3);
  dest = data[3];
}

void fn2(char data[]) {
  dest = data[3];
  dest = *(data +3);
}

int main(void) {
  fn1(text);
  fn2(text);
}

They all write the 3rd character of the string to the destination. You can pass the array in as a pointer or an array and then you can use either pointer or array syntax to access the characters in the string.