Solved

dynamic memory allocation

Posted on 2001-07-25
16
226 Views
Last Modified: 2008-03-10
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;
0
Comment
Question by:chandas
  • 7
  • 5
  • 4
16 Comments
 
LVL 22

Expert Comment

by:nietod
ID: 6316842
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.
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6316843
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).
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6316848
Hi nietod, your post wasn't there when I made mine.
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 22

Expert Comment

by:nietod
ID: 6316976
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.
0
 

Author Comment

by:chandas
ID: 6317007
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?  
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6317035
> 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];
0
 
LVL 22

Accepted Solution

by:
nietod earned 50 total points
ID: 6317042
"ABCD" is 5 characters long.  This is sort of surprisizing, since C/C++ programers start counting from 0 (that is why I have 1 eye and 9 fingers.)

A C-style string is stored in an array of characters.  In C/C++ there is no way to dell how long an array is when you are given only a pointer to the start of the array.   For that reason the end of the string has to be marked in some way--since the length of the array is unavailable, then the length of the string in it is unavaialble.  In C/C++ a C-style string's end is usually marked by a NUL character.   (You could mark it in other ways, but strings created by the compiler are marked in this way).  A NUL character is a character whose binary value is 0.   So when you create a string literal like

const char *AString = "ABCD";

the compiler creates an array of 5 characters.  it places A in the first entry (index 0), B in the second (index 1), C in the third entry (index 2), D in the fourth (index 3), AND a 0 in the fifth entry (index 4).

If you do

char AStringp[4]  = "ABCD"; // Error

in C++ you will get a compiler error.  (not in C though).  The compiler tries to store 5 bytes in that 5 byte array.  again you need to do

char AStringp[5]  = "ABCD";

and you could also do

char AStringp[1000]  = "ABCD";

This allcoates room for 1000 characters (which would hold s NUL terminated string of a length  up tp 999, but it initializes it to hold a string of length 4, for the momemt.



When you use strlen() on a character array it simply searches the array looking for the NUL character that marks the end of the string and returns the number of characters before that NUL character.  it does not know now long the array is.  So if there is no NUL character in the array, strlen() wil continue searchign memory past the end of the array.  This could cause a crash.  or it might actually find a NUL character used eleswhere in memory and treat that as the end of the string

0
 
LVL 22

Expert Comment

by:nietod
ID: 6317043
Now, I'm plagerizing you.  :-)
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6317050
> Now, I'm plagerizing you.

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

0
 

Author Comment

by:chandas
ID: 6317082
Ok, got it. Thanks guys, I'll try that out :-)
0
 

Author Comment

by:chandas
ID: 6317118
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];
0
 
LVL 22

Expert Comment

by:nietod
ID: 6317121
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.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6317139
>> 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!
0
 

Author Comment

by:chandas
ID: 6317168
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
0
 
LVL 9

Expert Comment

by:jasonclarke
ID: 6317296
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.
0
 
LVL 22

Expert Comment

by:nietod
ID: 6317398
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.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Many modern programming languages support the concept of a property -- a class member that combines characteristics of both a data member and a method.  These are sometimes called "smart fields" because you can add logic that is applied automaticall…
Basic understanding on "OO- Object Orientation" is needed for designing a logical solution to solve a problem. Basic OOAD is a prerequisite for a coder to ensure that they follow the basic design of OO. This would help developers to understand the b…
The viewer will learn how to use the return statement in functions in C++. The video will also teach the user how to pass data to a function and have the function return data back for further processing.
The viewer will be introduced to the member functions push_back and pop_back of the vector class. The video will teach the difference between the two as well as how to use each one along with its functionality.

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question