Go Down

Topic: Do I need a special library for strcpy and strcat (Read 16908 times) previous topic - next topic

acboother

Here is a test mule like i suggest

Code: [Select]
char coords[127];

#define COORDSSIZ 20  // change this to see what happens to your variables
                      // lat and lon
                      // this has to be big enough for the string AND the NULL
                      // terminator

char lat[COORDSSIZ];
char lon[COORDSSIZ];

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

  // let's start with clearing the memory where we are
  // working as otherwise it will contain rubbish, probably
  // from the previous run which would be very confusing
  memset(&coords, 0 , sizeof(coords));
  memset(&lat, 0 , sizeof(lat));
  memset(&lon, 0 , sizeof(lon));

  // check what we've got before we do anything
  Serial.print("LAT\t");
  Serial.print(lat);
  Serial.print("\t");
  Serial.println(strlen(lat)); 

  Serial.print("LON\t");
  Serial.print(lon);
  Serial.print("\t");
  Serial.println(strlen(lon));

  // confirm the output is ready
  Serial.print("COORDS\t");
  Serial.print(coords);
  Serial.print("\t");
  Serial.println(strlen(coords));

  // simulate the function call that populates the variables
  getPar(lon,lat);
 
  // do the good stuff
  /* can also try with strcat if you variables lat and lon have a NULL terminator
  strcat(coords, lat);
  strcat(coords, lon);
  */
 
  strncat(coords, lat, COORDSSIZ);   
  strncat(coords, lon, 50);    //lat isn't 50 long so only does lat length 
   

  // look at our results
  Serial.print("COORDS\t");
  Serial.print(coords);
  Serial.print("\t");
  Serial.println(strlen(coords));
}

void loop() {

}

char getPar(char *str_long, char *str_lat)
{
  strcpy(str_lat, "a234567890.23b");
  strcpy(str_long, "c234567890.23d");

  return 0;
}


And it seems to work - here's the output
Code: [Select]
LAT 0
LON 0
COORDS 0
COORDS a234567890.23bc234567890.23d 28


I guess you have an issue elsewhere in your code as this is I think essentially your code that you think is not working.

UKHeliBob

Quote
I can not hardly code this {"712.585044"};

I was trying to make the point that concatenating the strings works as long as what you supply are strings and the destination array is big enough.  You have now posted your whole code so there may be be more progress in solving your problem.
Please do not send me PMs asking for help.  Post in the forum then everyone will benefit from seeing the questions and answers.

PeterH


Try simulating the problem with a piece of code that has the essential parts that you think are 'faulty' including a simulated call to this function.


That's excellent advice.

Also, now that you have narrowed the problem down to a block of code, narrow it down further to the individual statement that causes it. The symptoms all point to an unterminated string or a buffer overflow, but I can't see anything in the code that would cause that with the same data you posted. So, take acboother's advice and write a test sketch that reproduces the problem using the data values that you think you're getting when the problem occurs. I have a sneaking suspicion you'll find that wasn't actually the data that produces the problem, but you're only dealing with a dozen lines of code to concatenate a few char arrays, and if the problem really is happening here as it seems, you should be able to reproduce it in a trivial sketch that we can all review and run for ourselves. Once you get into that situation, it should only take a few seconds to figure out what's causing the problem.

pierrot10

Thank for all, for all of your suggesrion.

I am very happy, because I got a success solution but not at 100%. There is a little bug at the end, but I am on a good solution.

I modify my code, as the following:
I move the initialisation of char coords[]; to the getGPSCoords() function
Code: [Select]

