0

I have a little problem. I am writing a program in Visual C++ (VS 2013). And I want to make work code like this.

void Blob::ReadBytes(BYTE* target, DWORD position, DWORD readLength)
{
    // check
    if (position + readLength > this->Length)
    {
        // clean if it allocated memmory, because need return nullptr
        target = static_cast<BYTE*>(realloc(target, 0));
        return;
    }

    // allocate memmory
    target = static_cast<BYTE*>(realloc(target, readLength));

    memmove(target, this->Data + position, readLength);
}

It works, target allocated and initialized. But when I return from this function, target links to NULL.

for example:

...
Blob b;
BYTE* data = new BYTE[4];
data[0] = 'a';
data[1] = 'b';
data[2] = 'c';
data[3] = 'd';

b.Append(data, 4); // Add data to Blob

BYTE* bytes = nullptr;
b.ReadBytes(bytes, 0, 3); 
// There bytes = NULL
...

Where Blob is like

class Blob
{
    public:
    ...
    BYTE* Data;
    DWORD Length;
    ...
}

What I can do to save new allocated scope after function returns? One of solutions is to make a new object Blob and allocate its field like this:

Blob Blob::ReadBytes(DWORD position, DWORD readLength)
{
    Blob blob;

    // check
    if (position + readLength > this->Length)
    {
            blob.Data = static_cast<BYTE*>(realloc(blob.Data, 0));
            return Blob();
    }

    // allocate memmory
    blob.Data = static_cast<BYTE*>(realloc(blob.Data, readLength));

    memmove(blob.Data, this->Data + position, readLength);

    blob.Length = readLength;

    return blob;
}

And in this case all work well. But what if I want get only BYTE* pointer with allocated memory? May be I do not understand something?

rcs
  • 6,713
  • 12
  • 53
  • 75
velgames
  • 35
  • 1
  • 10

2 Answers2

2

You need to either return target or use a pointer of pointer of BYTE:

BYTE* Blob::ReadBytes(DWORD position, DWORD readLength)
{
    BYTE* target, 
    // your code
    return target ;
}

BYTE *bytes = Blob::ReadBytes(...) ;

Or:

void Blob::ReadBytes(BYTE** target, DWORD position, DWORD readLength)
{
    // check
    if (position + readLength > this->Length)
    {
        // clean if it allocated memmory, because need return nullptr
        *target = static_cast<BYTE*>(realloc(target, 0));
        return;
    }

    // allocate memmory
    *target = static_cast<BYTE*>(realloc(target, readLength));

    memmove(*target, this->Data + position, readLength);
}

BYTE *bytes ;
Blob::ReadBytes (&bytes, ...) ;

Remember that when you have function fn (TYPE var), the value you assigned to var is only kept for the scope of the function:

void fn (BYTE var) {
    var = 8 ;
}

BYTE myVar = 4 ;
fn (myVar) ;
// myVar still equals 4

This is the same for pointer:

void fn (BYTE *bytes) {
    bytes = static_cast<BYTE*>(realloc(target, readLength));
}

BYTE *bytes = 0 ;
fn (bytes) ;
// bytes still equals 0

If you want to assign a value to a given parameter, you need to use a pointer, and then dereference it using *p.

  • If you want to retrieve a BYTE, then you use a BYTE*, and you do *pb = 4.
  • If you want to retrieve a BYTE*, then you use a BYTE**, and you do *ppb = new BYTE[...] (or whatever you want).
void gn (BYTE **bytes) {
    *bytes = static_cast<BYTE*>(realloc(target, readLength));
}

BYTE *bytes = 0 ;
fn (&bytes); // Don't forget to send a pointer to bytes using &bytes, not simply bytes!
// bytes is not equals to 0 anymore!
Holt
  • 36,600
  • 7
  • 92
  • 139
1

This is because the 'targets' name is local to your function. If you want to change the value of a variable in the calling function, you have to pass a pointer to or a reference to the variable, or return as a value (as in your 2nd example).

You are passing a pointer to some memory, not a pointer to the variable that points to the memory.

So you could declare your function

void Blob::ReadBytes(BYTE* &target, DWORD position, DWORD readLength)

which'd have the advantage it wouldn't require rewriting all your code, though it has the disadvantage it's not immediately apparent that it alters the passed in variable if you can't see the declaration anywhere.

or you could declare it as

void Blob::ReadBytes(BYTE** target, DWORD position, DWORD readLength)

which makes it fairly clear what you are doing at the expense of some unreadabilility in the implementation.

Tom Tanner
  • 9,244
  • 3
  • 33
  • 61