Solved

dynamic memory allocation

Posted on 2001-07-25
16
213 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
Netscaler Common Configuration How To guides

If you use NetScaler you will want to see these guides. The NetScaler How To Guides show administrators how to get NetScaler up and configured by providing instructions for common scenarios and some not so common ones.

 
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

Are your AD admin tools letting you down?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Load and store *.pnm image file 1 86
returning a dereferenced pts in C++ 10 149
Setting nameservers after res_init fails doing res_query 2 97
Unable to start eclipse ? 17 141
Often, when implementing a feature, you won't know how certain events should be handled at the point where they occur and you'd rather defer to the user of your function or class. For example, a XML parser will extract a tag from the source code, wh…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

773 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