const char *RecBuffer, int *packetLength point to the data and the size
string packet(RecBuffer,*packetLength);//store here
...do some stuff
RecBuffer = packet.c_str();//retrieve it later
now what is happening is that my Recbuffer contains lots of floats, and ints packet together which I receive as a UDP packet. But when I store and retrieve it from the string it contains garbage.
Where am I going wrong?
I suspect the std::string instance named packet is being destructed, or modified, before RecBuffer is being used, meaning RecBuffer is a dangling pointer. You need to copy the content of packet rather than store a reference to an internal member of it. Instead of dynamically allocating a char* suggest using a std::vector<char> (as commented by Bartek) instead:
std::vector<char> RecBuffer(packet.begin(), packet.end());
Use &RecBuffer[0] (or RecBuffer.data() if available, introduced in c++11) to access the internal array.
Use memcpy:
RecBuffer[packet.size()]=0;
memcpy(RecBuffer, packet.c_str(), packet.size());
Related
Assume we have defined a char* as follow:
char *x;
And we have a function like it:
void append(void *y, char *z);
This function appends it's second parameter (where the pointer z is pointing at) to the end of a string that the pointer y is pointing to it's beginning. The reason that I am restricted to have the first parameter to be void* is that I need to override a libcurl function:
size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata);
Any time the header_callback function is called I need to append buffer to the end of userdata. The userdata pointer is pointing to beginning of a string.
According to documentation you linked, userdata is a pointer previously supplied to CURLOPT_HEADERDATA. Something like this might work for you.
size_t header_callback(char *buffer, size_t size, size_t nitems, vector<string> *userdata)
{
userdata->push_back(string(buffer, size*nitems));
return size*nitems;
}
//...
vector<string> headers;
curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
//...
It is impossible to implement your
void append(void *y, char *z);
in such a way that it could append a non-null terminated character sequence.
The char *buffer given to the callback is non-null terminated.
Also, you can convert the void pointer to the correct type of the buffer in the callback, before calling the append. That must be done eventually, since you cannot append anything to void.
You hardly need an external function since appending is quite trivial. Assuming your void* points to a std::string:
auto bytes = size * nitems;
auto str = (std::string*)userdata;
str->append(buffer, bytes);
To append data to buffer those things should be defined:
allowed size of destination buffer
amount of data in buffer present in destination buffer
amount of data to be copied to destination buffer
In C realloc() can be used to create new buffer with content of old one.. that may or may not change location of buffer. In C++ there is flavor of new operator that allows similar action.
If we assume that data stored is strictly null-terminated string (but even that wasn't specified!) then 2nd and 3rd are known - the size of buffer is unknown to append() is size of buffer. Therefore, the function
void append(void *y, char *z);
looks either unfit for the task or very unsafe and possibly ill-defined, unless void y is actually some structure or class (but passing that as void???) .
You did not provide implementation OR description of it. By the look is should be rather limited one. We should pre-allocate a buffer of proper size and ensure that append() won't run outside of its bounds. It cannot reallocate target buffer, so it is limited by already allocated memory. To actually reallocate target buffer append would have void **y or void &* y as formal parameter (realloc() may change pointer and does copy data from old buffer to new buffer)
This poses an architecture problem - ownership of buffer. If we pass buffer we control, we can allocate it properly and pass it to append() OR pass ownership to append() so it would reallocate it. If we don't, we have to create a temporal buffer... but can we use that temporal buffer afterwards?
The point is moot unless you are using custom header write function. user data pointer is CURLOPT_HEADERDATA, which is either pointer to valid FILE and you should _fwrite() data to it... Or, if you are implementing CURLOPT_WRITEFUNCTION and CURLOPT_READFUNCTION callback, that pointer can be used at discretion of designer of callbacks, as a pointer to some useful data container (libcurl uses fwrite as default callback).
Your question looks more referring to C (not C++) approach. Then you need the following:
know the size of the y
realloc the y to be of the size + 1
memcpy/memmove y to the new place
set the last byte of the new buffer to z
return to the user the pointer and the size of the new buffer
free the old buffer y (depends on the need).
In C++ hovewer you need to use some container like std::vector, which will allow you to append one byte.
I am coming back to C++ after many years (and never went so deeply before), so please indulge with me for my noobness :)
I have, as a field of a struct, a *void which points to some data. The memory pointed by the struct is filled with different data after every call of a given function, so I'd like to "cache" the results after every function call in a vector, in order to obtain all data in the end. How can I achieve this goal?
I declared a static vector<unsigned char> vectorBuffer; and tried vectorBuffer.insert(vectorBuffer.end(), (unsigned char*)myStruct->thePointer) and vectorBuffer.push_back((unsigned char*)myStruct->thePointer) but obviously I'm getting errors. Which is the correct way to obtain such a result?
Thanks
EDIT: I know the size of the void* as well, since I have another field in my struct that refreshes as the data do.
Something along these lines is what you want to do to buffer the data fragmented over multiple callbacks:
#include <vector>
std::vector<char> buffer;
buffer.insert(buffer.end(), data, data+length);
Assuming that data is your data coming in the callback and length is available too.
You should declare the vector with
static vector<unsigned char *> vectorBuffer;
(it's an array of unsigned character pointers, not unsigned characters).
To save the data (assuming you know the size),
unsigned char *p = new unsigned char[myStruct->bufferLength];
memcpy((void *) p, myStruct->thePointer, myStruct->bufferLength);
vectorBuffer.push_back(p);
You can then keep track of the length with
static vector<unsigned char *> bufferLength;
bufferLength.push_back(myStruct->bufferLength);
Note that you will need to free the memory afterwards.
I want to use the gets() function for std::string str. But I get an error:
invalid conversion from 'const char*' to 'char*'
The strlen() function on the other hand doesn't give any error when I write
int len = strlen(str.c_str())
but gets(NUM.c_str()) gives the error.
Any suggestions? I need to use std::string and gets() as my character size is unknown.
c_str() returns a const pointer to the string contents, so you cannot use that to modify the string.
Even if you did circumvent that (which you really shouldn't), it would be impossible to change the size of the string (as you're trying to do), since that's managed by the string object. The best you could do is write over memory that may not be owned by the string, causing crashes or other undefined behaviour.
Even if you did have a suitable array to write to, don't use gets. There is no way to prevent it from overflowing the buffer, if the input line is too long. It's been deprecated in C since at least 1999.
Any suggestions?
std::getline(std::cin, NUM);
Where to begin...
(1) Firstly, gets expects a char*, but std::string::c_str() returns const char*. The purpose of std::string::c_str() is merely to provide a C-string representation of the string data - it is NOT meant to provide a writable buffer. The function gets needs a writable character buffer.
(2) Secondly, you can use std::string as a writable character buffer using the [] operator, by saying:
std::string s(100); // create a buffer of size 100
char* buf = &s[0];
This is guaranteed to work properly in C++11, however in earlier versions of C++, it is not necessarily guaranteed that std::string provide a contiguous memory buffer. (Although, in practice, it almost always does.) Still, if you want a buffer, it's better to use std::vector<char>.
(3) Finally, don't use gets, EVER. It's ridiculously dangerous and makes your program prone to buffer overflow and shellcode injection attacks. The problem is that gets doesn't include a size parameter, so in practice the program will read any arbitrary amount of bytes into the buffer, potentially overflowing the buffer and resulting in undefined behavior. This has historically been an attack vector for many hackers, especially when gets is used with a stack array. The function fgets should be used instead in C, because it lets you specify a maximum read size parameter. In C++, it's better to use std::getline, because it works directly with an std::string object and therefore you don't need to worry about the size of the buffer.
I want to use gets() function
gets() is C. When possible it is better using C++ features
Instead try getline like this:-
std::getline(std::cin, NUM);
And as Jrok mentioned in the comments:-
Make the world a better place - don't use gets
In addition to the problems with trying to use gets in the first place, you cannot use it on a buffer returned from c_str() as the buffer is a const char* (which points to the string buffer held by the std::string object. If you insist on using gets(), you would need to create your own buffer to read into:
char buffer[1024] = {0}; // temporary buffer
gets(buffer); // read from stdin into the buffer
std::string s(buffer); // store the contents of the buffer in a std::string
For an explanation and example of why you should never use gets: http://www.gidnetwork.com/b-56.html
A much better approach is to
std::string s; // the std::string you are using
std::getline(std::cin, s); // read the line
I am new to C++, and haven't quite grasped all the concepts yet, so i am perplexed at why this function does not work. I am currently not at home, so i cannot post the compiler error just yet, i will do it as soon as i get home.
Here is the function.
const char * ConvertToChar(std::string input1, std::string input2) {
// Create a string that you want converted
std::stringstream ss;
// Streams the two strings together
ss << input1 << input2;
// outputs it into a string
std::string msg = ss.str();
//Creating the character the string will go in; be sure it is large enough so you don't overflow the array
cont char * cstr[80];
//Copies the string into the char array. Thus allowing it to be used elsewhere.
strcpy(cstr, msg.c_str());
return * cstr;
}
It is made to concatenate and convert two strings together to return a const char *. That is because the function i want to use it with requires a const char pointer to be passed through.
The code returns a pointer to a local (stack) variable. When the caller gets this pointer that local variable doesn't exist any more. This is often called dangling reference.
If you want to convert std::string to a c-style string use std::string::c_str().
So, to concatenate two strings and get a c-style string do:
std::string input1 = ...;
std::string input2 = ...;
// concatenate
std::string s = input1 + input2;
// get a c-style string
char const* cstr = s.c_str();
// cstr becomes invalid when s is changed or destroyed
Without knowing what the error is, it's hard to say, but this
line:
const char* cstr[80];
seems wrong: it creates an array of 80 pointers; when it
implicitly converts to a pointer, the type will be char
const**, which should give an error when it is passed as an
argument to strcpy, and the dereference in the return
statement is the same as if you wrote cstr[0], and returns the
first pointer in the array—since the contents of the array
have never been initialized, this is undefined behavior.
Before you go any further, you have to define what the function
should return—not only its type, but where the pointed to
memory will reside. There are three possible solutions to this:
Use a local static for the buffer:
This solution was
frequently used in early C, and is still present in a number of
functions in the C library. It has two major defects: 1)
successive calls will overwrite the results, so the client code
must make its own copy before calling the function again, and 2)
it isn't thread safe. (The second issue can be avoided by using
thread local storage.) In cases like yours, it also has the
problem that the buffer must be big enough for the data, which
probably requires dynamic allocation, which adds to the
complexity.
Return a pointer to dynamically allocated memory:
This works well in theory, but requires the client code to free
the memory. This must be rigorously documented, and is
extremely error prone.
Require the client code to provide the buffer:
This is probably the best solution in modern code, but it does
mean that you need extra parameters for the address and the
length of the buffer.
In addition to this: there's no need to use std::ostringstream
if all you're doing is concatenating; just add the two strings.
Whatever solution you use, verify that the results will fit.
I need to save packet state for a while.
So I read the packet data which is represented as unsigned char* and than I create a record with this data and save the record in the list for a while.
Which will be a better way to represent the packet in the record as char* or as char[].
How do i copy the read data ( unsigned char ) to both options :
To unsigned char[] and to unsigned char*
I need to copy the data because each time I read packet it will be readed to the same char*,so when I save it for a while I need to copy data first
If the packet data is binary I'd prefer using std::vector to store the data, as opposed to one of the C strXXX functions, to avoid issues with a potential NULL character existing in the data stream. Most strXXX functions look for NULL characters and truncate their operation. Since the data is not a string, I'd also avoid std::string for this task.
std::vector<unsigned char> v( buf, buf + datalen );
The vector constructor will copy all the data from buf[0] to buf[datalen - 1] and will deallocate the memory when the vector goes out of scope. You can get a pointer to the underlying buffer using v.data() or &v[0].
So, it sounds like you need to save the data from multiple packets in a list until some point in the future.
If it was me, I'd use std::string or std::vector normally because that removes allocation issues and is generally plenty fast.
If you do intend to use char* or char[], then you'd want to use char*. Declaring a variable like "char buf[1024];" allocates it on the stack, which means that when that function returns it goes away. To save it in a list, you'd need to dynamically allocate it, so you would do something like "char *buf = new char[packet.size];" and then copy the data and store the pointer and the length of the data in your list (or, as I said before, use std::string which avoids keeping the length separately).
How do you copy the data?
Probably memcpy. The strcpy function would have problems with data which can have nul characters in it, which is common in networking situations. So, something like:
char *buf = new char[packet_length];
memcpy(buf, packet_data, packet_length);
// Put buf and packet_length into a structure in your list.