views:

260

answers:

6

I'm investigating a memory leak and from what I see, the problem looks like this:

int main(){
    char *cp = 0;
    func(cp);
    //code
    delete[] cp;
}

void func(char *cp){
    cp = new char[100];
}

At the //code comment, I expected cp to point to the allocated memory, but it still is a null pointer meaning I never delete the memory. What am I doing wroing?

+5  A: 

The parameter cp is a local variable of the function - changing it does not alter anything outside the function. A better way to write the function is:

char * func(){
    return new char[100];
}

And not to do directly with your question, but you should probably be using std::string and std::vector rather than dynamically allocated arrays.

anon
Hmm, two downvotes. Not that I care particularly, but others here might benefit from knowing what is wrong with this answer.
anon
Nothing that I can see. If you're going to point out something like the C++ features you mentioned, I think it's probably good to also add a part about not hard-coding the array size. Additionally, if you're going to use those particular features, you probably want to pass a pointer to one in by reference to create it, or else pass an already-created one in by reference to avoid the copy constructor penalty... but there's really nothing WRONG with this answer.
San Jacinto
Pointers don't have a copy constructor.
anon
I was referring to std::String and std::vector when speaking of "the c++ features you mentioned." I did mangle my reply, so sorry for the confusion. For what you have, I would add "don't hardcode...". the rest is referring to the "c++ features."
San Jacinto
+5  A: 

You are assigning cp the value of the allocated memory. However, that's a variable on the stack: a copy of the cp in main! cp is local to the function you're in.

What you want is a reference:

void func(char *& cp)

This will alias cp to be the parameter passed in.

GMan
+1  A: 

You're passing in cbuf, not cp.

Skilldrick
even if he was passing *cp, it would remain pointing to 0 after //code
Ciwee
That doesn't matter, because you're also passing it by value.
mobrule
+4  A: 
void func(char *cp){
    cp = new char[100];
}

In this function, char *cp is a "pointer being passed by copy" what means that they are pointing to the same memory address but they are not the same pointer. When you change the pointer inside, making it to point somewhere else, the original pointer that has been passed will keep pointing to 0.

Ciwee
Thanks, solved it fine. Very clear explanation.
David
@David: Thanks :)
Ciwee
+1  A: 

The function is only changing a COPY of cp. Use a reference instead.

Jesse Emond
A: 

As GMan and Neil mentioned, in order to work you will have to change func to:

char* func();

or void func(char*& p);

which will solve your immediate problem.

There is, however, a maintenance problem. In either case, func returns a pointer. What is not clear to the user of func is that returned pointer will have to be deleted. For this reason, generally avoid this construct unless 100% necessary. Rather:

  1. Help the user allocate the correct amount of memory which can then be passed to func
  2. Use an object to store the allocated memory. The object can then delete the character array when it is destructed.

So for C++ code,I would recommend:


class CBuf
{
public
    CBuf() 
    {
        iBuf = new char[100];
    }
    ~CBuf
    {
        delete[] iBuf;
    }
    char* func()
    {
        //do stuff;
        return iBuf;
    }
private:
    char* iBuf;
};

int main()
    {
    CBuf cb;
    char* mychar = cb.func();
    //do stuff with character array

    //destructor gets called here because cb goes out of scope
    }

However, in C programming especially, it might be 100% necessary to have some sort function to create the array. Therefore in C programming you can replace the destructor with a CreateCBuf and DestroyCBuf function. In this way the user of your library will know that the buffer returned needs to be destroyed.

doron
May I ask what's wrong with `std::vector`?
GMan
std:vector is fine. It handles all the memory management for you. The problem in OPs example is that ownership is very unclear.
doron