Hi I'm trying to copy char * to std::string, the char * variable allocated with malloc, after the copy I want to free char * cause I'm pretty sure std::string won't free it. I want to do that without affecting the newly created std::string.
typedef struct {
std::string name;
} st;
st fst;
name = (char *) malloc(len + 1);
for (i = 0; i<len; i++)
name[i] = name_orig[offset + i]; //name_orig is const unsigned char *
name[i] = 0;
fst.name.assign(name,len);
free(name);
cout << fst.name << endl; // prints "wiped"
The malloc'd string and the copy are unnecessary. You can just do
typedef struct {
std::string name;
} st;
st fst;
fst.name.assign(reinterpret_cast<const char*>(&name_orig[offset]), len);
Related
Here is a problem. When I try to convert it by using strncpy_s, array has some type of "trash data" from memory in the end of it. Even when I fill buffer with "\0". How to convert it clear?
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
strncpy_s(text, strin.c_str(), sizeof(text) - 1);
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
The idea to use c_str() function to convert the std::string to a a-string. Then we can simply call strcpy() function to copu the c-string into char array
std::string s = "Hello World!";
char cstr[s.size() + 1];
strcpy(cstr, s.c_str()); // or pass &s[0]
std::cout << cstr << '\n';
return 0;
When using the strncpy_s function you tell it to copy as many chars as will fit into your buffer "text". Since the string you create the "example" instance with is shorter, the copy function will keep going after the end of the actual string.
That is where your garbage comes from. Even worse you risk a Segmentation Fault this way. Your code might access parts of the RAM it is not allowed to read from. That will cause it to crash.
You are right though to copy the data pointed to by the return of c_str(). The pointer returned by c_str() points to data that belongs to the std::string object and might be changed or even invalidated by that object. (Read more here)
Here's a modified version of your code that should avoid the garbage:
typedef class Ryadok {
private:
int LengthOf = 0;
char text[20];
string* address;
public:
Ryadok(string strin) {
this->text[0] = '\0';
memset(text, '\0', sizeof(text));
if(strin.length()+1 <= sizeof(text)) {
strncpy_s(text, strin.c_str(), strin.length()+1);
} else {
//some error handling needed since our buffer is too small
}
this->address = &strin;
for (int i = 0; i < sizeof(strin); i++) {
cout << this->text[i];
}
}
~Ryadok() {
}
}*cPtr;
int main()
{
Ryadok example("sdsdfsdf");
}
I'm trying to make my own String class, its called MyString. I have few string manipulation functions. All of them work except the insert function. When I use the insert function many times, the program crashes (source.exe has stopped working). I'm currently using Dev C++.
MyString MyString::insert(MyString s2, int pos) {
int size = strlen(this->getptr());
if(pos > size || pos < 0){
return "Error";
}
char * ptrLeft = this->substr(0, pos);
char * ptrRight = this->substr(pos, size - pos);
strcat(ptrLeft, s2.getptr());
strcat(ptrLeft, ptrRight);
return ptrLeft;
}
This is the substr() function in MyString class:
char * MyString::substr(int position, int length) {
char* otherString = 0;
otherString = (char*)malloc(length + 1);
memcpy(otherString, &this->getptr()[position], length);
otherString[length] = 0;
return otherString;
}
Parameterized constructor (char * ptr is a private member):
MyString::MyString(char* str){
int size = strlen(str);
ptr = new char[size];
ptr = str;
}
If I do the following many times, it crashes sometimes.
buff = buff.insert(" Text", 5);
cout << buff;
system("PAUSE");
buff = buff.insert(" Text", 5);
cout << buff;
system("PAUSE");
the insert call is not mallocing the size of the new array. is only mallocing in the first substr call, up to the size of the original array
I am doing this
char *draw_line(int n, char ch)
{
char *line = new char[50];
for(int i = 0; i <= n; i++)
line[i] = ch;
return line;
}
and while calling the function I am writing this:
char *res_line = draw_line(50, '=');
cout<<*res_line;
but instead of getting = printed 50 times in the console window, it just show = sign one time. My main aim is to return the = or any character as many times I want and output
the same to a text file. That's it.
cout<<*res_line;
is printing one char because *res_line is char, not char*.
Write:
cout<<res_line;
But wait — that is not going to work either because res_line is NOT null-terminated.
Use std::string or std::vector<char> — avoid explicit memory allocation, use RAII idiom instead:
std::string draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
So simple!
Or if you use std::vector:
std::vector<char> draw_line(int n, char ch)
{
return {n, ch}; //C++11
}
which is almost same.
In C++03, however, you've to write:
return std::string(n, ch); //in the first case
return std::vector<char>(n, ch); //in the second case
That is, invoke the constructor explicitly.
The valid code will look as
char* draw_line( int n, char ch )
{
char *ch2= new char[n + 1]();
std::memset( ch2, ch, n );
return ch2;
}
//...
char *ch50 = draw_line(50,'=');
cout << ch50;
//...
delete []ch50;
Take into account this statement
char *ch2= new char[n + 1]();
But it would be much better to write simply
std::cout << std::string( 50, '=' );
char* draw_line(int n, char ch)
{
char *ch2= (char *) malloc(sizeof(char)*(n+1)); // (n+1) here
for(int i=0;i<n;i++) // < instead of <=
ch2[i]=ch;
ch2[n] = 0; // terminator
return ch2;
}
char *ch50 = draw_line(50,'=');
cout<< ch50; // changed from *ch50 to ch50
ADDON: look at string-fill constructor
cout << string(50, '=');
I have been pulling my hair out on this particular issue and would like some advice. I have the following struct:
struct MqlStr // MQL String Array
{
int len;
char *string;
};
this is being passed to a function as a pointer from an external application as such:
MT4_EXPFUNC double __stdcall CheckExecutionRequests(MqlStr* RequestInfo)
within the function i am generating a number of string values that i need to assign to varies elements of the MqlStr array. the following works fine:
RequestInfo[1].string = "1";
RequestInfo[2].string = "2";
but when i use strcpy to get my generated string value into the array, it overwrites the entire array with the value i copied. for example:
string field1 = value.substr(Demark + 1, Demark2 - Demark - 1);
strncpy(RequestInfo[1].string, field1.c_str(), field1.size());
string field2 = value.substr(Demark + 1, Demark2 - Demark - 1);
strncpy(RequestInfo[2].string, field2.c_str(), field2.size());
if field1 = 1 and field2 = 2 then the entire RequestInfo[] array would be equal to 2 (the last value copied)
can someone point me in the right direction?
RequestInfo[1] = "1";
is not doing what you think. It's either
RequestInfo[1].string = "1";
if RequestInfo is a vector of MqlStr objects containing at least 2 elements, or
RequestInfo->string = "1";
if RequestInfo is a pointer to a single MqlStr object.
Have you allocated enough space for the .string pointers in your RequestInfo elements? strncpy is not allocating the space for you, use strdup for that.
You need to manage MqlStr memory in a safe manner, this can happen by using a standard container like std::string or by writing methods to allocate and deallocate the internal memory.
Here is an example of a simple class that manages its internal memory:
#include <cstdlib>
#include <iostream>
#include <string.h>
#include <sstream>
struct MqlStr
{
public:
int len;
char *string;
MqlStr() { init (); }
~MqlStr() { dealloc(); }
void assign(std::string& str) {
dealloc();
string = new char[str.length() + 1];
strncpy(string, str.c_str(), str.length());
string[str.length()] = 0;
len = str.length();
}
void dealloc() {
if(string != 0) delete [] string; init();
}
private:
void init() { string = 0; len = 0; }
MqlStr(const MqlStr &);
void operator= (const MqlStr &);
};
double CheckExecutionRequests(MqlStr* RequestInfo)
{
static int callCount = 0;
std::ostringstream stringstream; stringstream<<"callCount: "<<callCount++;
std::string field1 = stringstream.str();
RequestInfo->assign(field1);
return 1.0;
}
int main(int argc, char** argv)
{
MqlStr s[5];
std::cout<<"First call"<<std::endl;
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
CheckExecutionRequests(s + i);
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
std::cout<<"MqlStr["<<i<<"].string = "<<s[i].string<<std::endl;
std::cout<<"Second call"<<std::endl;
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
CheckExecutionRequests(s + i);
for(unsigned i = 0; i < sizeof(s)/sizeof(s[0]); ++i)
std::cout<<"MqlStr["<<i<<"].string = "<<s[i].string<<std::endl;
return EXIT_SUCCESS;
}
The second execution of CheckExecutionRequests with the same MqlStr instances will not corrupt the memory.
An extension to the code can be preallocation of the string size, and only reallocating the memory in the assign method if the new str.length > this.maxLength (preallocated length different from the string size).
The copy constructor and assignment operator are currently disabled, because they can cause problems if not implemented properly while managing internal memory on the heap.
A simpler solution would be to write your struct using a standard container as follows:
struct MqlStr
{
public:
std::string string;
}
And then just assign the string you get for the fields to MqlStr string.
Let's say you have this structure:
struct MMFS_IDENTIFICATION
{
char *szVendor;
char *szControllerModel;
char *szRevision;
char *szId;
char *szExecutive;
char *szKarelRevision;
char *szProcessName;
char *szCommRevision;
char *szRobotModel;
};
Is there any easy way to do something like this?
MMFS_IDENTIFICATION mmfsId;
for( int i = 0; i < 9; i++ )
{
int len = buf[pos++];
mmfsId[i] = malloc(len);
memcpy( mmfsId[i], buf[pos], len );
pos += len;
}
The only thing I know to do is copy and paste the code nine times. But I really don't want to do that because in the real program I'm using this concept for, calculating len is not as simple as I made it in this example.
Since your structure contains 9 different pointers with different names, the only standard way to access them is with 9 different pieces of code. You might try to cheat and rely on the internal representation of the structure, and you might even get away with it, but it isn't advised.
Use a function to turn each piece into a single one-liner.
void CopyString(char * & string_ptr, char * buf, int & pos)
{
int len = buf[pos++];
string_ptr = new char[len];
memcpy( string_ptr, buf[pos], len );
pos += len;
}
CopyString(mmfsId.szVendor, buf, pos);
CopyString(mmfsId.szControllerModel, buf, pos);
CopyString(mmfsId.szRevision, buf, pos);
CopyString(mmfsId.szId, buf, pos);
CopyString(mmfsId.szExecutive, buf, pos);
CopyString(mmfsId.szKarelRevision, buf, pos);
CopyString(mmfsId.szProcessName, buf, pos);
CopyString(mmfsId.szCommRevision, buf, pos);
CopyString(mmfsId.szRobotModel, buf, pos);
Since all of the structure members are char* pointers, you could do something like this:
#include <pshpack1.h>
struct MMFS_IDENTIFICATION
{
char *szVendor;
char *szControllerModel;
char *szRevision;
char *szId;
char *szExecutive;
char *szKarelRevision;
char *szProcessName;
char *szCommRevision;
char *szRobotModel;
};
#include <poppack.h>
MMFS_IDENTIFICATION mmfsId;
char** pmmfsId = (char**) &mmfsId;
for( int i = 0; i < 9; ++i )
{
int len = buf[pos++];
pmmfsId[i] = malloc(len+1);
memcpy( pmmfsId[i], buf[pos], len );
}
For the moment, I've made the members std::string instead of char *, for the sake of slightly simpler demo code, but the general idea should work the same with with char * instead1.
#include <stddef.h>
#include <iostream>
#include <string.h>
#include <sstream>
struct MMFS_IDENTIFICATION
{
std::string Vendor;
std::string ControllerModel;
std::string Revision;
std::string Id;
std::string Executive;
std::string KarelRevision;
std::string ProcessName;
std::string CommRevision;
std::string RobotModel;
};
int main() {
MMFS_IDENTIFICATION s;
// We need a char *, because we need to add byte-wise offsets:
char *base = (char *)&s;
typedef std::string *ptr;
ptr fields[9];
// Set up our `fields` array with the addresses of the fields.
// Note the parens to force pointer arithmetic on `char *`, *then* conversion
// to `std::string *`.
fields[0] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Vendor));
fields[1] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, ControllerModel));
fields[2] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Revision));
fields[3] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Id));
fields[4] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, Executive));
fields[5] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, KarelRevision));
fields[6] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, ProcessName));
fields[7] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, CommRevision));
fields[8] = (std::string *)(base + offsetof(MMFS_IDENTIFICATION, RobotModel));
// Initialize the field contents to some recognizable values:
for (int i=0; i<9; i++) {
std::ostringstream buffer;
buffer << "Field " << i;
*fields[i] = buffer.str();
}
// print out some spot results to show we've written to the fields in the struct:
std::cout << "printing by field names:\n";
std::cout << "Vendor = " << s.Vendor << "\n";
std::cout << "Id = " << s.Id << "\n";
std::cout << "CommRevision = " << s.CommRevision << "\n";
return 0;
}
Another possibility would be to use std/tr1/boost tuples. These won't let you use run-time iteration like I have above, but they will give you access to fields by number at compile time. With some case, you can probably use this to eliminate duplication at the source code level, even though it may remain in the object code.
Technically, you can only use offsetof in a POD struct (at least under C++98/03), so it's not required to work at all with them being std::string. At least with most typical compilers (e.g., VC++, g++) I've yet to see it fail for non-POD types, at least as long as the parent struct has no virtual functions, etc., of its own.