Dealing with strings on Arduino

Hello,

Im kinda new to Arduino and C++. Tutorials on arduino.cc or the rest of internet is just ok for what I did until now.
Problem now is that i need string manipulation and cant find anything about the matter. Tried lot of C++ code on strings but they seem not working (like str.size() e.g. and a bunch of other things).

Im stucked trying to clear a char type variable,

Im declaring like: 'char test[3] = "ab";' and further on code i need to override the value, tried like 'test = "cd";' and 'char test[3] = "cd";' and 'test[3] = "cd";' nothing work. The usual test.clear() do not work aswell.

There´s any library i must specify to have string manipulation facilities? If so i must download such library?

Anyway, how to clear or reassign such a variable?

Thanks,

Rodrigo

PString ?

http://arduiniana.org/libraries/PString/

Rodrigo,

Try this:

#include <string.h>

char test[10] = "abc";

...

strcpy(test,"def");

The C string functions are documented here: avr-libc: <string.h>: Strings

One thing to be careful of: always make sure that the character array is big enough to hold all of the characters, plus one more for the terminating NUL character.

Regards,

-Mike

Hello mfm9 and Mitch,

Thanks Mitch for the library reference, that sounds absolutely useful ! Other library that sounds interesting too, on that same page, is : Streaming | Arduiniana

Thanks Mitch for the tip and the useful link. Actually I solved the issue doing the follow:
Declared the char type like: 'char allhour[60];' and if I do 'char allhour[60] = "" ;' it clears the string.

But there´s one thing that´s annoying me, because i cant find the logic behind.

The command 'char allhour[60] = "" ;' works if it´s placed in the beginning of the loop sequence, but don't if placed at the end of the loop sequence. I cant find any logical explanation for this. I would call this a bug, unless there´s a very exotic explanation behind the fact.

In the sketch I added commented lines to show you what Im talking about:

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h> 

int minute = 0;
int hour = 0;

int hourT;
int minuteT;
int secondT;
int dayT;
int monthT;
int yearT;
char hourS[5];
char minuteS[5];
char secondS[5];
char allhour[60];
char te[4] ;

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


void loop() {
  
  
////// THIS WORKS ////////    
char allhour[60] = "" ;
/////   THIS WORKS //////

hourT = (RTC.get(DS1307_HR,true)) ;
minuteT = (RTC.get(DS1307_MIN,false)) ;
secondT = (RTC.get(DS1307_SEC,false));
dayT = (RTC.get(DS1307_DATE,false));
monthT = (RTC.get(DS1307_MTH,false));
yearT = (RTC.get(DS1307_YR,false));

itoa(hourT, hourS, 10);
itoa(minuteT, minuteS, 10);
itoa(secondT, secondS, 10);

if (strlen(hourS) < 2) { char te[4] = "0" ; strcat(te, hourS);  strcpy (hourS, te); }
if (strlen(minuteS) < 2) { char te[4] = "0" ; strcat(te, minuteS);  strcpy (minuteS, te); }
if (strlen(secondS) < 2) { char te[4] = "0" ; strcat(te, secondS);  strcpy (secondS, te); }

strcat(allhour, hourS) ;
strcat(allhour, "/"); 
strcat(allhour, minuteS); 
strcat(allhour, "/"); 
strcat(allhour, secondS);
Serial.println(allhour); 

 delay(1000);
// char allhour[60] = "" ; <------------------- This dont work

  }

Executing this sketch i have normal result like:

02/06/36
02/06/37
02/06/38
02/06/39
02/06/40
02/06/41
02/06/42

But changing the place of 'char allhour[60] = "" ;' the result i get is:

02/03/36
02/03/3602/03/37
02/03/3602/03/3702/03/38
02/03/3602/03/3702/03/3802/03/39
02/03/3602/03/3702/03/3802/03/3902/03/40
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/42
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/4202/03/43
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/4202/03/4302/0n/44A

This is weird enough. Maybe this is something proving that dealing with strings on Arduino is a knightmare ? Im not a skilled programmer so far but now this reaction in the code looks non-sense to me.

Clues ?

Regards,

Rodrigo

You have two allhour[60] variables declared. The global one declared on line 17. And a local one declared again in the main loop; either at the "// this works" or the "// this don't [doesn't] work" comments.

The compiler is following the correct rules for variable scope. You should remove your duplicate declarations.

Hello Mitch,

Im not sure if I got it.
And to be more clear:

The code:

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

int minute = 0;
int hour = 0;

int hourT;
int minuteT;
int secondT;
int dayT;
int monthT;
int yearT;
char hourS[5];
char minuteS[5];
char secondS[5];
char allhour[60];
char te[4] ;

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


