How to make a copy of a byte array in c code? - c++

I have the address of the first char in my byte array, and it's size:
const char *rawImageBytes, int size
And I want to copy the content to a different byte array. and then modify that one a bit.
This is whay I am doing now:
LOGI("FrameReceived will reach here 1");
modifiedRawImageBytes = rawImageBytes;
jint sizeWH = width * height;
jint quarter = sizeWH/4;
jint v0 = sizeWH + quarter;
for (int u = sizeWH, v = v0, o = sizeWH; u < v0; u++, v++, o += 2) {
modifiedRawImageBytes[o] = rawImageBytes[v]; // For NV21, V first
modifiedRawImageBytes[o + 1] = rawImageBytes[u]; // For NV21, U second
}
But I don't get the correct colours, as if I would to this in Java, instead of c++.
And I am assuming this happens, because I just do modifiedRawImageBytes = rawImageBytes; instead of actually copying the whole byte array, so that it can start in memory from another address pointer.
A bit of a beginner with c, so I'm lost at this, can someone help me understand what is done wrong?
PS: I am assuming that, because even if I send the rawImageBytes and not the modifiedRawImageBytes, it will still be modified

This is because const char * is a pointer. This mean it represent an address. So you guessed right, the new variable represent the same datas.
To avoid this you should create a copy.
char modifiedRawImageBytes[size];
//if the pointer come from function's param don't redeclare it ;)
std::memcpy(modifiedRawImageBytes, rawImageBytes, size*sizeof(char));
This code will allocate a new char array and then memcpy will copy in the previous array data in the new array.
Note that you need to includecstdio

Related

Accessing data from buffer created from boost

I am trying to access the data that is serialized using boost buffer function and would like to fill it into two vectors. I am having problem with address to fill the second vector. Following class shows the two vectors and how they are filled.
class LidarMeasurement {
private:
std::vector<uint32_t> _header;
std::vector<float> _azimuth;
public:
//The header consists of an array of uint32_t's in the following layout
enum Index : size_t {
HorizontalAngle,
ChannelCount,
SIZE
};
explicit LidarMeasurement(uint32_t NumOfChannels = 0u): _header(Index::SIZE + NumOfChannels, 0u) {
_header[Index::ChannelCount] = NumOfChannels;
}
// called before filling vectors
void Reset(uint32_t total_point_count) {
std::memset(_header.data() + Index::SIZE, 0, sizeof(uint32_t) * GetChannelCount());
_azimuth.clear();
_azimuth.reserve(total_point_count);
}
// after reset,Write point function starts filling vectors.. following function is called 104 times (not constant) before next reset
void WritePoint(uint32_t channel, float angle_hor) {
_header[Index::SIZE + channel] += 1u;
_azimuth.emplace_back(angle_hor);
}
uint32_t GetChannelCount() const {
return _header[Index::ChannelCount];
}
}
Once they are filled, its serialized and sent to a client. its serialized using the function below:
template <typename Sensor>
inline Buffer LidarSerializer::Serialize(
const Sensor &,
const LidarMeasurement &measurement,
Buffer &&output) {
std::array<boost::asio::const_buffer, 2u> seq = {
boost::asio::buffer(measurement._header),
boost::asio::buffer(measurement._azimuth)};
output.copy_from(seq);
return std::move(output);
}
Once I receive the serialized data, I need to put azimuth back to vector.
I am using the following function to get the vector. _begin is the address to the buffer.
std::vector<float> GetAzimuth(const uint32_t* _begin) const{
std::vector<float> localAzimuthMemCopy;
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));
end_azi = begin_azi + GetTotalPointCount();//Total point count is the addition of individual channel point counts (not shown here)
for(float* i = begin_azi; i < end_azi; i++){
localAzimuthMemCopy.emplace_back(*i);
}
return localAzimuthMemCopy;
}
However, the result i get has a memory offset. I am getting 104 values but the last 18 values are junk. vector is read from a wrong start address. What is wrong with the code?
The problem is caused bt wrong begin adress calculation.
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin )) + (sizeof(uint32_t) * (GetChannelCount() + Index::SIZE));
1) Pointer arithmetic requires only the pointer and number of elements to advance. Number of bytes the compiler should deduct by himself, based on the pointers type. So multiplication at sizeof(uint32_t) is redundant. The correct way of pointer advance is shown at float* end_azi = begin_azi + GetTotalPointCount();
2) Adress offset should be calculated for pointer to uint32_t type, and only then converted to pointer to float type.
So correct way of begin_azi should look this way:
begin_azi = const_cast<float*>(reinterpret_cast<const float*>(_begin + GetChannelCount() + Index::SIZE));
Why did it partially worked earlier? from cppreference
Pointer arithmetic
If the pointer P points at an element of an array with index I, then
P+N and N+P are pointers that point at an element of the same array with index I+N
P-N is a pointer that points at an element of the same array with index {tt|I-N}}
The behavior is defined only if both the original pointer and the result pointer are pointing at elements of the same array or one past the end of that array.
Noone knows where did the pointed begin_azi pointed after wrong calculation. So noone guarantee that the program will execute in correct or wrong way.

