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.
Related
How can I convert QByteArray coming from QFile::readAll() into a uint8_t array(uint8_t*)?
I tried static_cast<>() but didn't seemed to work for whole array.
examples of what I've done with static_cast:
uint8_t* x = new uint8_t;
x[0] = static_cast<uint8_t>(testWav.readAll()[0]);
uint8_t* x = new uint8_t;
*x = static_cast<uint8_t>(*testWav.readAll());
etc. didn't work
This doesn't do what you want.
uint8_t* x = new uint8_t;
x[0] = static_cast<uint8_t>(testWav.readAll()[0]);
This way you copy only [0] element of array. The rest of allocated memory stay uninitialized
This cannot work at all:
uint8_t* x = new uint8_t;
*x = static_cast<uint8_t>(*testWav.readAll());
QByteArray is a class-type of dynamic container, so you can't use static_cast to access its data as an array, it's a principally different, incompatible data structure. And you're still assigning only the first element: *x is an equivalent of x[0].
QByteArray has method QByteArray::data() which returns a pointer to char*:
https://doc.qt.io/qt-6/qbytearray.html#data
The pointer returned by data() isn't owning one and points to memory allocated by class, so data contained in QByteArray which returned by readAll() will cease to exist at end of statement containing it, unless it's assigned to a more persistent storage:
QByteArray fileContent = file.readAll();
char *buffer = fileContent.data();
Result of fileContent.size() would give the actual size of buffer. Note that in some cases it's more convenient to work with QByteArray instead of a raw pointer. You need conversion ONLY if you have to use some API taking raw pointer or face some performance issues.
I think first you need to know that a pointer is not an array. And that you cannot assing a c-array as a whole.
Then you should reconsider if you actually need to convert anything. QByteArray grants you access to the underlying array via its data member. (I find it a bit unfortunate that QByteArray is based on char rather than unsigned char, so you'd want to check whether char is signed or not).
Eventually, if you still want, you can write a loop to copy elements from the QByteArray to another array.
I am fairly new at C++ and am trying to understand how memory manipulation works. I am used to Java and Python and haven't really been exposed to this.
I am working on a project that has the following structure that doesn't quite make sense to me.
typedef struct
{
size_t size;
char *data;
} data_buffer;
This structure basically acts as a buffer, with a pointer to the data stored within the buffer and the size of the buffer to allow the program to know how large the buffer is when reading from it.
An example of how the program uses the buffer:
data_buffer buffer = {0};
//Manipulate data here so it contains pertinent information
CFile oFile;
oFile.Write(buffer.data, buffer.size);
The program mostly uses 3rd party code to read the data found within the buffer, so I am having trouble finding an example of how this is done. My main question is how do I read the contents of the buffer, given only a pointer to a character and a size? However, I would also like to understand how this actually works. From what I understand, memory is written to, with a pointer to where it starts and the size of the memory, so I should be able to just iterate through the memory locations, grabbing each character from memory and tagging it onto whatever structure I choose to use, like a CString or a string. Yet, I don't understand how to iterate through memory. Can someone help me understand this better? Thanks.
There is no reason you cannot use a std::string or CString to manipulate that data. (Use higher level constructs when they are available to you.)
To get the data into a std::string, use the constructor or assignment operator:
std::string s( buffer.data, buffer.size );
You can even stick it in a std::stringstream so you can treat the data buffer like a file:
std::istringstream ss( s );
int n;
ss >> n;
Things work similarly for the MFC string class.
To get the data from a string, you'll need to copy it over. Ideally, you'll be able to allocate the data's memory. Assuming you have data written into a stringstream
std::ostringstream ss;
ss << name << "," << employee_number;
You can then allocate the space you need using the function that creates the data_buffer object:
function_that_creates_a_data_buffer( buffer, ss.str().size() );
If there is no such function (there ought to be!) you must malloc() or new it yourself, as appropriate:
buffer.size = ss.str().size();
buffer.data = (char*)malloc( buffer.size );
Now just copy it:
ss.str().copy( buffer.data, buffer.size );
If your buffer needs a null-terminator (I have so far assumed it doesn't), make sure to add one to the size you allocate and set the last character to zero.
buffer.size = ss.str().size + 1;
buffer.data = new char[ buffer.size ];
ss.str().copy( buffer.data, buffer.size );
buffer.data[ buffer.size-1 ] = 0;
Make sure to look at the documentation for the various classes you will use.
Hope this helps.
A variable of type char* is actually a pointer to memory. Your struct contains data which is of type char* so it is a pointer to memory. (I suggest writing char* data instead of char *data, to help keep this clear.)
So you can use it as a starting point to look at your data. You can use another pointer to walk over the buffer.
char* bufferInspectorPointer;
bufferInspectorPointer = buffer.data;
bufferInspectorPointer will now point to the first byte of the buffer's data and
*bufferInsepectorPointer
will return the contents of the byte.
bufferInspectorPointer++
will advance the pointer to the next byte in the buffer.
You can do arithmetic with pointers in C++, so
bufferInspectorPointer - buffer.data
will tell you how many bytes you have covered. You can compare it to buffer.size to see how far you have left to go.
Since you tagged this as C++ I'd recommend using algorithms. You can get your iterators by using buffer.data as start and buffer.data + buffer.size as end. So to copy the memory into a std::string you'd do something like so:
std::string str(buffer.data, buffer.data + buffer.size);
Or perhaps to append onto a string:
str.reserve(str.size() + buffer.size);
std::copy(buffer.data, buffer.data + buffer.size, std::back_inserter(str));
Of course you can always chose a different end so long as it's not past buffer.data + buffer.size.
They are using a char array so that you can access each byte of the data buffer since size of char is usually 1 byte.
Reading the contents of the data buffer depends on the application. If you know how the internal data is encoded, you can write an unpacking function which selects chunks of the char array and convert/typecast it to the target variables.
eg: Lets say the data buffer is actually a list of integers of size 4 bytes.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char const* argv[])
{
//how the data buffer was probably filled
int *a = (int *)malloc(10*sizeof(int));
int i;
for(i=0;i<10;i++) {
a[i] = i;
}
char *data = (char *)a;
//how we could read from the data buffer
int *b = (int *)malloc(10*sizeof(int));
char *p = data;
for(i=0;i<10;i++) {
b[i]=(int )*p;
printf("got value %d\n",b[i]);
p += sizeof(int);
}
free(a);
free(b);
return 0;
}
Note: That being said, since this is C++, it would be much safer if we could avoid using char pointers and work with strings or vectors. Other answers have explored other options of how to handle such buffers properly in C++.
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've been trying to convert a const char to a char for the past 30 minutes.
Here's what I've got.
string atr;
getline(cin,atr); // Start off with a string because getline takes nothing else.
const char *buffA = atr.c_str(); // Create a const char of the string converted to a const char.
char *buff = ""; // Create a new char to hold the converted result.
strcat(buff,buffA); // Do the conversion.
parseargs(buff); // Pass the data on.
However, I get an unhandled exception. I have no idea why. I literally just typed 'try' into the console as my only argument.
Try using C++ instead of C idioms:
std::vector<char> data(atr.begin(), atr.end());
data.push_back('\0');
parseargs(&data[0]);
There are two things wrong with your code. First, you
initialize a char* with a string literal. This uses
a deprecated convertion; the type of a string literal is char
const[] (which converts to char const*, not to char*),
because any attempt to modify the literal is undefined behavior.
The second is that your string literal is only one char long,
so even if you could write to it, unless atr was empty, you're
writing beyond the end of the buffer.
You don't tell us anything about parseargs. If it doesn't
modify it's argument, you can just pass it atr.c_str(), and be
done with it. (If it's a legacy function which ignores const,
you may have to use a const_cast here.) If it does modify its
argument (say because it uses strtok), then you'll have to
explicitly push a '\0' onto the end of atr, and then pass it
&atr[0]. (Not a particularly clean solution, but if you're
not using atr afterwards, it should work.)
Both your contents of buff and buffA are in read-only memory of the process.
You will actually need to new your buff like
char* buff = new char[32];
This provides memory from the free-store and you can then strcat the string from buffA to buff.
You should prefer strncat, though to avoid buffer-overruns and delete your buff eventually.
This
char *buff = ""; // Create a new char to hold the converted result.
creates a char * that points to (probably read-only) memory of about 1 byte in extent. This:
strcat(buff,buffA); // Do the conversion.
attempts to overwrite that (probably read-only) memory of 1 or so bytes with an arbitrary string.
The chances are this will promptly crash. If the memory is read only, it will crash immediately. If the memory is not read only it will stomp over random data, resulting in very undefined behaviour.
Why on earth do you want to do that? Does parseArgs actually need a modifiable string? It's parsing arguments, it shouldn't need to change them. If it's really necessary, use a std::vector<char> and pass the address of the first element and hope that all it does is poke the contents of the array, rather than (say) running over the end.
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());