Arduino split char* based on delimiter to value - c++

thanks for your time, so I have a Char* from mqtt
I want to break this down into 3 seperate values
Char* mqttvalue
//Input Would be like the below for example.
mqttvalue = (255,200,230);
// I would like to split the values into the below.
int 1 = 255
int 2 = 200
int 3 = 230
I've tried strtok with no luck. probably something really dumb but some guidance would help.
Thank you
Edit, what I tried.
//Dummy Value for testing
Split("255,240,230");
//Split Value
void Split(char* e) {
String v[3];
char *p;
int i = 0;
p = strtok(e, ",");
while(p && i < 3)
{
v[i] = p;
p = strtok(NULL, ",");
Serial.println(p);
++i;
};
Serial.println(v[0]);
Serial.println(v[1]);
Serial.println(v[2]);
}

Updated the code to the below from a string to char* its all now working.
//Split Value
void Split(char* e) {
char* v[3];
char *p;
int i = 0;
p = strtok(rgb, ",");
while(p && i < 3)
{
v[i] = p;
p = strtok(NULL, ",");
i++;
};
Serial.println(v[0]);
Serial.println(v[1]);
Serial.println(v[2]);
};

As this is quite often asked question and I'd propose more like using wrapper class inheriting Stream interface on C string (and it can be initialized from Arduino String object too).
However usage with Arduino String class is tricky as the original String shouldn't be altered during usage of StringStream, but it's possible to reinitialize it again. Using rvalue (String literal, passed into the class) is forbidden by using non const reference as the parameter of setData method and constructor.
However it's not tested much, so there might be some mistakes. The copy/move constructor and assigment is ommited (and it shouldn't be :D), also using operator=(String&) and operator=(const char*) would be more intuitive interface for it.
class StringStream : public Stream
{
public:
StringStream()
{
setTimeout(1);
}
StringStream(const char * str)
{
setData(str);
}
StringStream(const char * begin, const char * end)
{
setData(begin, end);
}
explicit StringStream(String & view) // cannot be String literal (rvalue) and it gets invalidated if you change original String
{
setData(view);
}
////////////////////////////////////
inline void setData(const char * begin, const char * end)
{
m_start = begin;
m_end = end;
setTimeout(1);
}
inline void setData(const char * begin)
{
setData(begin, begin + strlen(begin));
}
inline void setData(String & view)
{
setData(view.c_str(), m_start + view.length());
}
//////////////////////////////////
// Stream Interface:
virtual int available() override
{
return m_end - m_start;
}
virtual int read() override
{
if (m_start < m_end)
{
return *(m_start++);
}
return -1;
}
virtual int peek() override
{
if (m_start < m_end)
{
return *m_start;
}
return -1;
}
virtual size_t write(uint8_t) override {
return 0;
}
protected:
const char * m_start{0};
const char * m_end{0};
};
And the test program would be like:
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println("Output:");
StringStream test{" 144, 7899, -5478"};
Serial.println(test.parseInt());
Serial.println(test.parseInt());
Serial.println(test.parseInt());
test.setData("1 2");
Serial.println(test.parseInt());
Serial.println(test.parseInt());
delay(2000);
}

Related

How to fix Segmentation Fault error when instantiating objects

