Pass by pointer not updating memory address - c++

I am wanting to read back data stored in a buffer. I have a function that takes a pointer to an unsigned char array as a parameter. I wanted this parameter to be populated (point to) the address of the buffer I wish to obtain.
Inside the function I can see while debugging that the parameter passed in is being updated correctly (Mock class), however once I return from this function to the calling method (Connection class), all the data is lost.
Please can anyone help me understand why this is?
Thanks in Advance
Unit Test
/// Unit test fails as expected data is not in the buffer
TEST(MemoryTest, TestWriteAndRead)
{
Connection* p_conneciton = new Connection();
/// Write
uint8_t txBuffer[_USB_PACKET_SIZE] = _CMD;
ASSERT_EQ(p_memory->Write(txBuffer), true);
/// Read
uint8_t* rxBuffer;
ASSERT_EQ(p_memory->Read((unsigned char*)&rxBuffer), true);
ASSERT_EQ(rxBuffer[0], 0xaa);
}
Connection Class
/// Information is lost here in _pu8_buffer
bool Connection::Read(uint8_t* _pu8_buffer)
{
int i_bytesRead = 0;
while(i_bytesRead != SIZE) {
i_bytesRead = read_timeout(_pu8_buffer, _PACKET_SIZE);
if ( i_bytesRead < _PACKET_SIZE) {
return false;
}
}
return true;
}
Mock Class
/// Information is copied correctly here from mpuc_data to data
int Mock:read_timeout(unsigned char* data, size_t length)
{
if (data == nullptr) {
return -1;
}
data = mpuc_data;
return 0;
}

You need to pass by reference parameters you want to modify. If you want to modify the value of a pointer, it's the pointer you need to pass by reference -that it is a reference itself (to something else) won't help.
Try
int Mock:read_timeout(unsigned char*& data, size_t length)
{
if (data == nullptr) {
return -1;
}
data = mpuc_data;
return 0;
}
this way, _pu8_buffer will actually point the same as mpuc_data after each call to read_timeout. You can do the same with the function Read.
In general, pay attention to levels of indirection. With
uint8_t* rxBuffer;
ASSERT_EQ(p_memory->Read((unsigned char*)&rxBuffer), true);
you're taking the address of a uint8_t*, obtaining a uint8_t**, pointer to a pointer. Then you cast it to unsigned char* -a simple, not double pointer! (and then implicitly to uint8_t* when it becomes a parameter) It can't end well... and it ends in trying to read an array of chars where the first 4 or 8 are in fact the bytes of your pointer, followed by other garbage.
Taking the address of a pointer is correct if you want to modify it, but then you need to expect a uint8_t** on the other side, and refer to it as *_pu8_buffer.

/// Information is lost here in _pu8_buffer
bool Connection::Read(uint8_t* _pu8_buffer)
{
int i_bytesRead = 0;
while(i_bytesRead != SIZE) {
i_bytesRead = read_timeout(_pu8_buffer, _PACKET_SIZE);
if ( i_bytesRead < _PACKET_SIZE) {
return false;
}
}
return true;
}
Calling this function gets you a copy of the pointer you passed to it. Meaning that if you change the location that the pointer is pointing to you only change the local copy.
You either change the way you set the data in read_timeout to:
*data = mpuc_data;
Or you pass a pointer to a pointer (uint8_t**) in Connection::Read and call read_timeout(&_pu8_buffer, _PACKET_SIZE);
Also, the way you currently have it &rxBuffer is not correct, it should be rxBuffer. Only pass the address if you change the signature to a uint8_t**.

Related

Appending char pointer after shallow copying

