So, thanks for all the help guys, I am just have one last problem, I am putting the website source in a char var, and then reading the product title (I have gotten that), however it only works if I take part of the source, or only the html from one of the featured products on neweggs page. I think the program is crashing, because it doesnt know which title to pick when I need to get all three titles and put them into an array. Any ideas? Thanks. Here is the parser code:
http://paste2.org/p/809045
Any solution is greatly appreciated.
/**
* num_to_next -
* takes in a pointer to a string and then counts how many
* characters are until the next occurance of the specified character
* #ptr: the pointer to a string in which to search
* #c: char delimiter to search until
**/
int num_to_next(char *ptr, char c)
{
unsigned int i = 0;
for (i = 0; i < strlen(ptr); i++) {
if (ptr[i] == c) {
return i;
}
}
return -1;
}
/**
* space_to_underscore -
* this should help to alleviate some problems when dealing with
* filepaths that have spaces in them (basically just changes all
* spaces in a string to underscores)
* #string: the string to convert, yo
**/
int space_to_underscore(char *string)
{
for (unsigned int i = 0; i < strlen(string); i++) {
if (string[i] == ' ') {
string[i] = '_';
}
}
return 0;
}
char *file_name = (char *)malloc(sizeof(char *)); // allocate memory for where the app name will be stored
memset(file_name, 0, sizeof(file_name)); // zero the memory
char td_one[] = "<ul class="featureCells"><li id="ItemCell" class="cell">";
char *pstr = strstr(buffer, td_one) + strlen(td_one) + 6; // buffer is the source
char *poop = pstr + num_to_next(pstr, '>') + 1;
int blah = num_to_next(poop, '<');
strncpy(file_name, poop, blah);
// null terminate the string //
file_name[blah] = '\0';
space_to_underscore(file_name);
MessageBox(NULL, file_name, "Product Name", MB_OK);
free(file_name);
I'm not sure if these are your only problems, but...
First, you can't do char* filename = (char*)malloc(sizeof(char*)) (well, you can, but that's not what you actually want from your app).
What you want to have is char* filename = (char*)malloc(SIZE_OF_YOUR_STRING * sizeof(char));, so you can't allocate just an abstract buffer for your string and you have to know the expected size of it. Actually, here you don't have to write sizeof(char) because it always equals 1, but this sometimes this way of writing the code can help you(or somebody else) to understand that this block would store a string as array of chars).
Another example on the same problem: char* filename = (char*)malloc(65); - is ok and will allocate a block of memory to store 65 char symbols.
If we go further (where you're doing the memset), char* is a plain pointer and sizeof(filename) in your case would return the size of your pointer, but not your string. What you should write here is strlen(filename).
Related
I have an XML file with many values and a working C++ function that can retrieve these values
Two of these values are:
A file path such as: "C:\foo1\foo2" and
A file name: "foo3.txt"
Combining these together, they would become "C:\foo1\foo2\foo3.txt"
However, while trying to set a CString to save a file path, it will give an error because using the character, \, in a string is not allowed due to string notation and its interaction with the \ character.
I am using MFC, and I know WIN32 allows you to create a file path with / instead of \, so: "C:/foo1/foo2/foo3.txt" would work. I tested this in Windows Explorer and it worked.
I would like to collect the file path from XML file, but when it comes in, it will have \ instead of / in its file path, meaning it will not be possible to replace the character (the string coming in will have an error already due to XML not having a problem with the \ character.
How do I safely retrieve the path as a CString, ideally while converting any \ character to a / character.
Now I'm not familiar with the "CString" class you are refering to. Googling the API documentation just has the standard c style char array format commands, so I'm going to assume rightly or wrongly cstring is a char array.
The fact we are going to need to use an object that is not resizable means we either
Need to use the heap, which will be slow, and can leak memory if the memory isn't deleted later
Allow a maximum string length and accept it will be truncated if below this
Heap example (NOTE: I'm not using smart pointers as I assume they don't have access to them, else you'd just std::string and not do this.)
char* escapeString(const char* data, unsigned int length){
//multiplying by 1.5 means this could still truncate,
//but I'm making an educated guess it's not all bad characters.
const int newLen = (length + 1) * 1.5;
char* escaped = new char[newLen + 1];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i++){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index++] = '\\';
}
else if(data[i] == '%'){
escaped[index++] = '%';
}
//else anything else you want to escape
escaped[index++] = data[i];
}
//Make sure a null string is null terminatedescaped
escaped[index] = '\0';
return escaped;
}
int main() {
const char* stringWithBadChars = "I\"m not a %%good \\string";
char* escapedString = escapeString(stringWithBadChars, strlen(stringWithBadChars));
std::cout << escapedString;
delete [] escapedString;
return 0;
}
If we do this on the stack instead it would be a lot faster, but we are limited by the size of the buffer we give, and the size of the buffer in the function. We will return a bool if either fails.
bool escapeString(char* data, unsigned int length){
const int newLen = 1000;
char escaped[1001];
unsigned int index = 0;
for(unsigned int i = 0; i < length && i < newLen; i++){
if(data[i] == '\\' || data[i] == '\"'){
escaped[index++] = '\\';
}
else if(data[i] == '%'){
escaped[index++] = '%';
}
escaped[index++] = data[i];
}
//Make sure a null string is null terminatedescaped
memcpy(data, escaped, index);
escaped[index] = '\0';
return index < length && index < 1000;
}
You could probably get even more efficiency using memmov rather than copy it character by character. Doing it this way you also wouldn't need the second char array.
CString reserves some special characters. Have a look at the Format command as an example. The linked documentation refers you to: Format specification syntax: printf and wprintf functions.
The \ is used as mentioned in the comments to indicate a special character. For example:
\t will insert a tab character.
\" will insert a double quote character.
So when it hits the \ it expects the next character to be one of the special ones. Therefore, when you actually need a backslash, you use \\.
The linked article does explain about % but not the slash. However, tt is exactly the same with % because it too has special meaning. So you would use %% when you want the percent sign.
I have the following string tok_str which is like "default.png" I would like to preprend char ' and append char ' too.
That's what I have done, but the chars are appended and prepended in the wrong places
char *tok_str = const_cast<char*>(mReader->getAttributeValue(pAttrIdx));
char * mod_tok = new char[tok_str_len+2];
mod_tok[0] = '\'';
size_t len = strlen(tok_str);
size_t i;
memmove(mod_tok + len, mod_tok, strlen(mod_tok) + 1);
for (i = 0; i < len; ++i)
{
mod_tok[i] = tok_str[i];
}
char *dup;
char *cstr="'";
sprintf(mod_tok,"%s%s",cstr,(dup=strdup(mod_tok)));
free(dup);
If you want to continue using null-terminated byte strings there are a few things you need to think of and do.
The first is of course the null-terminated part. A string of X characters needs space for X+1 to include the terminator.
The second is that all you need is really a single sprintf (or better yet snprintf) call (once you allocated memory):
char* mod_tok = new char[strlen(tok_str) + 3]; // +2 for the extra characters, +1 for terminator
snprintf(mod_tok, strlen(tok_str) + 3, "'%s'", tok_str);
That is it, now you have added the single quotes in front and at the end of the original string.
There are a couple of things to improve:
usage of const when possible
len vs tok_str_len, use only one.
the memmove done in the middle seems to have no effect on the final result
pay attention to the indexes in the for loop
be aware that strlen doesn't count the NULL terminator
if your code starts to mix new/delete with free try to refactor it
That's my proposal:
//keep it const and protect your data
const char *tok_str = mReader->getAttributeValue(pAttrIdx);
//retrive the len once for all (const, no one is supposed to change it)
const size_t len = strlen(tok_str);
char * mod_tok = new char[len+3]; // 2 "'" + '\0'
mod_tok[0] = '\'';
for (size_t i = 0; i < len; ++i)
{
mod_tok[i+1] =tok_str[i];
}
mod_tok[len+1] = '\'';
mod_tok[len+2] = '\0';
//done.
//later...
delete[] mod_tok;
Enjoy your coding!
Stefano
PS: I agree, though, that a use of std::string is reccomended.
I'm think pointer is 4Byte or(2Byte) heap memory allocated
I need Structure data convert to char* Just need 12byte convert
this is my code
please Contact me.
thank you
struct MyData {
unsigned int myNumber;
float x;
float y;
};
int main(){
Mydata* mydata = new Mydata();
mydata->userNumber = 188242268;
mydata->x = 100.0f;
mydata->y = 102.0f;
char* sender = (char*)&mydata;
sioclient->send(sender);
// SocketIO Server Send
}
I don't think what you are asking is possible. string doesn't like having null characters in itself, which would be necessary to directly send the data (For example, a int(1) would have 1 NULL (0x0) character (modern systems would have 3 NULL characters) and 1 0x1 character, which string wouldn't like the null and terminate the string there).
I think you should find another networking library for what you are doing if you can't use WebSocket and need to have the efficiency of sending the bytes of a struct. (Boost::asio perhaps?)
But if you HAVE to use Cocos2d-x SIOClient without the WebSocket, then in the sending side, create a string with the values separated by commas:
string sendMe = to_string(mydata->userNumber) + "," + to_string(mydata->x) + "," + to_string(mydata->y);
And then on the receiving side:
Mydata receiver;
string recStr;//Received string
string temp;
int stage = 0;
for (int itr = 0; itr < temp.length(); itr++)
{
if (recStr[itr] == ',')
{
if (stage==0)
receiver.myNumber = stoi(temp);
else if (stage==1)
receiver.x = stof(temp);
stage++;
temp = "";
}
else
temp += recStr[itr];
}
receiver.y = stof(temp);
Hope that helps.
The old answer, in case you want to switch and have a solution:
Ok, try using the overloaded function
void send (const unsigned char * binaryMsg, unsigned int len);
instead. read about it here
This should look something like the following:
sioclient->send(reinterpret_cast<unsigned char*>(mydata), sizeof(MyData));
Tell me if you are using a different version of Cocos2d-x and thus this doesn't work, or if it failed to solve the problem. When I tried this, it compiled nicely and seemed to behave correctly.
If your compiler doesn't like unsigned char* for a const unsigned char* parameter, just add a const_cast.
Also, remember to delete (mydata); when you are done with it.
I'm making a lexical analyzer and this is a function out of the whole thing. This function takes as argument a char, c, and appends this char to the end of an already defined char* array (yytext). It then increments the length of the text (yylen).
I keep getting segfaults on the shown line when it enters this function. What am I doing wrong here? Thanks.
BTW: can't use the strncpy/strcat, etc. (although if you want you can show me that implementation too)
This is my code:
extern char *yytext;
extern int *yylen;
void consume(char c){
int s = *yylen + 1; //gets yylen (length of yytext) and adds 1
//now seg faults here
char* newArray = new char[s];
for (int i = 0;i < s - 1;i++){
newArray[i] = yytext[i]; //copy all chars from existing yytext into newArray
}
newArray[s-1] = c; //append c to the end of newArray
for (int i = 0;i < s;i++){ //copy all chars + c back to yytext
yytext[i] = newArray[i];
}
yylen++;
}
You have
extern int *yylen;
but try to use it like so:
int s = (int)yylen + 1;
If the variable is an int *, use it like an int * and dereference to get the int. If it is supposed to be an int, then declare it as such.
That can t work:
int s = (int)yylen + 1; //gets yylen (length of yytext) and adds 1
char newArray[s];
use malloc or a big enought buffer
char * newarray=(char*)(malloc(s));
Every C-style string should be null-terminated. From your description it seems you need to append the character at c. So, you need 2 extra locations ( one is for appending the character and other for null-terminator ).
Next, yylen is of type int *. You need to dereference it to get the length (assuming it is pointing to valid memory location ). So, try -
int s = *yylen + 2;
I don't see the need of temporary array but there might be a reason why you are doing it. Now,
yytext[i] = newArray[i]; //seg faults here
you have to check if yytext is pointing to a valid write memory location. If yes, then is it long enough to fill the appending character plus null terminator.
But I would recommend using std::string than working with character arrays. Using it would be a one liner to solve the problem.
I have a method that that creates a MatLab array name from a file path and returns it as a std::string. the resulting string is passed into another method that writes the name to the file. When I try to get the length of the passed in string, it displays 0 when the length of the string is 12 or 13 chars.
My code:
bool MyClass::masterMethod(std::string fileURI){
FILE* dataStream;
// Assume dataStream is set up correctly
// Get arrayName from File URI
std::string arrayName = this->makeArrayNameFromPath( fileURI);
//Write array name to file
this->writeArrayName(arrayName , dataStream)
}
std::string MyClass::makeArrayNameFromPath(std::string filePathURI){
std::string tempString = filePathURI.substr(filePathURI.find_last_of('/')+1);
std::string returnString = "";
long index = 0;
for(long i = 0; i < tempString.length(); i++){
if((tempString[i] != ' ') && (tempString[i] != '.')){
returnString[index++] = tempString[i];
}
}
return returnString;
}
void MyClass::writeArrayName(std::string name , FILE *nameStream){
// long testLength = name.length();
// long testLength2 = name.size();
// const char* testChar = nam.c_str();
// long testCharLen = strlen(testChar);
// The size of the name is the number of Chars * sizeof(int8_t)
int32_t sizeOfName = (int32_t)(name.length() * sizeof(int8_t));
int32_t nameType = miINT8;
fwrite(&nameType , sizeof(int32_t) , 1 , nameStream);
fwrite(&sizeOfName, sizeof(sizeOfName), 1, nameStream);
fwrite(&name , sizeof(name[0]), sizeOfName , nameStream);
}
So I'm not sure why string::length is not working. If a create a std::string test = name, and print it , I can get the value of the string but can not get its length or size.
If I use const char* testName = name.c_str(); long test = strlen(testName), I get a the
correct value, but thought that wasn't necessary.
So any advice or suggestion is appreciated.
returnString[index++] = tempString[i]; doesn't do what you think it does. It's not adding additional space or length to the string, only overwriting memory at a location that the string doesn't actually own. I think returnString.append(1, tempString[i]) or similar should do it.
You never give the string a size, just trying to assign positions that isn't there.
Try this instead to add characters to the return value
returnString += tempString[i];