Solved

dynamic memory allocation

Posted on 2001-07-25
16
193 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
Comment Utility
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
Comment Utility
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
Comment Utility
Hi nietod, your post wasn't there when I made mine.
0
 
LVL 22

Expert Comment

by:nietod
Comment Utility
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
Comment Utility
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
Comment Utility
> 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
Comment Utility
"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
Comment Utility
Now, I'm plagerizing you.  :-)
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 
LVL 9

Expert Comment

by:jasonclarke
Comment Utility
> Now, I'm plagerizing you.

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

0
 

Author Comment

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

Author Comment

by:chandas
Comment Utility
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
Comment Utility
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
Comment Utility
>> 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
Comment Utility
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
Comment Utility
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
Comment Utility
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

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

Article by: SunnyDark
This article's goal is to present you with an easy to use XML wrapper for C++ and also present some interesting techniques that you might use with MS C++. The reason I built this class is to ease the pain of using XML files with C++, since there is…
IntroductionThis article is the second in a three part article series on the Visual Studio 2008 Debugger.  It provides tips in setting and using breakpoints. If not familiar with this debugger, you can find a basic introduction in the EE article loc…
The goal of the video will be to teach the user the concept of local variables and scope. An example of a locally defined variable will be given as well as an explanation of what scope is in C++. The local variable and concept of scope will be relat…
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.

771 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

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now