I'm working to create a few classes that work together to simulate functions for a rental car agency. I have the classes working and I can create objects of each of the classes, but when I try to run the following code I get a segmentation fault and I'm not sure why. Why am I getting a segmentation fault when I declare the objects in this order?
I've tried switching the order in which I declare the objects and the error goes away. If I declare two cars with just the Car() constructor, then the problem also goes away. If I remove any of the functions in either the Car or Sensor class, the error goes away.
PS: I asked this question a few days ago, and I included way too much code because I couldn't identify the error (far from complete, minimal, and verifiable), but this time I've narrowed it down as far as I can. I apologize if it's a lot of code, but I've removed all the code I can and if I remove any more of it the problem goes away.
Here's my main file:
#include "Car.h"
int main() {
char make[] = "Subaru", model[] = "Outback", name[] = "Brandon",
type[] = "radar";
Sensor sensors[3];
Sensor sensor1 = Sensor(type), sensor2 = Sensor(), sensor3 =
Sensor();
sensors[0] = sensor1;
sensors[1] = sensor2;
sensors[2]= sensor3;
Car car1 = Car();
Car car2 = Car(make, 155.81, sensors);
return 0;
}
My Car class:
#ifndef CAR_H
#define CAR_H
#include <iostream>
#include "MyString.h"
#include "Sensor.h"
using namespace std;
#define MAX_STR_SIZE 256
#define MAX_NUM_SNSRS 3
class Car {
public:
Car();
Car(char* make, float baseprice, Sensor* sensors);
void setMake(char* make);
void setBaseprice(float baseprice);
void setAvailable(bool available);
void setOwner(char* owner);
void updatePrice();
private:
char m_make[MAX_STR_SIZE];
Sensor m_sensors[MAX_NUM_SNSRS];
int m_numsensors;
float m_baseprice;
float m_finalprice;
bool m_available;
char m_owner[MAX_STR_SIZE];
};
#endif
#include "Car.h"
Car::Car() {
char dflt[] = {'\0'};
setMake(dflt);
setAvailable(true);
setOwner(dflt);
m_numsensors = 0;
setBaseprice(0.0);
}
Car::Car(char* make, float baseprice, Sensor* sensors) {
char dflt[] = {'\0'};
setMake(make);
setAvailable(true);
setOwner(dflt);
for(int i = 0; i < MAX_NUM_SNSRS; i++) {
(*(m_sensors + i)) = Sensor(*(sensors + i));
if(myStringCompare((sensors + i)->getType(), "none") != 0) {
m_numsensors++;
}
}
setBaseprice(baseprice);
}
void Car::setMake(char* make) {
myStringCopy(m_make, make);
}
void Car::setBaseprice(float baseprice) {
m_baseprice = baseprice;
updatePrice();
}
void Car::setAvailable(bool available) {
m_available = available;
}
void Car::setOwner(char* owner) {
myStringCopy(m_owner, owner);
}
void Car::updatePrice() {
float totSnsrPrice = 0.0;
for(int i = 0; i < m_numsensors; i++) {
totSnsrPrice += (m_sensors + i)->getCost();
}
m_finalprice = m_baseprice + totSnsrPrice;
}
My Sensor class:
#ifndef SENSOR_H
#define SENSOR_H
#include "MyString.h"
#define MAX_STR_SIZE 256
#define NUM_TYPES 5
class Sensor {
public:
Sensor();
Sensor(char* type);
char* getType();
float getCost();
void setType(char* type);
void setCost(float extraCost);
private:
char m_type[MAX_STR_SIZE];
float m_extracost;
};
#endif
#include "Sensor.h"
const char* validSensors[] = {"gps", "camera", "lidar", "radar",
"none"};
const float prices[] = {5.0, 10.0, 15.0, 20.0, 0.0};
Sensor::Sensor() {
char dflt[] = "none";
setType(dflt);
setCost(0.0);
}
Sensor::Sensor(char* type) {
int index = -1;
char dflt[] = "none";
for(int i = 0; i < NUM_TYPES; i++) {
if(myStringCompare(type, *(validSensors + i)) == 0) {
index = i;
}
}
if(index < 0) {
setType(dflt);
setCost(0.0);
} else {
setType(type);
setCost(*(prices + index));
}
}
char* Sensor::getType() {
return m_type;
}
float Sensor::getCost() {
return m_extracost;
}
void Sensor::setType(char* type) {
myStringCopy(m_type, type);
}
void Sensor::setCost(float extracost) {
m_extracost = extracost;
}
myStringCopy and myStringCompare are just the typical std::string copy and compare functions, we're just not allowed to use them (they are include in MyString.h, I've been using them for a while, so I know they work as intended).
I expect the output to be nothing, but still successful, instead of a segmentation fault. I cannot find the error anywhere, any help would be appreciated. Thanks!
Edit: Here's my string class, as asked:
#ifndef MYSTRING_H
#define MYSTRING_H
int myStringCompare(const char* str1, const char* str2);
char* myStringCopy(char* destination, const char* source);
#endif
#include "MyString.h"
int myStringCompare(const char* str1, const char* str2) {
int index = 0;
while(*(str1 + index) != '\0' || *(str2 + index) != '\0') {
if(*(str1 + index) < *(str2 + index)) {
return -1;
}
if(*(str1 + index) > *(str2 + index)) {
return 1;
}
index++;
}
return 0;
}
char* myStringCopy(char* destination, const char* source) {
int index = 0;
while(*(source + index) != '\0') {
*(destination + index) = *(source + index);
index++;
}
*(destination + index) = '\0';
return destination;
}
We don't have the full details on your string class, so this is hard to reproduce.
However, when you call sensors[0] = sensor1; you are copying your Sensor, but haven't defined an assignment operator (or copy constructor for that matter).
You also do this in the Car constructor with
(*(m_sensors + i)) = Sensor(*(sensors + i));
Now without the full details of your string class, I can give suggestions that might help.
First, you are doing a lot of copying when you set up the senors.
You can collapse this
Sensor sensors[3];
Sensor sensor1 = Sensor(type), sensor2 = Sensor(), sensor3 =
Sensor();
sensors[0] = sensor1;
sensors[1] = sensor2;
sensors[2]= sensor3;
down to
Sensor sensors[3]={{type}, {}, {}};
This might not solve the problem, but is less to look at.
Next, remove the setters. You can use delegating constructors to tie the two you have together, and avoid these.
This avoids some copies.
Look very carefully at what gets deep or shallow copied.
If you have two char * types,
char * word = "Hello";
char * another_word = word;
the second is a "shallow" copy. You need an equivalent of strcpy to actually make a different ("deep") copy of the string.