void loop() {
  
  
    
char allhour[60] = "" ; //// DECLARATION IS HERE ////


hourT = (RTC.get(DS1307_HR,true)) ;
minuteT = (RTC.get(DS1307_MIN,false)) ;
secondT = (RTC.get(DS1307_SEC,false));
dayT = (RTC.get(DS1307_DATE,false));
monthT = (RTC.get(DS1307_MTH,false));
yearT = (RTC.get(DS1307_YR,false));

itoa(hourT, hourS, 10);
itoa(minuteT, minuteS, 10);
itoa(secondT, secondS, 10);

if (strlen(hourS) < 2) { char te[4] = "0" ; strcat(te, hourS);  strcpy (hourS, te); }
if (strlen(minuteS) < 2) { char te[4] = "0" ; strcat(te, minuteS);  strcpy (minuteS, te); }
if (strlen(secondS) < 2) { char te[4] = "0" ; strcat(te, secondS);  strcpy (secondS, te); }

strcat(allhour, hourS) ;
strcat(allhour, "/");
strcat(allhour, minuteS);
strcat(allhour, "/");
strcat(allhour, secondS);
Serial.println(allhour);

 delay(1000);


  }

Works as desired, returning values like:

02/06/36
02/06/37
02/06/38
02/06/39
02/06/40
02/06/41
02/06/42

And the code:

#include <WProgram.h>
#include <Wire.h>
#include <DS1307.h>

int minute = 0;
int hour = 0;

int hourT;
int minuteT;
int secondT;
int dayT;
int monthT;
int yearT;
char hourS[5];
char minuteS[5];
char secondS[5];
char allhour[60];
char te[4] ;

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


void loop() {
  

hourT = (RTC.get(DS1307_HR,true)) ;
minuteT = (RTC.get(DS1307_MIN,false)) ;
secondT = (RTC.get(DS1307_SEC,false));
dayT = (RTC.get(DS1307_DATE,false));
monthT = (RTC.get(DS1307_MTH,false));
yearT = (RTC.get(DS1307_YR,false));

itoa(hourT, hourS, 10);
itoa(minuteT, minuteS, 10);
itoa(secondT, secondS, 10);

if (strlen(hourS) < 2) { char te[4] = "0" ; strcat(te, hourS);  strcpy (hourS, te); }
if (strlen(minuteS) < 2) { char te[4] = "0" ; strcat(te, minuteS);  strcpy (minuteS, te); }
if (strlen(secondS) < 2) { char te[4] = "0" ; strcat(te, secondS);  strcpy (secondS, te); }

strcat(allhour, hourS) ;
strcat(allhour, "/");
strcat(allhour, minuteS);
strcat(allhour, "/");
strcat(allhour, secondS);
Serial.println(allhour);

 delay(1000);

char allhour[60] = "" ; //// DECLARATION IS NOW HERE ////

  }

Dont work as desired as:

02/03/36
02/03/3602/03/37
02/03/3602/03/3702/03/38
02/03/3602/03/3702/03/3802/03/39
02/03/3602/03/3702/03/3802/03/3902/03/40
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/42
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/4202/03/43
02/03/3602/03/3702/03/3802/03/3902/03/4002/03/4202/03/4302/0n/44A

Point is that in both cases the char type is declared twice, as you said, but in one case it works but dont for the second case. See that the only difference between the two codes is that in the first code, 'char allhour[60] = "" ; ' is the first command of void loop() and in the second code, 'char allhour[60] = "" ; ' is the last command of void loop().

The logic says to me that if a command is explicit as the very first of void loop() or if explicit as latest one, cant alter your final result. Considering that void loop() keeps cycling until you turn Arduino off or reset.

The only thing i can imagine is that after loop sequence restart, something change, some buffer is cleared or anything else that i really dont know. Or even: Im just too stupid to state what´s going on :smiley:

Rodrigo,

Mitch is right about the scope -- in other words, which part of your program "sees" which variable.

In addition, you should understand the difference between an assignment and a declaration with an initializer. It's confusing, because both use the '=' symbol.

When you have a declaration, like:char x[10];the compiler is allocating space for ten characters. When you have a declaration with an initializer, like:char x[10] = "abcdefghi";the compiler is allocating space for ten characters, and arranging for them to be filled with the values you specified.

When you have an assignment statement, like:x[0] = 'z';your program sets the first element of the array to 'z'. Unfortunately, there is no assignment statement in C that can initialize all of the positions in a character array. If you say:x[10] = "abcdefghi"; // this won't compile you'll get a syntax error.

Because of the scoping rules, when you do a declaration, the variable you declared will only be used by code in the same block as the declaration. It's considered bad programming practice to redeclare a variable with the same name as previously declared, because it makes the code very confusing. Without careful reading, it is difficult to determine which variable the statements in your program are referring to.

Summary: Declare the character array only once, with an initializer if you like. If you need to change it, use a string function like strcpy(), or change the characters in the array one at a time.

Regards,

-Mike

The strcat function appends data onto the end of a string. It does this by searching through the characters in the array, looking for a NULL. The new characters replace the NULL, and the following characters. The strcat function adds a new NULL at the end of the new characters.

That way, multiple calls to strcat keep adding on to the end.

To make strcat start at the beginning again, you need to set the first character in the array to NULL, when you want to begin again.

char allHour[60];

void loop()
{
   allHour[0] = '\0'; // Initialize the string to 0 length

   // Get the bits that make up the time strings

   strcat(allhour, hourS) ;
   strcat(allhour, "/");
   strcat(allhour, minuteS);
   strcat(allhour, "/");
   strcat(allhour, secondS);
   Serial.println(allhour);
}

Thanks all for the clarifications,

Things start making sense for me now.