void getGPSCoords(){
  /*
  memset(&coords, 0 , sizeof(coords));
  memset(&lon, 0 , sizeof(lon));
  memset(&lat, 0 , sizeof(lat));
  memset(&alt, 0 , sizeof(alt));
  memset(&time, 0 , sizeof(time));
  memset(&vel, 0 , sizeof(vel));
  */
 
// Get static on GPS status/availability
  #ifdef DEBUG
    stat=gps.getStat();
    if(stat==1){
      Serial.println("NOT FIXED");
    }else if(stat==0){
      Serial.println("GPS OFF");
    }else if(stat==2){
      Serial.println("2D FIXED");
    }else if(stat==3){
      Serial.println("3D FIXED");
    }
    delay(5000);
  #endif   
 
  //Get data from GPS
   gps.getPar(lon,lat,alt,time,vel);

  #ifdef DEBUG
    // I check if the the variable are filled and display the length
    Serial.print(lon); Serial.print(" "); Serial.println(strlen(lon));
    Serial.print(lat); Serial.print(" "); Serial.println(strlen(lat));
    Serial.print(alt); Serial.print(" "); Serial.println(strlen(alt));
    Serial.print(vel); Serial.print(" "); Serial.println(strlen(vel));
    Serial.print(time); Serial.print(" "); Serial.println(strlen(time));
    Serial.println("-----");
  #endif
 
   char lo[]="lo=";
   char la[]="&la=";
   char al[]="&al=";
   char ti[]="&ti=";
   char ve[]="&ve=";
 
   // Count the number of caracter of the coords + the string, which are now, type of char (and not string any more)
   int le = strlen(lo)+strlen(la)+strlen(al)+strlen(ti)+strlen(ve)+strlen(lon)+strlen(lat)+strlen(alt)+strlen(vel)+strlen(time);
   // Disèplay the number of caracter
   Serial.println(le);
// Iniatiate the coords with the exact number of caracter, whatever if lat, lon, alt change of length
// Add +1 for the terminator
  char coords[le+1];

  // Concatenate all char varaiable
  strcpy(coords,lo);
  strcat(coords,lon);

  strcat(coords,la);
  strcat(coords,lat);
 
  strcat(coords,al);
  strcat(coords,alt);

  strcat(coords,ti);     
  strcat(coords,time);   
 
  strcat(coords,ve);     
  strcat(coords,vel);
 
  #ifdef DEBUG
    Serial.print(F("Coords : "));                               
    Serial.println(coords);
    Serial.println(strlen(coords));
  #endif
 

}


I am very happy, because coords display the correct value. here is my display:
I am in a train and I can not get fix, It's the reason why we have 0.000000, but it does not matter, for my issue
Quote

GETTING GPS COORDS
--------------------------------
In progress, wait...
NOT FIXED
0.000000 8
0.000000 8
0.000000 8
0.000000 8
20130714223032.000 18
-----
(the lenght of char lo, la, al, ti and ve are not display here)
69
Coords : lo=0.000000&la=0.000000&al=0.000000&ti=20130714223032.000&ve=0.000000


Code: [Select]
The last problem:
After, the terminal display the result of
Quote

Coords : lo=0.000000&la=0.000000&al=0.000000&ti=20130714223032.000&ve=0.000000

the program stop working, like if it freeze.
Would you have an idea, why it freeze juste at the "end"?
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

acboother

I think you re still on sticky ground.

Code: [Select]
  char coords[le+1];

le is a runtime variable but the compiler allocates space at compile time. I'm sure this would be bad in C but maybe in C++ this is okay (I am rusty.

Do some more tests just to be sure and possible be more explicit about your allocation perhaps with a malloc()

See here...


Code: [Select]
Assume you have variable size as a variable (it is NOT defined as constant). The compiler will give you an error if you try this:
BOTH VERSIONS

int array[size];


What you can do is allocate this memory dynamically. For example:
C VERSION:
1
2
int *array;
array=(int *) malloc(size*sizeof(int));

C++ VERSION:
1
2
int *array;
array=new int[size]l



taken from http://www.cplusplus.com/forum/articles/416/



AWOL

Quote
le is a runtime variable but the compiler allocates space at compile time.

No, it's an automatic variable in a function, so the array is sized according to the value of "le".

pierrot10

#36
Jul 15, 2013, 10:23 am Last Edit: Jul 15, 2013, 10:30 am by pierrot10 Reason: 1
Dear All,
I modified my code in order to have a terminator (\0).
I do niot know if it's a good reasonnement, ans I could not try it yet. But do you think it can be solve the issue?
(I will try later in the day, as soon as I can)

Code: [Select]

