Link to home
Start Free TrialLog in
Avatar of chandas
chandas

asked on

dynamic memory allocation

Hi, why is it that when I write code like this..

char* p = new char[num];

//where num is calculated elsewhere dynamically

delete [] p;

I get a DAMAGE AFTER NORMAL BLOCK error as soon as I hit the delete [] p;
Avatar of nietod
nietod

The code you've shows us is fine.   The problem is elsewhere in your code.

the problem is that you are somhow altering memory slightly before or slightly after (most likely after) the ends of this memory block.  The debugger is detecting that this memory was altered, even though it had not been allocated (or cosndier allocated) and is warning you of this.

For example, A common mistake is to allocate character arrays for storign NUL terminated string that are one character too short because they don't consider the fact that a NUL character has to be stored at the end.  For example.

char *SourceString = "ABCD";
int StringLength = strlen(SourceString);
char *DestinationString = new char[StringLength];
strcpy(DestinationString,SourceString) // ERROR

This code created a character array that was 5 characters long.  But then it tries to store 5 characters "ABCD" and NULL in this array.

You need

char *SourceString = "ABCD";
int StringLength = strlen(SourceString);
char *DestinationString = new char[StringLength + 1];  // Extra space for NUL.
strcpy(DestinationString,SourceString);

If that doesn't help, post more code.
It is probably nothing to do with the new/delete pair (these are fine).

What is likely is that somewhere between new/delete you are writing past the array bounds (something like p[num] = 2).

The debug run-time cannot, however check for this kind of error until delete is called (hence the message at this point).

Check your code for writing past the end of the array (remember the valid part of the array is in the subscript range 0 to num-1).
Hi nietod, your post wasn't there when I made mine.
That or you read what I write and plagerized it all in 1 minute or less.  Hmmmm, I wonder....  :-)

>> The debug run-time cannot, however check for this
>> kind of error until delete is called (hence the message
>> at this point).
Actually it can, and in tough cases you can use this to help you locate the code that corrupts the memory.   VC has a function _CrtCheckMemory() then will check every single dynamically allocated block to make sure they are okay.  You can place calls to this function at stratigic points in your program to try to locate (narrow in on) the location where the memory is beign corrupted.

Note that this is a VC feature, its not part of the C++ langauge.  But message youa re getting is also a VC feature (a related one).  Soem other compilers may have similar features too, but these things are not part of the C++ langauge.
Avatar of chandas

ASKER

Hello again Nietod, good to see you're still active on EE :-) You wrote...

" char *SourceString = "ABCD";
int StringLength = strlen(SourceString);
char *DestinationString = new char[StringLength];
strcpy(DestinationString,SourceString) // ERROR

This code created a character array that was 5 characters long "

strlen(SourceString) should return 4 shouldn't it? ABCD is 4 characters. Or am I missing something?  
> Actually it can

Sure, I should have said something like 'typically does not'.  

> Or am I missing something?

yes, the terminating 0, strlen does indeed return 4, but you need 5 chars (one for the terminating 0 to store it - usually) - so to make this fragment work, you would need to do new char[StringLength+1];
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Now, I'm plagerizing you.  :-)
> Now, I'm plagerizing you.

amazing amount of it going on around here really...

Avatar of chandas

ASKER

Ok, got it. Thanks guys, I'll try that out :-)
Avatar of chandas

ASKER

Woah, wait a sec, but if I want to create a C-Style string that will hold a string of, say, currently selected text in an edit box, and I want to do this dynamically, can I be sure that it will be null terminated?

I mean, if I have...

char* p = new char[selectedTextNumber]

where selectedTextNumber is equal to the number of charcaters selected, does this mean I must actually say,

char* p = new char[selectedTextNumber + 1];
After you fix this I recommend you take steps to NEVEr make this mistake again.   C-style strings are beleived to be the leading cause of errors (crashes etc) in C programs.  C++ was developed to prevent these sorts of problems.

C++ provides string objects so you don't ever have to worry about these sort of problems. String objects "know" the length of the string they store and mor importantly they will expand their storae space as needed to hold any length string required--unless you run out of memory.  And they are first-class data types.  You can copy them using operator =, concatenate them using operator + compare them using == etc etc etc.   Say goodby to NUL-terminated strings.
>> can I be sure that it will be null terminated?
You always need to look at where the string is comming from to see how the length of the string is indicated.  In the case of the Windows OS, virutally all text-based strings will be NUL terminated.  But ther will be times when the data is not NUL terminated and a length vlaue is also returned to you in some way.  This should all be documented in the windows API help.     If the length is not mentioend in any way, its safe to assume that windows will use a NUL to mark the end.  That might or might not be true of code form other sources.

>> char* p = new char[selectedTextNumber + 1];
Yes.  

or better yet.

string p;

p = something.

Which is easier!  Which is safer!
Avatar of chandas

ASKER

Ok, point taken Nietod, but what do I do when I need to copy a const char* to a std::string object? Some Win32 API calls

IIRC, MENUITEMINFO's dwTypeData attribute is a const char* (not sure)

I think I've tried copying that to a std::string and got compatibility/conversion errors, which led me to C-Style strings. Incidentally, I've never used C and am scared half to death of pointers though I've been challenging my fears for a while now.

Thanks
Copying to a std::string is easy:

const char* str = "ABCD";
std::string s = str;
s = str;

To get a const char* from a std::string,

const char* str2 = s.c_str();

If you have a function that returns a char array, you still need to manage that manually to allocate it/delete it, when you copy to a string.
Actually to clarify a litle bit, c_str() does not actually "copy" anything.  It returns a pointer to a NUL-terminated string that is stored somewhere.  This string is of a temporary nature.  The string may be changed or even destroyed the next time a non-constant member function is called on the string object that returned it.  (its probalby best just to assume that the string will be destroyed the next time any member function of the string is invoked.)  So you don't want to do things like

const char *Function()
{
   string s = "ADFSAFASF";
   return s.c_str();
}

here s is destoyed--invoking a destructor which is deifintely not a constant member function so the pointer value it returns is no longer valid.  The value returned by this fucntion is unsafe for use.

If you need to preserve the NUL terminated string, then you need to copy it another location using strcpy() and the pointer returned by c_str().   However, this should not be needed often.  usually the only time you need to use NUL-terminated strigns is when dealing with the OS, and the OS will usually make its own copy of the string.