I'm trying convert vector to char * for send by socket
the type of T is a simple struct
struct CategoryStruct {
int ID;
char name[32];
};
std::vector<CategoryStruct> categories;
Function, where I'm trying to convert -
char * Category::decodeCategoryToCharArray()
{
int structSize = sizeof(CategoryStruct),
currentByte = 0,
i = 0;
if(decoded)
delete [] decoded;
decoded = new char[structSize * categories.size()];
std::vector<CategoryStruct>::iterator start, end;
start = categories.begin();
end = categories.end();
for(; start != end; start++, i++)
{
memcpy(decoded+currentByte, &categories[i], structSize);
currentByte += structSize+1;
}
return decoded;
}
End return will be ""
There's no need for conversion, std::vector<CategoryStruct> already stores the data in a contigous memory area. so your function could be boiled down to
std::vector<CategoryStruct> categories;
char * Category::decodeCategoryToCharArray()
{
return reinterpret_cast<char*>(categories.data());
}
Related
I have two structure
struct TbtStreamHeader
{
short MsgLen;
short StreamId;
int SeqNo;
TbtStreamHeader()
{
MsgLen = StreamId = 0;
SeqNo = 0;
}
};
struct Multicast_OrderMsg
{
char MsgType; ///'N', 'X', 'M'
long long Timestamp;
double OrderId;
int Token;
char OrderType;
int Price;
int Quantity;
string ToString()
{
std::stringstream ss;
ss<<MsgType<<'|'<<Timestamp<<'|'<<(long long)OrderId<<"|0|"<<Token<<'|'<<OrderType<<'|'<<Price<<'|'<<Quantity;
return ss.str();
}
};
I am reading a file using ifstream, filling that file into the structure object because file is not into the format of structure, then copy the structure into char buffer. Here is the code for better understanding.
TbtStreamHeader hdr;
Multicast_OrderMsg oMsg;
hdr.MsgLen = 38;
hdr.StreamId = streamID;
hdr.SeqNo = 0;
bool firstLine = true;
while(ifs1)
{
if (!getline(ifs1, str1)) break;
istringstream ss(str1);
v1.clear();
while(ss)
{
string s1;
if(!getline( ss, s1, '|' ))
{
break;
}
v1.push_back(s1);
}
if(firstLine)
{
firstLine = false;
seq = atoi(v1[1].c_str());
hdr.SeqNo = seq;
getline(ifs1, str1);
}
else
{
char tempData[38];
int tempBufOffset=0;
hdr.SeqNo++;
oMsg.OrderId = atoll(v1[0].c_str());
oMsg.Token = atoi(v1[1].c_str());
oMsg.OrderType = v1[2][0];
oMsg.Price = atoi(v1[3].c_str());
oMsg.Quantity = atoi(v1[4].c_str());
oMsg.MsgType = 'N';
memcpy(tempData, &hdr, 8);
tempBufOffset += 8;
memcpy(tempData+tempBufOffset, oMsg, 30);
Multicast_OrderMsg* oMsgT = (Multicast_OrderMsg*)tempData+8; //Not able to caste
cout<<oMsgT->ToString()<<endl;
tempBufOffset += 30;
mcastTbt.streams[0].RecoveryPacket(tempData);
}
}
Here cout<< showing me segmentation fault. I am not able to understanding what wrong it is..?
At the location tempData+8 are no Multicast_OrderMsg objects, dereferencing such pointer is undefined behaviour as it violates the strict aliasing rule.
But that on itself does not usually cause seg. faults, the reason is tempData is not big enough to store the aliased Multicast_OrderMsg object. On most implementation the types require to be aligned at least to their size, which causes padding:
struct Multicast_OrderMsg
{
char MsgType; // 1
// Padding 7
long long Timestamp;// 8
double OrderId;// 8
int Token;// 4
char OrderType;// 1
// Padding 3
int Price;// 4
int Quantity;// 4
};
Making the structure 40 bytes long, you only have space for 30. So the printing tries to access memory locations not belonging to you, hence the segfault.
I am still a newbie to c++; I was wondering why the code i wrote for a custom string split fuction does not work? (it splits by char and not string) I think there is something wrong with memcpy in the second instance?
char** strsplit(const char *s, const char splitboi)
{
const int LEN = length(s);
int segs = 0;
char *segstore, **out;
for (int chrs=0; chrs<=LEN; chrs++)
{
if(*(s+chrs) != splitboi)
{char* temp = chrs==0 ? (char*)"" : segstore;
segstore = new char[chrs+1];
memcpy(&segstore, &temp, sizeof(char*));
segstore[chrs] = *(s+chrs);}
else if(*(s+chrs) == splitboi)
{char **temp = out;
out = new char* [segs+1];
memcpy(&out, &temp, sizeof(char**)); //something wrong with this
out[segs] = segstore;
segs++;}
}
delete segstore;
cout << out[0] << '\n';
return out;
}
I have a character array like below:
char array[] = "AAAA... A1... 3. B1.";
How can I split this array by the string "..." in Arduino? I have tried:
ptr = strtok(array, "...");
and the output is the following:
AAAA,
A1,
3,
B1
But I actually want output to be
AAAA,
A1,
3.B1.
How to get this output?
edit:
My full code is this:
char array[] = "AAAA... A1... 3. B1.";
char *strings[10];
char *ptr = NULL;`enter code here`
void setup()
{
Serial.begin(9600);
byte index = 0;
ptr = strtok(array, "..."); // takes a list of delimiters
while(ptr != NULL)
{
strings[index] = ptr;
index++;
ptr = strtok(NULL, "..."); // takes a list of delimiters
}
for(int n = 0; n < index; n++)
{
Serial.println(strings[n]);
}
}
The main problem is that strtok does not find a string inside another string. strtok looks for a character in a string. When you give multiple characters to strtok it looks for any of these. Consequently, writing strtok(array, "..."); is exactly the same as writing strtok(array, ".");. That is why you get a split after "3."
There are multiple ways of doing what you want. Below I'll show you an example using strstr. Unlike strtokthe strstr function do find a substring inside a string - just what you are looking for. But.. strstr is not a tokenizer so some extra code is required to print the substrings.
Something like this should do:
int main()
{
char array[] = "AAAA... A1... 3. B1...";
char* ps = array;
char* pf = strstr(ps, "..."); // Find first substring
while(pf)
{
int len = pf - ps; // Number of chars to print
printf("%.*s\n", len, ps);
ps = pf + 3;
pf = strstr(ps, "..."); // Find next substring
}
return 0;
}
You can implement your own split as strtok except the role of the second argument :
#include <stdio.h>
#include <string.h>
char * split(char *str, const char * delim)
{
static char * s;
char * p, * r;
if (str != NULL)
s = str;
p = strstr(s, delim);
if (p == NULL) {
if (*s == 0)
return NULL;
r = s;
s += strlen(s);
return r;
}
r = s;
*p = 0;
s = p + strlen(delim);
return r;
}
int main()
{
char s[] = "AAAA... A1... 3. B1.";
char * p = s;
char * t;
while ((t = split(p, "...")) != NULL) {
printf("'%s'\n", t);
p = NULL;
}
return 0;
}
Compilation and execution:
/tmp % gcc -g -pedantic -Wextra s.c
/tmp % ./a.out
'AAAA'
' A1'
' 3. B1.'
/tmp %
I print between '' to show the return spaces, because I am not sure you want them, so delim is not only ... in that case
Because you tagged this as c++, here is a c++ 'version' of your code:
#include <iostream>
using std::cout;
using std::endl;
#include <vector>
using std::vector;
#include <string>
using std::string;
class T965_t
{
string array;
vector<string> strings;
public:
T965_t() : array("AAAA... A1... 3. B1.")
{
strings.reserve(10);
}
~T965_t() = default;
int operator()() { return setup(); } // functor entry
private: // methods
int setup()
{
cout << endl;
const string pat1 ("... ");
string s1 = array; // working copy
size_t indx = s1.find(pat1, 0); // find first ... pattern
// start search at ---------^
do
{
if (string::npos == indx) // pattern not found
{
strings.push_back (s1); // capture 'remainder' of s1
break; // not found, kick out
}
// else
// extract --------vvvvvvvvvvvvvvvvv
strings.push_back (s1.substr(0, indx)); // capture
// capture to vector
indx += pat1.size(); // i.e. 4
s1.erase(0, indx); // erase previous capture
indx = s1.find(pat1, 0); // find next
} while(true);
for(uint n = 0; n < strings.size(); n++)
cout << strings[n] << "\n";
cout << endl;
return 0;
}
}; // class T965_t
int main(int , char**) { return T965_t()(); } // call functor
With output:
AAAA
A1
3. B1.
Note: I leave changing "3. B1." to "3.B1.", and adding commas at end of each line (except the last) as an exercise for the OP if required.
I looked for a split function and I didn't find one that meets my requirement, so I made one and it works for me so far, of course in the future I will make some improvements, but it got me out of trouble.
But there is also the strtok function and better use that.
https://www.delftstack.com/es/howto/arduino/arduino-strtok/
I have the split function
Arduino code:
void split(String * vecSplit, int dimArray,String content,char separator){
if(content.length()==0)
return;
content = content + separator;
int countVec = 0;
int posSep = 0;
int posInit = 0;
while(countVec<dimArray){
posSep = content.indexOf(separator,posSep);
if(posSep<0){
return;
}
countVec++;
String splitStr = content.substring(posInit,posSep);
posSep = posSep+1;
posInit = posSep;
vecSplit[countVec] = splitStr;
countVec++;
}
}
Llamada a funcion:
smsContent = "APN:4g.entel;DOMAIN:domolin.com;DELAY_GPS:60";
String vecSplit[10];
split(vecSplit,10,smsContent,';');
for(int i = 0;i<10;i++){
Serial.println(vecSplit[i]);
}
String input:
APN:4gentel;DOMAIN:domolin.com;DELAY_GPS:60
Output:
APN:4g.entel
DOMAIN:domolin.com
DELAY_GPS:60
RESET:true
enter image description here
I am having the following problem with my code, though it compiles correctly:
value type const char cannot be used to initialize an entity of type char*
Can someone help me? I can run the code which is weird but I can't create a makefile using this. It's very weird to me.
int SpliString(struct dict_word *entry, const char *str)
{
long word_length,j,k;
int yearIndex;
char *buffer;
char *endOfYears;
char *endOfYear;
char *endOfDefinition;
char *endOfWord = strstr(str, "_#_");
//Sets the first num bytes of the block of memory pointed by ptr
//to the specified value (related as an unsigned char)
memset(entry, 0, sizeof(struct dict_word));
// If '_#_' is not found, it's NULL
if (endOfWord)
{
// Calculating word legth; 'str' points to start of word, 'endofWord' points to '_#_' that is just after word
word_length = endOfWord - str;
// Copying data into the word
strncpy(entry->words, str, word_length);
// 'endOfYears' points to '_#_,' but wee need to find follow '_#_'
// therefore there is added 3 in order to skip curremnt '_#_
endOfYears = strstr(endOfWord+3, "_#_");
if (endOfYears)
{
word_length = endOfYears - (endOfWord+3);
// Skips _#_
buffer = endOfWord+3;
yearIndex = 0;
j = 0;
// Finds next year in the line, it stops if all 10 years is filled
// or end of years string is reached
while(yearIndex<10 && buffer+j<endOfYears)
{
// Stores year in the buffer, with converting 'stirng' to 'int'
entry->year[yearIndex] = atoi(buffer+j);
// check year for negative...
if (entry->year[yearIndex]<=0)
return 0;
// Locating substring; 'j' is current offset from beginning of buffer
endOfYear = strchr(buffer+j, '_');
if (endOfYear)
{
j = endOfYear - buffer;
j++;
yearIndex++;
}
else
{
break;
}
}
//endOfYears points to '_#_' that separatates 'years' and 'definition'
//and there is needed to find '_#_' between 'definition' and 'synonyms'
//therefore it skips '_#_' that separatates 'years' and 'definition',
//+3, because '_#_' has length = 3
endOfDefinition = strstr(endOfYears+3, "_#_");
if (endOfDefinition)
{
word_length = endOfDefinition - (endOfYears+3);
k = 0;
for(j=0; j<word_length; j++)
{
// Skips '_#_'
if (endOfYears[j+3]==',')
{
entry->eng_synonyms[k] = ' ';
k++;
}
else if (endOfYears[j+3]>='a' && endOfYears[j+3]<='z')
{
entry->eng_synonyms[k] = endOfYears[j+3];
k++;
}
else if (endOfYears[j+3]!='_')
{
return 0;
}
}
k = 0;
word_length = (str+strlen(str)) - (endOfDefinition+3);
for(j=0; j<word_length; j++)
{
if (endOfDefinition[j+3]==',')
{
entry->heb_synonyms[k] = ' ';
k++;
}
else if (endOfDefinition[j+3]>='A' && endOfDefinition[j+3]<='Z')
{
entry->heb_synonyms[k] = endOfDefinition[j+3];
k++;
}
else if (endOfDefinition[j+3]!='_')
{
return 0;
}
}
}
// Check for legality
// Check all symbols of 'entry->words'
// calculate length and supress warning
for(j=0;j<(int)strlen(entry->words);j++)
{
if (entry->words[j]<'a' || entry->words[j]>'z')
return 0;
}
return 1;
}
}
return 0;
}
Use
const char *buffer;
const char *endOfWord = strstr(str, "_#_");
Confident OP is compiling in C++.
// C
char *strstr(const char *s1, const char *s2);
// C++
const char* strstr(const char* s1, const char* s2);
char* strstr( char* s1, const char* s2);
See
Compile C app with Visual Studio 2012
How to compile and execute C program on Visual Studio 2012 for Windows 8?
I'm interested in unescaping text for example: \ maps to \ in C. Does anyone know of a good library?
As reference the Wikipedia List of XML and HTML Character Entity References.
For another open source reference in C to decoding these HTML entities you can check out the command line utility uni2ascii/ascii2uni. The relevant files are enttbl.{c,h} for entity lookup and putu8.c which down converts from UTF32 to UTF8.
uni2ascii
I wrote my own unescape code; very simplified, but does the job: pn_util.c
Function Description: Convert special HTML entities back to characters.
Need to do some modifications to fit your requirement.
char* HtmlSpecialChars_Decode(char* encodedHtmlSpecialEntities)
{
int encodedLen = 0;
int escapeArrayLen = 0;
static char decodedHtmlSpecialChars[TITLE_SIZE];
char innerHtmlSpecialEntities[MAX_CONFIG_ITEM_SIZE];
/* This mapping table can be extended if necessary. */
static const struct {
const char* encodedEntity;
const char decodedChar;
} entityToChars[] = {
{"<", '<'},
{">", '>'},
{"&", '&'},
{""", '"'},
{"'", '\''},
};
if(strchr(encodedHtmlSpecialEntities, '&') == NULL)
return encodedHtmlSpecialEntities;
memset(decodedHtmlSpecialChars, '\0', TITLE_SIZE);
memset(innerHtmlSpecialEntities, '\0', MAX_CONFIG_ITEM_SIZE);
escapeArrayLen = sizeof(entityToChars) / sizeof(entityToChars[0]);
strcpy(innerHtmlSpecialEntities, encodedHtmlSpecialEntities);
encodedLen = strlen(innerHtmlSpecialEntities);
for(int i = 0; i < encodedLen; i++)
{
if(innerHtmlSpecialEntities[i] == '&')
{
/* Potential encode char. */
char * tempEntities = innerHtmlSpecialEntities + i;
for(int j = 0; j < escapeArrayLen; j++)
{
if(strncmp(tempEntities, entityToChars[j].encodedEntity, strlen(entityToChars[j].encodedEntity)) == 0)
{
int index = 0;
strncat(decodedHtmlSpecialChars, innerHtmlSpecialEntities, i);
index = strlen(decodedHtmlSpecialChars);
decodedHtmlSpecialChars[index] = entityToChars[j].decodedChar;
if(strlen(tempEntities) > strlen(entityToChars[j].encodedEntity))
{
/* Not to the end, continue */
char temp[MAX_CONFIG_ITEM_SIZE] = {'\0'};
strcpy(temp, tempEntities + strlen(entityToChars[j].encodedEntity));
memset(innerHtmlSpecialEntities, '\0', MAX_CONFIG_ITEM_SIZE);
strcpy(innerHtmlSpecialEntities, temp);
encodedLen = strlen(innerHtmlSpecialEntities);
i = -1;
}
else
encodedLen = 0;
break;
}
}
}
}
if(encodedLen != 0)
strcat(decodedHtmlSpecialChars, innerHtmlSpecialEntities);
return decodedHtmlSpecialChars;
}
QString UNESC(const QString &txt) {
QStringList bld;
static QChar AMP = '&', SCL = ';';
static QMap<QString, QString> dec = {
{"<", "<"}, {">", ">"}
, {"&", "&"}, {""", R"(")"}, {"'", "'"} };
if(!txt.contains(AMP)) { return txt; }
int bgn = 0, pos = 0;
while((pos = txt.indexOf(AMP, pos)) != -1) {
int end = txt.indexOf(SCL, pos)+1;
QString val = dec[txt.mid(pos, end - pos)];
bld << txt.mid(bgn, pos - bgn);
if(val.isEmpty()) {
end = txt.indexOf(AMP, pos+1);
bld << txt.mid(pos, end - pos);
} else {
bld << val;
}// else // if(val.isEmpty())
bgn = end; pos = end;
}// while((pos = txt.indexOf(AMP, pos)) != -1)
return bld.join(QString());
}// UNESC