Unexpected results from printing

Hi everyone.
I’m new on Arduino and C++.
I’m creating my own library for my project : This is the .cpp

#include "ss.h"
#include <stdlib.h> 
#include <Arduino.h>
#include <MemoryFree.h>

Ss::Ss(char* k){
	this->length = strlen(k);
	strcpy(this->string,k);
  this->string[length] = '\0';

}


Ss::~Ss(){
  free(this->string);
}

int Ss::lengthh(){
  this->length = strlen(this->string);
  return this->length;
}

int Ss::getlength(){
  return this->length;
}

char* Ss::getString(){
  return this->string;
}

void Ss::setString(char* k){
  strcpy(this->string, k);
  this->lengthh();
  this->string[strlen(k)] = '\0';
}

char Ss::charAt(int n){
	return this->string[n];

}


Ss& Ss::operator=( const Ss& other ) {
      length = other.length;
      //Serial.println(other.length);
      strcpy(string,other.string);
      string[length] = '\0';
      //Serial.println(string);
      return *this;
  }




void Ss::concatt(char* txt2){
  const int l1 = strlen(this->getString());
  const int l2 = strlen(txt2);
  char* var = this->getString();
  const int ltot = l1+l2;
  char txtconcat[ltot+1] ;
  strncpy(txtconcat,var,l1);
  txtconcat[l1] = '\0';
  strcat(txtconcat,txt2);
  txtconcat[l1+l2] = '\0';
  this->setString(txtconcat);
}




void Ss::substring( int n, char* gauc){
      char* intern = "";
      Ss gauche(intern);
      char* cl;
      for(int k=0; k<n; k++){
        char c = this->charAt(k);
        cl = &c;
        cl[1] = '\0';
        gauche.concatt(cl);
      }
      gauche.lengthh();
      gauc = (char*) "";
      strcpy(gauc, gauche.getString());
      //Serial.print(F("On est dans la fonction substring      ")); Serial.println(gauche.getString());
}

And here is the .h

#ifndef SS_H
#define SS_H

class Ss
{
	public:
		Ss(char*);
		~Ss();
		Ss& operator=( const Ss& other );

		int lengthh();
		char charAt(int );
		Ss* substringr(int );
		void substring(int, char*);
		void remove(int, int);
		void concatt(char*);


		char* getString();
		void setString(char*);
		int getlength();

	private:
		unsigned int length;
		char* string;


};

#endif

So I’ve been testing my functions especially substring() from the class Ss. I’m testing it with the following code :

#include <ss.h>

//#include <Lampe.h>
//#include <Motor.h>
#include <stdlib.h>


#include <Arduino.h>
#include <SoftwareSerial.h>
#include <MemoryFree.h>



void setup() {
  Serial.begin(9600);
  char* cc = "Bonjourj ca va et toiec?";
  Ss dd(cc);
  Ss* str = &dd;
  Serial.println(str->getString());
  //str->concatt(cc);
  Serial.println(getFreeMemory());
  char* azer;
  str->substring(5,azer);
  Serial.println(azer);
  Serial.println("COUCOU");


}

void loop() {

  delay(100000);

}

And I have something really weird on the Board :

I was expecting more this :

Bonjourj ca va et toiec?
1720
Bonjo
COUCOU