I have made two object of string class each having char* pointer . By shallow copying, i have copied the first object into second object by shallow copying . Now both of them pointing at the same location.
What i have to do is append the char pointer through one object so that it does not make another but increase the size of original char pointer so second object point to the same location.
void String::append(char c) {
auto_ptr<StringBuffer> newdata(new StringBuffer);
newdata.get()->reserve(this->_str->length() + 1);
newdata.get()->smartCopy(this->_str);
this->_str = newdata.release();
this->_str->append(c);
}
The wrapper class of StringBuffer
void StringBuffer::reserve(int n) {
if (_length < n) {
int newlength = n; //max(_length*2,n);
char* newbuf = new char[newlength];
//copy contents of the stored string in the new buffer
revSmartCopy(newbuf);
//return stuff from the new buffer to the stored buffer
delete[] this->_strbuf;
this->_strbuf = newbuf;
this->_length = newlength;
newbuf = 0;
}
}
void StringBuffer::revSmartCopy(char* newString) {
int it = 0;
while (it < this->_length) {
newString[it] = this->_strbuf[it];
it++;
}
}
void StringBuffer::smartCopy(StringBuffer* newString) {
int shorterLength = 0;
(this->_length < newString->_length) ? shorterLength = this->_length : shorterLength = newString->_length;
int it = 0;
while (it < shorterLength) {
*_strbuf++ = *(newString->_strbuf)++;
it++;
}
}
This code is making another copying with object from whom we append pointing to new copy and older one pointing to previous
Let's assume you're doing this as an exercise, because it makes no sense otherwise.
You can't reallocate a pointer to a different size and have it at the same pointer value; this might happen accidentally, but it's impossible to enforce. Since the two objects are independent, the only way to make this work is double indirection - the pointer in your object points to a second pointer, which is the pointer to the character buffer.
You're also going to have a problem with destruction, because you have multiple objects with the same pointer. The standard library has std::shared_ptr to solve this very problem. If a pointer is shared between different objects, use shared_ptr to hold it.
Since there will only be one pointer to the actual character buffer, you can use std::unique_ptr for that one. You could use std::auto_ptr instead, and it will work fine as long as you don't try to copy it, but unique_ptr is a far better choice.

Returning pointer to global array from function

I am not experienced enough in C/C++ programming, so I am asking for an explanation.
I have global array declared as following. ASAK it is located in seperate memory part of initialized global memory in context of process memory.
Sensor sensorsArray[SENSORS_COUNT] = {dhtTempSensor, dhtHumSensor, dallasTempSensor, waterLevelSensor};
I need to find element in this array and return pointer to it (because I am going to change its value). I have written such function.
Sensor* getSensorById(uint32_t id) {
for (int i = 0; i < SENSORS_COUNT; i++) {
Sensor* current = &sensorsArray[i];
if (current->sensorId == id) {
return current;
}
}
}
Will it work properly, I am not sure about current pointer, it is allocated on the stack so it is in function scope, will it be poped from the stack after function ends ? Or it will work properly.
I mean not pointer(address of array element which is taken using &sensorsArray[i]), but current pointer variable which contains address of erray element, will it be poped or not.
Please suggest best way how to do in such situation.
Thx.
You aren't covering all the possible returning cases of the function, namely, the case when the id does not match with any of the ids of the array.
Currently the pointer will return the last element of the array if there is no match.
You could correct that by defining the pointer Sensor* sensor_found = nullptr outside the for loop such that if there is no sensor found the return value is still valid, i.e. nullptr and assigning the found value of current to sensor_found, only if there is a match.
Sensor* getSensorById(uint32_t id) {
Sensor* sensor_found = nullptr;
for (int i = 0; i < SENSORS_COUNT; i++) {
Sensor* current = &sensorsArray[i];
if (current->sensorId == id) {
sensor_found = current;
break;
}
}
return sensor_found;
}
If the id found return current, otherwise, if there is no match return nullptr.
you want to make sure that the function has a valid return statement on its every execution path. In you current implementation if the id is not matched then the return value of Sensor* is not set and will contain random bytes. One wau to deal with this situation is to return the nullptr to indicate that the Sensor was not found. Other than that, ythe function will work properly.
Sensor* getSensorById(uint32_t id) {
for (int i = 0; i < SENSORS_COUNT; i++) {
Sensor* current = &sensorsArray[i];
if (current->sensorId == id) {
return current;
}
}
return nullptr; // id not matched
}
Your code is fine (as the comments suggest). The reason why you don't need to worry about the current pointer becoming invalid is because the memory that it points to (ie, the global array) stays valid beyond the scope of the function. Just because you happen to create a pointer (and remember, a pointer is really just a number that corresponds to some place in memory) to that memory doesn't mean that it becomes invalid when used elsewhere.
When you say Sensor *current = &sensorArray[i];, then if sensorArray[i] is stored at, say, position 0x10 in memory, then current = 0x10, and no matter where it is used, then sensorArray[i] will still be at memory location 0x10. When you assign a value to current, you are not copying the value from the sensor, you are merely getting a pointer to it.

Convert (void **) to object in C++