Custom wxDataObject format for XML for copy-paste support

I am trying to implement a custom data object for XML strings, so that if it exists in the clipboard I can parse that accordingly. The code for the XMLDataObject is as follows:
class XMLDataFormat : public wxDataFormat
{
public:
XMLDataFormat() : wxDataFormat(wxT("XMLDataFormat")) {}
};
class XMLDataObject : public wxDataObjectSimple
{
public:
XMLDataObject(const wxString& xmlstring = wxEmptyString) : wxDataObjectSimple(), m_XMLString(xmlstring)
{
SetFormat(XMLDataFormat());
}
size_t GetLength() const { return m_XMLString.Len() + 1; }
wxString GetXML() const { return m_XMLString; }
void SetXML(const wxString& xml) { m_XMLString = xml; }
// Must provide overloads to avoid hiding them (and warnings about it)
size_t GetDataSize() const
{
return sizeof(void*); //or return GetLength()
}
bool GetDataHere(void *buf) const
{
char* c = _strdup(m_XMLString.c_str());
buf = (void*)c;
return true;
}
bool SetData(size_t len, const void* buf)
{
char* c = (char*)buf;
std::string stdString(c, len);
m_XMLString << stdString;
return true;
}
private:
wxString m_XMLString;
};
I send the data to clipboard (when user clicks copy) in the following fashion:
wxDataObjectComposite* dataobj = new wxDataObjectComposite();
dataobj->Add(new XMLDataObject("XML"));
if (wxTheClipboard->Open()) wxTheClipboard->SetData(dataobj);
wxTheClipboard->Close();
To get the data from the clipboard:
if (wxTheClipboard->Open()) {
XMLDataObject xmlObj;
wxTheClipboard->GetData(xmlObj);
if (xmlObj.GetLength() != 0) wxMessageBox(xmlObj.GetXML());
}
wxTheClipboard->Close();
When user clicks paste, I get weird characters instead of the text "XML". I realized that in the functions bool GetDataHere(void *buf) const and bool SetData(size_t len, const void* buf) the address of buf is different. I am not sure but maybe that is how it should be since Clipboard owns the data or behind the scenes wxWidgets is doing something.
By the way, I am using VS 2015 on Windows 10 and using wxWidgets 3.1.0.
Any suggestions is appreciated.
The following code so far has worked correctly:
class XMLDataFormat : public wxDataFormat
{
public:
XMLDataFormat() : wxDataFormat(wxT("XMLDataFormat")) {}
};
class XMLDataObject : public wxDataObjectSimple
{
public:
XMLDataObject(const wxString& xmlstring = wxEmptyString) : wxDataObjectSimple(), m_XMLString(xmlstring)
{
SetFormat(XMLDataFormat());
}
size_t GetLength() const { return m_XMLString.Len() + 1; }
wxString GetXML() const { return m_XMLString; }
void SetXML(const wxString& xml) { m_XMLString = xml; }
size_t GetDataSize() const
{
return GetLength();
}
bool GetDataHere(void *buf) const
{
//char* c = _strdup(m_XMLString.c_str()); not needed as per suggestion
memcpy(buf, m_XMLString.c_str(), m_XMLString.Len()+1);
return true;
}
bool SetData(size_t len, const void* buf)
{
//char* c = new char[len + 1]; not needed as per suggestion
//memcpy(c, buf, len); not needed as per suggestion
m_XMLString = wxString::FromUTF8((const char*)buf); //changed as per suggestion
//delete c;
return true;
}
virtual size_t GetDataSize(const wxDataFormat&) const
{
return GetDataSize();
}
virtual bool GetDataHere(const wxDataFormat&, void *buf) const
{
return GetDataHere(buf);
}
virtual bool SetData(const wxDataFormat&, size_t len, const void *buf)
{
return SetData(len, buf);
}
private:
wxString m_XMLString;
};
Any suggestions as to improve it is again appreciated.