on the board. So I ran an other test with the following code : (same thing I just deleted the Serial.println(azer):wink:

#include <ss.h>

//#include <Lampe.h>
//#include <Motor.h>
#include <stdlib.h>


#include <Arduino.h>
#include <SoftwareSerial.h>
#include <MemoryFree.h>



void setup() {
  Serial.begin(9600);
  char* cc = "Bonjourj ca va et toiec?";
  Ss dd(cc);
  Ss* str = &dd;
  Serial.println(str->getString());
  //str->concatt(cc);
  Serial.println(getFreeMemory());
  char* azer;
  str->substring(5,azer);
  Serial.println(azer);
  Serial.println("COUCOU");


}

void loop() {

  delay(100000);

}

And now I have this on the Board:

I’m really new with pointers etc. I’m used to code on python. So I believe that it must be a pointer error or something, but I don’t really see it.

Thanks for reading and for your answers.
Have a good day :slight_smile:

Quick scan, I only see you making a char pointer. But you you never make room for an actual string. So writing to the pointer location will just crap up the memory.

void Ss::setString(char* k){
  strcpy(this->string, k);

string is NOT an array that you can write data to. It is a pointer to memory that you don't own. You can NOT change the amount of data in the pointed to location.

Your whole class is riddled with the assumption that you can add data to the end of a pointer, without knowing how much data the pointer initially pointed to.

Ok I see. But how do I affect a new char* to an object Ss ? Or how do I say that I free string and I put another char* into it ?

char c[41]={0}; //will hold a 40 character zero terminated string

Thanks jremington and PaulS

Is this ok if I write the constructor of my class like that ?

Ss::Ss(char* k){
  this->length = strlen(k);

  if (strlen(k)<5){
    const int lenn = 6;
    char c[lenn] ={0};
    strcpy(c,k);
    c[length] = '\0';
    this->string = c;
  }
  else if ((5<=strlen(k)) and (strlen(k)<10)){
      const int lenn = 11;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 50) and (strlen(k)>=10)){
      const int lenn = 50;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 100) and (strlen(k)>=50)){
      const int lenn = 100;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 150) and (strlen(k)>=100)){
    const int lenn = 150;
    char c[lenn] ={0};
    strcpy(c,k);
    c[length] = '\0'; 
    this->string = c;
  }
  else if ((strlen(k)< 200) and (strlen(k)>=150)){
     const int lenn = 200;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 250) and (strlen(k)>=200)){
     const int lenn = 250;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 300) and (strlen(k)>=250)){
     const int lenn = 300;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 350) and (strlen(k)>=300)){
     const int lenn = 350;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else if ((strlen(k)< 400) and (strlen(k)>=350)){
     const int lenn = 400;
      char c[lenn] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }
  else{
     Serial.println("CC");
     const int lenn = -1;
      char c[1] ={0};
      strcpy(c,k);
      c[length] = '\0';
      this->string = c;
  }

}

No, because after

  if (strlen(k)<5){
    const int lenn = 6;
    char c[lenn] ={0};
    strcpy(c,k);
    c[length] = '\0';
    this->string = c;
  }

The closing bracket c goes out of scope which leaves string again pointing to memory you don’t own (anymore)…

Thanks for your answer septillion ! I always forgot that what's in the bracket can only be used in the bracket So I should create one big buffer in order to not have this problem ? But if I do that I'll run out of memory very fast since I'm programing on Arduino Uno. And I will have later to treat String with 200 char ! Do you know any solutions?

Then you'll have to ask yourself, why do you want to first receive/create a string that can be 200 char long?

So there are no possibilities ? I guess it will be difficult then. I thought of creating one class for big string and another one for little strings. Do you think it would work or it's too complicated.

And if I treat 200 char long strings it's because at the end of my project, my arduino will have to control 5 motors. The informations will be comming from a computer and the data that "enters" Arduino will be dictionnaires with some infos. So I will have to treat long char strings.

You can do it dynamically but that will open a whole new can of worms...

But again to the 200 char string. What on earth are you all putting in that string? :D Even for 5 motors. I would think you can split that into smaller pieces which would be much more reasonable.

Ahah I've tried Dynamic allocation, probably very badly, but I heard that this is not good to do it with arduino because it would cause memory fragmentation.

Well for one motor I have this : But I will probably change it in order to have less chars :) 'm1':{'angle': 40,'speed':30,'direction':'LEFT','type':'SERVOS'} Anyway thanks a lot for your help !

Syndorik: because it would cause memory fragmentation.

That is indeed part of the can of worms and will happen if you do it wrong.

Syndorik: Well for one motor I have this : But I will probably change it in order to have less chars :) 'm1':{'angle': 40,'speed':30,'direction':'LEFT','type':'SERVOS'}

Alright, first, I don't see a real use for ''. You already separate name and value with a : and different parts with a ,.

Second, why can't you decode while receiving? Granted, the fact you group it per motor makes it a little harder. I would just split it into all separate short commands. "1:ang:40\n" "1:spd:30\n" "1:dir:L\n" etc

That way you have nice and easy to process bits, even when you don't do it on the fly.

Yes I think I will change what I'm sending first. And I'll try to do that comand per comand thing ! Hope it will work :D ! Again thanks a lot for your answers, it helped me a lot !