I am trying to convert a (void**) object into a queue in C++.
In one file HashTableVoid.cc I use the method find to:
bool HashTableVoid::find( const char * key, void ** data)
{
// Add implementation here
int i = hash(key);
HashTableVoidEntry * node = _buckets[i];
while(node){
if(strcmp(node->_key,key) == 0)
{
*data = node->_data;
return true;
}
node = node->_next;
}
return false;
}
And in IRCServer.cc I used
void IRCServer::sendMessage(int fd, const char * user, const char * password, const char * args)
{
//Get user's room
//Write to room messages
char * temp;
temp = strdup(args);
void ** q;
queue<char*> data;
const char * room = //Found Room;
communication.find(room, q);
data = (queue<char*>) ((char *)q);
data.push(temp);
//Make sure only 100 elements or less in the list
while(data.size() > 100)
data.pop();
}
I am creating void ** q to pass as a parameter to communication. The variable communication is a HashTable where the key is the room name and the value is a unique queue of messages. I am having trouble converting the void object to a queue. I can't change the find method.
Two problems that I can see directly:
First you call find without initializing q, so it doesn't actually point anywhere. So in the find function when you dereference do *data you dereference an unknown pointer leading to undefined behavior. I think what you're supposed to do is to declare q to be a single pointer, and then pass the address of that to the find function (emulating pass by reference). Like
void *q;
...
communication.find(room, &q);
However, since you're programming in C++ I don't see a reasong to use double-pointer to emulate pass by reference, since C++ have it built-in:
bool HashTableVoid::find( const char * key, void *& data);
The above declares the argument data as a reference to a pointer.
The second problem is your assignment from the pointer q to the variable data:
data = (queue<char*>) ((char *)q);
What you have now (without the changes above), q is a pointer to a pointer, and you try to use it as a single pointer, which you then try to cast to a value. A pointer is not a value, and can never be.
Maybe you mean
data = *reinterpret_cast<std::queue<char*>*>(q); // After change detailed above

Memory corruption when passing data to method

I'm having trouble passing data by reference to a given method - when the method access the data, it's corrupted, but I'm sure that when the method is called it's not (by debuggin). Here is something like the code:
//Calling code
const void* tempPointer = array.mid(readerPos,RE8K_ICDEF_HARMONICS_SIZE).constData();
const re8k_ics_harmonics* const newStruct = static_cast< const re8k_ics_harmonics* >(tempPointer);
DSInstance().updateHarmonics(*newStruct);
//method
void DataStream::updateHarmonics(const re8k_ics_harmonics &infoHarmonics, ...)
{
//Use infoHarmonics
}
So if I use the debugger and go put a breakpoint in the "calling code" in the last line and watch what is in newStruct, I see that the data is perfect as it should be. Than the method is called and I put a new breakpoint (or go "next line") till enter the first line inside updateHarmonics, and when I see the content of infoHarmonics, I see part of the data corrupted and part of it is there.
Why is the code becoming corrupted? What should I do? :x
Additional info:
array is a Qt's QByteArray
readerPos is a int that iterates over the QByteArray from the point data should be read
constData() returns a const char*
Thanks,
Momergil
QByteArray QByteArray::mid (int pos, int len = -1 ) const
This function returns object by value, so in the line
const void* tempPointer = array.mid(readerPos,
RE8K_ICDEF_HARMONICS_SIZE).constData();
you are taking a pointer to temporary data. This pointer is not valid just in the next line. You should create object on the heap or use stack allocated instance, e.g:
QByteArray midQ = array.mid(readerPos, RE8K_ICDEF_HARMONICS_SIZE);
const void* tempPointer = midQ.constData(); // pointer valid as long
// as midQ breaths
const re8k_ics_harmonics* const newStruct =
static_cast< const re8k_ics_harmonics* >(tempPointer);
DSInstance().updateHarmonics(*newStruct);

Function is not changing the value of pointer

I think the code is self-explanatory:
MyClass* pointer = NULL;
changePointer( pointer );
if (pointer == NULL)
{
// it's entering here :(
}
void changePointer( MyClass* p)
{
MyClass* temp = NULL;
for (int i = 0; i < myContainer.size(); ++i)
{
p = &(myContainer[i]);
if (p == NULL)
{
// it's not entering here :)
}
}
}
The pointer is being passed by value, not by reference, so the original variable cannot be changed. You need to change the function signature to:
void changePointer(MyClass** p)
...and pass a pointer to the pointer:
changePointer(&pointer);
You'll need to make some corresponding changes in the body of the function, too.
You want to pass the pointer by reference, if you want to change what the pointer points to in the caller function
void changePointer(MyClass*& p)
You dont need to change how you call the function, or how you use p in the function. Now if you change the target of p inside the function, it will be changed in the original variable as well.
Is this what you are asking?