strange segfault using template as parameter

I have a sorted list, which takes a Comparator as parameter. In a unit test I tried to use two different comparators.
The strange thing is, using the StringReverseComparator with the two if-statements disabled (commented out), all works well and valgrind does not claim any error.
template<typename T> class Comparator {
public:
virtual int compare(const T * left, const T * right) = 0;
};
class StringReverseComparator : public Comparator<String> {
public:
int compare(const String *left, const String *right) {
int rv = strcasecmp((const char *)*left, (const char *)*right);
if (rv < 0) return 10;
if (rv > 0) return -10;
return rv;
}
};
class StringComparator : public Comparator<String> {
public:
int compare(const String *left, const String *right) {
return strcasecmp(left->operator const char*(), right->operator const char*());
}
};
As soon as I enable both if-statements, I get a segfault from sort method.
Sort method is the standard qsort by sedgewick.
const char * is an operator from String class to access the character array.
First I thought, that changing the comparator might cause troubles, so I created a new instance of sorted list. But that traps too as soon as I have the two if-statements enabled.
So what's wrong with the compare method?
//edit:
Ok, first the sort code (taken from sedgewick):
template<typename T> class SortedList {
public:
// rest omitted
protected:
void sort() { qsort(0, _size - 1); }
void qsort(int left, int right) {
if (right > left) {
const T *v = _elements[right], *tmp;
int i = left-1;
int j = right;
for (;;) {
while (_comparator->compare(_elements[++i], v) < 0) ;
while (_comparator->compare(_elements[--j], v) > 0) ;
if (i >= j) break;
tmp = _elements[i];
_elements[i] = _elements[j];
_elements[j] = tmp;
}
tmp = _elements[i];
_elements[i] = _elements[right];
_elements[right] = tmp;
qsort(left, i-1);
qsort(i+1, right);
}
}
private:
int _size;
const T **_elements;
Comparator<T> *_comparator;
};
... and here the operator char *.
by the way: String class passed all unit tests and was ok with valgrind too.
class String {
public:
// rest omitted
operator const char * () const { return _s; }
const char * operator * () const { return _s; }
private:
char *_s;
};
about usage of strcasecmp: my first attempt was:
return strcasecmp( ... ) * (-1);
using the same parameters as in StringComparator. When that failed, I tried anything I could imagine about, including the if-statements and different call syntax of operator char *.
strcasecmp does not return just -1, 0, 1 - as mentioned in many tutorials. The return value differs in size and sign and after -1, 0, 1 failed to, I tried using 10. The value has no significance, could be 815 or 42, what ever.
// edith 2
Thanks you all for your attention!
I solved it myself. The point is, the qsort algo was not safe enuf :(
The following sort code works fine (with any kind of comparator):
void qsort(int left, int right) {
if (right > left) {
const T *v = _elements[right], *tmp;
int i = left-1;
int j = right;
for (;;) {
while (++i < _size && _comparator->compare(_elements[i], v) < 0) ;
while (--j > 0 && _comparator->compare(_elements[j], v) > 0) ;
if (i >= j) break;
tmp = _elements[i];
_elements[i] = _elements[j];
_elements[j] = tmp;
}
tmp = _elements[i];
_elements[i] = _elements[right];
_elements[right] = tmp;
qsort(left, i-1);
qsort(i+1, right);
}
}
Thanks.

How to pass struct to a class in c++? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I'm getting these results:
constructor
setFunc
setFunc
Basically I want my class-object globally and pass the struct array to setMethod of the class. and Program is successfully compiling but not getting any results.
DataInput.h
#ifndef DATAINPUT_H_
#define DATAINPUT_H_
#include <stdio.h>
struct Data{
const char *name;
int salary;
void set(int salary, const char *name){
printf("setFunc \n");
this->name = name;
this->salary = salary;
}
};
This class in a seprate cpp file with above header file
class DataInput {
public:
int dataSize;
struct Data data[];
DataInput();
virtual ~DataInput();
void setData(struct Data d[], int numberOfData);
void printData();
private:
};
#endif
-------eof----------
DataInput.cpp
#include "DataInput.h"
DataInput::DataInput() {
printf("constructor \n");
dataSize = 0;
}
DataInput::~DataInput() {
}
void DataInput :: setData(struct Data d[], int numberOfData){
dataSize = numberOfData;
for (int i = 0; i< numberOfData; i++){
printf("i-val in setData() --> %d",i);
this->data[i] = data[i];
}
}
void DataInput::printData(){
for (int i = 0; i< dataSize; i++){
printf("name--> %s \n",data[i].name);
printf("salary--> %d \n",data[i].salary);
}
}
--------eof-----------
main.cpp
#include <stdlib.h>
#include "DataInput.h"
#include <stdio.h>
DataInput *dataInput;
int main(void) {
DataInput in;
dataInput = &in;
struct Data d[2];
d[0].set(1000, "ABC");
d[1].set(2000, "XYZ");
dataInput->setData(d, 2); //not setting data
dataInput->printData(); //not printing
return 0;
}
Note: May not compile, is just illustrative
Few things:
DataInputconstructor do not reserve space for new items. So, this->data[i] = data[i]; result is undefined.
This is C++, Rule of three, strings, ....
struct Data
{
std::string name;
int salary;
Data(const std::string & n, int s);
Data & operator=(const Data & d);
};
Data::Data(const std::string & n, int s) :
name(n), salary(s)
{
}
Data & Data::operator=(const Data & d)
{
name = d.name;
salary = d.salary;
return *this;
}
Use standards containers:
class DataInput
{
private:
std::vector<Data> data;
public:
DataInput();
virtual ~DataInput();
// you don't need use size
void setData(const std::vector<Data> & d);
void printData();
};
void DataInput::setData(const std::vector<Data> & d)
{
data = d;
}
void DataInput::printData()
{
for (std::vector<Data>::iterator it = data.begin(); it != data.end(); ++it)
{
std::cout << it->name << ":" << it->salary << std::endl;
}
}
Now, you can use it from main (without pointers):
int main(void)
{
DataInput in;
std::vector<Data> d;
d.push_back(Data(1000, "ABC"));
d.push_back(Data(2000, "XYZ"));
dataInput.setData(d); // yes setting data
dataInput.printData(); // yes printing
return 0;
}
Do a memcpy of the entire array, just assigning the data might lead to memory leaks due to stack frame removal or deletion. This way however you lose the logging simultaneously avoiding the for loop increasing performance
void DataInput :: setData(const struct Data const* d, const int numberOfData) {
// Cleanup old data!
if(this->data) delete [] this->data;
if(!d) throw new std::invalid_argument("Cannot set NULL data!"); // Remove this line if NULL may be assigned and replace with the commented code.
// if(!d) {
// this->data = NULL;
// this->dataSize = 0;
// } else {
this->data = new Data[(this->dataSize = numberOfData)];
memcpy(this->data, d, sizeof(struct Data) * numberOfData);
// }
}
Don't forget to update the DataInput class!
class DataInput {
public:
int dataSize;
struct Data* data;
DataInput();
virtual ~DataInput();
void setData(const struct Data const* d, const int numberOfData);
void printData();
private:
};
void DataInput::printData() {
for (int i = 0; i< this->dataSize; i++){
printf("name--> %s \n",this->data[i].name);
printf("salary--> %d \n",this->data[i].salary);
}
}
DataInput::~DataInput() {
if(this->data) delete [] this->data;
}

How to pass child object in the method

I am parsing the child object to a method but my child data is lost. Please tell how to parse the object without loosing its data.
class A
{
int size;
std::string name;
public:
A(const std::string &name, int &size){}
virtual B *C();
}
function D()
{
int size = 10;
std::string name = "name";
return new A(name , size);
}
B *A::C(){
\\here I need name and size
}
Write now the value of size it give is 0 instead of 10 and for name it give segmentation fault
Thanks 4 the help in advance
UPDATE 1
the abstract of my code
class PrototypeAST
{
int size;
std::string FnName;
std::vector<std::string> ArgNames;
public:
PrototypeAST(const std::string &fnName, const std::vector<std::string> &argNames, int &size)
: FnName(fnName), ArgNames(argNames) {}
Function *Codegen();
void CreateArgumentAllocas(Function *F);
};
static PrototypeAST *ParsePrototype() {
int size;
std::string FnName = IdentifierStr;
getNextToken();//eat id1
std::vector<std::string> ArgNames;
if(CurTok != ')' )
{
getNextToken(); //eat int
ArgNames.push_back(IdentifierStr);
getNextToken();// eat id
while (CurTok == ',')
{
getNextToken(); //eat ,
getNextToken(); //eat int
ArgNames.push_back(IdentifierStr);
getNextToken();// eat id
}
}
// success.
getNextToken(); // eat ')'.
size = ArgNames.size();
return new PrototypeAST(FnName, ArgNames, size);
}
Function *PrototypeAST::Codegen() {
printf("\nI am in prototypeAST function\n");
// Make the function type: double(double,double) etc.
std::vector<Type*> Doubles(size,
Type::getInt1Ty(getGlobalContext()));
printf("\nI am in prototypeAST function's 1\n");
FunctionType *FT;
if(isFunInt)
FT = FunctionType::get(Type::getInt1Ty(getGlobalContext()),
Doubles, false);
else if(isFunVoid)
FT = FunctionType::get(Type::getInt1Ty(getGlobalContext()),
Doubles, false);
printf("\nI am in prototypeAST function's 2\n");
Function *F = Function::Create(FT, Function::ExternalLinkage, FnName, TheModule);
printf("\nI am in prototypeAST function's 3\n");
// If F conflicted, there was already something named 'Name'. If it has a
// body, don't allow redefinition or reextern.
if (F->getName() != FnName) {
// Delete the one we just made and get the existing one.
F->eraseFromParent();
F = TheModule->getFunction(FnName);
}
// Set names for all arguments.
unsigned Idx = 0;
for (Function::arg_iterator AI = F->arg_begin(); Idx != ArgNames.size();
++AI, ++Idx) {
AI->setName(ArgNames[Idx]);
}
printf("\nI am in prototypeAST function\n");
return F;
}
As others have pointed out in the comments, you should have looked at the empty constructor. You are not setting the values of the data members in the constructor. That is why the error.
PS: Do familiarize with Stack Overflow question checklist. Happy learning.
I have got what you wanna do. Here is the way to do it.
The empty constructor was making the problem. You can initialize your parameter with the value return by the function in following manner.
class A
{
int Size;
std::string Name;
public:
A(const std::string &name, int &size):Name(name), Size(size) {}
virtual B *C();
}
A *D()
{
int size = 10;
std::string name = "name";
return new A(name , size);
}
B *A::C(){
\\here I need name and size
}