void getGPSCoords(){
  /*
  memset(&coords, 0 , sizeof(coords));
  memset(&lon, 0 , sizeof(lon));
  memset(&lat, 0 , sizeof(lat));
  memset(&alt, 0 , sizeof(alt));
  memset(&time, 0 , sizeof(time));
  memset(&vel, 0 , sizeof(vel));
  */
 
  #ifdef DEBUG
    stat=gps.getStat();
    if(stat==1){
      Serial.println("NOT FIXED");
    }else if(stat==0){
      Serial.println("GPS OFF");
    }else if(stat==2){
      Serial.println("2D FIXED");
    }else if(stat==3){
      Serial.println("3D FIXED");
    }
    delay(5000);
  #endif   
 
  //Get data from GPS
 
   gps.getPar(lon,lat,alt,time,vel);

 
  char lo[]="lo=";
  char la[]="&la=";
  char al[]="&al=";
  char ti[]="&ti=";
  char ve[]="&ve=";
  char en[]="\0"; // NEW ADD

#ifdef DEBUG
    // I check if the the variable are filled and display the length
    Serial.print(lon); Serial.print(" "); Serial.println(strlen(lon));
    Serial.print(lat); Serial.print(" "); Serial.println(strlen(lat));
    Serial.print(alt); Serial.print(" "); Serial.println(strlen(alt));
    Serial.print(vel); Serial.print(" "); Serial.println(strlen(vel));
    Serial.print(time); Serial.print(" "); Serial.println(strlen(time));
    Serial.print(lo); Serial.print(" "); Serial.println(strlen(lo));
    Serial.print(la); Serial.print(" "); Serial.println(strlen(la));
    Serial.print(al); Serial.print(" "); Serial.println(strlen(al));
    Serial.print(ti); Serial.print(" "); Serial.println(strlen(ti));
    Serial.print(ve); Serial.print(" "); Serial.println(strlen(ve));
    Serial.print(en); Serial.print(" "); Serial.println(strlen(en));
    Serial.println("-----");
  #endif
 
  int le = strlen(lo)+strlen(la)+strlen(al)+strlen(ti)+strlen(ve)+strlen(en)+strlen(lon)+strlen(lat)+strlen(alt)+strlen(vel)+strlen(time);
  Serial.println(le);

  char coords[le]; // NEW CHANGE

  strcpy(coords,lo);
  strcat(coords,lon);

  strcat(coords,la);
  strcat(coords,lat);
 
  strcat(coords,al);
  strcat(coords,alt);

  strcat(coords,ti);
  strcat(coords,time);
 
  strcat(coords,ve);
  strcat(coords,vel);
 
  strcat(coords,en); // NEW ADD
 
 
  #ifdef DEBUG
    Serial.print(F("Coords : "));                               
    Serial.println(coords);
//   Serial.println(strlen(coords));
  #endif
 

}
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

AWOL

Your debug prints seem to be quite inconsistent - sometime you use the F() macro, other times not.
Is DEBUG enabled?
It could be part of your problem.

pierrot10

All right, I do not belive!!!!

I think my problem is solved. So I just tried and it works since I make those change

1) I make all Serial.print to use the F() macro
2) I added char en[]="\0"; as I wrote before

I still can get fis from my GPS antena, because I am in a "heavy" buildig, but I am unpatient to try the code while I will be able to get gps fix.

I hope it is definitivly solved.

Thank for all, all, and all
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

PeterH


2) I added char en[]="\0"; as I wrote before


I can't be sure without seeing your code, but that looks very wrong to me. It defines a char array of length one containing a null value - which is utterly pointless.

AWOL

Quote
It defines a char array of length one containing a null value

No, it it's a char array of length 2, containing two nulls.

pierrot10

#41
Jul 15, 2013, 01:32 pm Last Edit: Jul 15, 2013, 01:36 pm by pierrot10 Reason: 1
Hello,

But at the end, this
Code: [Select]

char en[]="\0";

is good? I am confuse because it work...

I have a last question.

I declare the function, in that way, now, because I want it to return an array

Code: [Select]
char * getGPSCoords(void){
// coords is an array, I will not write all code

return coords;

}

Somewhere else in my code, I do this
Code: [Select]
Serial.println(getGPSCoords());

And it print the right value.

But when I want to copy the retun of getGPSCoords() into a char, like this
Code: [Select]

// To get the size of the return value
    int i = strlen(getGPSCoords());
// Define the size of value
  char value[i];
strcpy(value,getGPSCoords()); 
//value = getGPSCoords();
Serial.println(value);


value display nothing while Serial.println(getGPSCoords()); displays the right value.

However, I add a * at the function, like this
char * getGPSCoords(void){}

What did I wrong to use the return char value in a other function ? :smiley-mr-green:

Here is the function I need to use
Code: [Select]

inet.httpPOST(host, port_post, path_post, value , "Result", 1000);

I also try this, which would be the best
Code: [Select]

inet.httpPOST(host, port_post, path_post, getPGSCoords() , "Result", 1000);


Thank
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

AWOL

Code: [Select]
But at the end, this
Code:

char en[]="\0";

is good? I am confuse because it work...

Does it work, or does it appear to work?
The two are not the same.

I can't see the context, but by itself as you have shown it, the construct looks pretty pointless to me.

pierrot10

It's works. So the Serial.print() display what I am waiting for but as I am a beginer, I am suspicious  :)
Il ne suffit pas de tout savoir, la persévérance, c'est déjà presque tout!
You can not know everything, perseverance, it is almost everything!

PaulS

Quote
It's works. So the Serial.print() display what I am waiting for but as I am a beginer, I am suspicious

But, the strcpy() and then Serial.print() doesn't, so your definition of "works" is flawed.

If a function is to return a pointer to an array of chars, that pointer needs to point to something that will persist after the function ends. If the function calls malloc() to allocate memory, that memory will persist after the function ends, and returning a pointer to it is perfectly valid.

If the function simply declares an array on the stack, that memory will NOT persist after the function ends, so returning a pointer to it is not legal. It may, or may not be immediately overwritten. So, it may appear to "work", but it doesn't really.
The art of getting good answers lies in asking good questions.

Go Up