Storing differnt values in char* vector, all positions in array have same value

Let me explain my problem
First of all, imagine I randomly generated the number "5".
I want to convert this integer to a char* so I can display it using my
Draw_String() method.
I want to have "5" as the central position which would be [1] in a
char* array[2].
In position [0] I want the lower adjacent number "4"
In position [2] I want the higher adjacent number "6"
so
[0] = 4
[1] = 5
[2] = 6
Then I want to display the contents of the vector positions, like this.
4
5
6
However, my output is more like this:
5
5
5
No matter what number I generate, and no matter which operations I perform, I will only get the number "5" in all of my vectors positions.
Code
int startpoint = rand() % 7 + 1;
int assigner = -1;
for (int i = 0; i < 3; i++)
{
startpoint += assigner;
convert = std::to_string(startpoint);
char *converted = &convert[0u];
blocks.push_back(converted);
assigner++;
}
//spin around twice for visual effect.
for (int counter = 0; counter < 2; counter++)
{
Draw_String(drawY, drawX - 1, blocks.at(0));
Draw_String(drawY, drawX, blocks.at(1));
Draw_String(drawY, drawX + 1, blocks.at(2));
}
if anyone could help out I'd appreciate it.
Don't ask me to get rid of char*.
Your code has undefined behavior: it harvests a pointer to the internal string buffer from inside the conver string
char *converted = &convert[0u];
but the buffer can become invalid the next time convert string is re-assigned. The behavior that you see suggests that the buffer gets reused, rather than re-allocated, so the same pointer gets stored in the blocks vector.
The best solution would be to store std::string directly, because it would manage both copying and de-allocation for you:
std::vector<std::string> blocks;
...
blocks.push_back(std::to_string(startpoint));
If you insist on using pointers, make a copy of the string before adding it to the container:
char *copy = new char[strlen(converted)+1];
strcpy(copy, converted);
blocks.push_back(copy);
Now you are required to call delete[] on each element of blocks when you are done in order to avoid memory leaks.
If you needto use char* and not std::string than you need to allocate it and copy content of the string intead of copy the pointer.
instead of:
char *converted = &convert[0u];
use:
char *converted = malloc(convert.length() + 1); // number + '\0'
// can also use char *converted = new char[convert.length() + 1];
strcpy(converted, convert.c_str())
Now, no matter what happens to convert, you have control on your converted data. (take care to also delete it when you don't need it)
Otherwise when convert changes, converted can change or point to invalid data.
This is because in the original implementation converted is pointing to data that is managed by convert object.

Read/Write a single byte of a void* variable

If I have
void *temp = malloc(128);
memset(temp, 0 , 128);
And I want to read the first byte alone, following is what I'm doing.
char a[2];
strncpy(a, (char*)temp, 1);
int p = a[0];
//p will be zero in this case
Q1. I'm sure there is a more elegant way to achieve the same. If so, what would it be?
Q2. Is there a way I can alter the value of that single byte alone?
Say I want the first byte to have the value equivalent to the int value 48 (i.e. 00110000)
How would I do that?
I was able to make no progress with the write.
you can cast it to char * then access the memory
char *buff = temp;
char p = buff[0]; // read first byte

Could anyone please explain me this piece of code?

"header" is an object of a struct and you can consider header.img to have a value of 496. And header struct has 3 integer elements so is the value 12 bytes. (Considering 4 bytes a int)
double** MatrixBuffers = new double* [header.img];
MatrixBuffers[0] = new double[header.img* 12];
for (unsigned int i=1; i<header.img; ++i) {
MatrixBuffers[i] = MatrixBuffers[0] + i * 12;
}
globaldata.adv_MatrixBuffers = MatrixBuffers;
I understand that MatrixBuffers is a pointer to 496 doubles. But I don't understand what's happening in the second line.
MatrixBuffers[0] = new double[header.img* 12];
1.Does this mean MatrixBuffers[0] is a pointer to 496*12 doubles ?
2.What is happening in the for loop ?
3.Later in the code, MatrixBuffer[0] is being passed to a function. Does this mean I am passing a pointer that is the base address to MatrixBuffers[0] ?
For a double pointer you have to allocate memory for first as well as second dimension.
For the second level instead of allocating memory for every dimension he allocates memory at one shot
MatrixBuffers[0] = new double[header.img* 12];
Inside the for loop they move the address and assign the same to every index.
Instead he can also do like this inside the for loop and comment the line above the for loop
MatrixBuffers[i] = new double[header.img];

Is it possible to pass char[][] to a function requesting char**?

I am trying to call a function that takes char** as a parameter. Its job is to fill an array of strings (i.e. an array of char*). I know the max length of the strings, and I can pass the max number to fill as another parameter, so I was hoping to stack allocate it like this:
fill_my_strings(char** arr_str, int max_str); // function prototype
char fill_these[max_strings][max_chars_per_string]; // allocating chars
fill_my_strings(fill_these, max_strings); // please fill them!
Of course, I get the "cannot convert char[max_strings][max_chars_per_string] to char**" error.
I know this is some subtle (or not-so-subtle) problem with my understanding of the difference between arrays and pointers. I'm just not sure why it's not possible to pass this block of memory to something wanting a char** and have it fill in my stack-allocated chars. Could somebody please explain if this is possible, or if not, why not?
Is it possible to call a function like this without calling malloc / new?
The simple answer to your question is no; a two dimensional array is different than a pointer-to pointer type. Arrays decay to pointers to their first element, but pointers actually are that value.
The difference between these types is clear, if you cast both to char*
int x;
char *arr_pp[] = {"foo", "bar", "baz"};
char arr_2d[][4] = {"foo", "bar", "baz"};
char *cp = (char*)arr_pp;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
cp = (char*)arr_2d;
for(x=0; x<3; x++)
printf("%d ", cp[x]);
printf("\n");
The output (on my computer) is:
-80 -123 4
102 111 111
Where the first row is gibberish formed by the fact that I'm printing an address cast into bytes, and the second row is the ascii values of "foo".
In a function taking a char ** the compiler can't know to decay array types, which don't actually contain pointers.
Suppose you have n pointers to strings of m-1 maximum characters (m characters including the NULL).
So, in pure C:
sizeof(char[n][m]) will return n*m.
sizeof(char**) will return the size of a pointer in your architecture, probably 32 (if x86) or 64 (if x86_64).
char[n][m] actually allocates the n*m byte contiguously. char** allocates a single pointer. This pointer references a memory stripe of *n bytes. Each of these n pointers points to a memory stripe of m characters.
So, considering that sizeof(char) == u, if you declare char a[n][m], when you use a[i][j], the compiler understands *(a + i*m*u + j*u).
So, considering that sizeof(char *) == w, if you declare char **a, when you use a[i][j], the compiler understands ((a + i*w) + j*w).
Completely different data management.
The closes thing you could do to handle your special case is to create a char** variable, and populate it with the addresses of your stack allocated matrix.
char **tmp = malloc(max_strings * sizeof(char *));
int i;
for(i = 0; i < max_strings; i++){
tmp[i] = &(fill_these[i][0]); //you probably can't reference a char[][] with a single index - not confirmed
}
I am not sure why fill_my_strings() need a char** parameter. From your example, caller have already allocated the memory from stack. So using a char* should be OK.
But if you want to use char** or you can't modify the fill_my_strings() function, try following example code:
void fill_my_strings(char** arr_str, int max_chars_per_string, int max_strings)
{
for(int i = 0; i < max_strings; ++i)
{
//Make sure you have enough space
memcpy(*arr_str, "ABCD", sizeof("ABCD"));
*arr_str += max_chars_per_string;
}
}
char fill_these[max_strings][max_chars_per_string];
char* pointer = (char*)fill_these;
fill_my_strings(&pointer, max_strings, max_chars_per_string);
The obvious thing to do is build an index
In c use something like:
char string_list[num_strings][str_length];
// ...
char**index = calloc( (num_strings+1), sizeof(*index) ); // calloc insures NULL termination
for (int i=0; i<num_strings; ++i) {
index[i] = string_list[i]
}
In c++ prefer new[] to calloc;