I am fairly new to C++, and this problem I am having has had me stumped for like the last 2 hours. What I am trying to do is create an array of pointers to my class Word objects, so a 2 dimensional array, which is **wordPtrList. Then I need to delete the memory of certain objects in the array and set their pointers to null. I have written a smaller version of what I am trying to accomplish below.
int main()
{
char *cArray;
cArray = new char[4];
int i;
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i + 1] = '\0'; //cArray is a null terminated string
Word **wordPtrList;
wordPtrList = new Word* [3];
for (i = 0; i < 3; i++)
{
wordPtrList[i] = new Word(cArray);
}
wordPtrList[1]->del();
delete wordPtrList[1];
wordPtrList[1] = '\0';
return 0;
}
class Word
{
private:
char* ptr_;
int len_;
public:
Word(const char* word)
{
len_ = strlen(word);
ptr_ = new char[len_];
strcpy(ptr_, word);
}
~Word()
{
delete [] ptr_;
ptr_ = 0;
}
void del()
{
delete [] ptr_;
ptr_ = 0;
return;
}
};
When I do this however, I get:
Debug Error Heap Corruption Detected after normal block
This is in VS 2010 on Windows 7.
So what I am asking is, how do I delete the memory of my object so that I can set wordPtrList[1] to Null?
You are allocating 4 bytes to cArray (meaning you have access to write to bytes 0 through 3), and then writing to cArray[4]. You also allocate one byte too small in the Word constructor.
char *cArray;
cArray = new char[4];
int i;
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i] = '\0'; //cArray is a null terminated string - i is now 3
and
Word(const char* word)
{
len_ = strlen(word);
ptr_ = new char[len_ + 1];
strcpy(ptr_, word);
}
should do the trick.
Look at this code:
for (i = 0; i < 3; i++)
cArray[i] = 'a';
cArray[i + 1] = '\0'; //cArray is a null terminated string
The problem is at the last line which is using i+1 as index, which is going out of range, as by the time the loop exits, the value of i is already 3; that means i+1 will become 4 which cannot be a valid index when you've allocated cArray as:
cArray = new char[4]; //taken from your code
The solution is this:
cArray[i] = '\0'; //Now, it is correct. Here i is equal to 3
That is, use i instead of i+1; Or simply use 3.
In C++, you could std::fill instead of manual loop, as:
std::fill(cArray, cArray + 4, 'a'); //done
Even better avoid using char* with new as much as possible, and prefer using std::string instead.
There are two obvious off-by-one errors in the code (when you get out of the first loop what is the value of the variable i? when calling strlen did you remember to consider the space needed by the null terminator?).
Also please note that c strings are not "null terminated", they are "NUL terminated" with uppercase letters and only one "L". NUL is the name of the ASCII control character with all bits set to zero and is represented in C++ with '\0'.
In one place you used NUL character as a null pointer, and while this is technically correct (because of a design bug of the C++ language) it's better to understand that the two concepts are quite different.
As others have said, you're basically accessing an array index which is out of bounds of the array.
I would go with Nathan Wiebe's solution.
In the future, when you have the option to do this, it's recommended to use std::vector<T> as that will allow you to store any type you wish in a dynamically resizeble array. In other words, providing you don't access an index which is outside of the vector's bounds, you could do something like this:
std::vector< char* > str;
for( size_t i = 0; i < str.size(); ++i )
{
str.push_back( 'a pointer to a block of memory consisting of characters' );
}
class Word
{
public:
Word( const char* str )
{
mStrs.push_back( str );
}
~Word( void )
{
for( size_t i = 0; i < mStrs.size(); ++i )
{
if( mStrs[ i ] )
{
delete mStrs[ i ];
mStrs[ i ] = NULL;
}
}
mStrs.clear();
}
private:
void del( size_t index )
{
if( index > mStrs.size() )
{
//error - throw new exception or something
}
delete mStrs[ index ];
}
std::vector< const char* > mStrs;
};
Related
Program crashes when I'm trying to delete[] an array that was allocated with new[]. I don't see any reasons why this shouldn't work. The array is allocated in method and deleted in the end of it, it's local, everything should be fine, but it's not.
I don't see any exception name that was thrown in debug, that's why I don't know where to dig.
Through debug I see that crash is happening at first delete[] operator.
Without those two deletes no crashes happening, but I don't want something to float in memory.
void Atbash::EncryptString(string t)
{
char *cOriginalString;
char *cEncryptedString;
unsigned int originalStringLength;
unsigned int i;
unsigned short j = 0;
originalString = t;
originalStringLength = originalString.length();
cOriginalString = new char(originalStringLength + 1);
cEncryptedString = new char(originalStringLength + 1);
strcpy_s(cOriginalString, originalStringLength + 1, originalString.c_str());
cOriginalString[originalStringLength] = '\0';
for (i = 0; i < originalStringLength; i++)
{
while (cOriginalString[i] != alphabet[j])
{
j++;
}
cEncryptedString[i] = alphabet[N - j - 2];
j = 0;
}
cEncryptedString[originalStringLength] = '\0';
encryptedString = cEncryptedString;
delete[] cOriginalString;
delete[] cEncryptedString;
}
originalString and encryptedString are of "string" type.
You aren't allocating a char[], just a plain old char. Note that you should be using square braces ([]) and not parenthethis (()):
cOriginalString = new char[originalStringLength + 1];
// Here ------------------^------------------------^
cEncryptedString = new char[originalStringLength + 1];
// And here ---------------^------------------------^
You can process individual characters in a std::string and it will both simplify your code and make it more robust. Here is one possible implementation.
void Atbash::EncryptString(string originalString)
{
encryptedString.clear();
encryptedString.reserve(originalString.size());
for (auto ch:originalString)
{
auto index= alphabet.find(ch);
if (index != npos)
encryptedString += alphabet[N - index - 2];
}
}
Written code to find and remove the largest word in a string without the using of library functions. Everything works fine. But when I want to free memory, the result is negative (displays an empty line). If you remove the call to the memory release function, everything will work correctly, but there will be a leak of memory.
How do I fix it? Please help me.
#include <iostream>
using namespace std;
int length(char *text) // string length
{
char *begin = text;
while(*text++);
return text - begin - 1;
}
int size(char **text) // size of two-dimensional array
{
int i = 0;
while(text[i]) i++;
return i;
}
void free_memory(char **text)
{
for(int i=0; i<size(text); i++)
delete text[i];
delete [] text;
}
char **split(char *text, char delim)
{
int words = 1;
int len = length(text);
for(int i=0; i<len; i++)
if(text[i] == delim) words++;
char **result = new char*[words + 1];
int j = 0, t = 0;
for(int i=0; i<words; i++)
{
result[i] = new char[len];
while(text[j] != delim && text[j] != '\0') result[i][t++] = text[j++];
j++;
t = 0;
}
result[words + 1] = nullptr;
return result;
}
char *strcat(char *source, char *destination)
{
char *begin = destination;
while(*destination) destination++;
*destination++ = ' ';
while(*source) *destination++ = *source++;
return begin;
}
char *removeWord(char *in_string)
{
char **words = split(in_string, ' ');
int max = length(words[0]);
int j = 0;
for(int i=0; i<size(words); i++)
if(max < length(words[i]))
{
max = length(words[i]);
j = i;
}
int index;
char *result;
if(!j) index = 1;
else index = 0;
result = words[index];
for(int i=0; i<size(words); i++)
if(i != j && i != index)
result = strcat(words[i], result);
free_memory(words); // I want free memory here
return result;
}
int main()
{
char text[] = "audi and volkswagen are the best car";
cout << removeWord(text) << endl;
return 0;
}
In fact, this is C style programming - not C++. I see that your aim is to implement everything from scratch, possibly for practicing. But even then, your code is not designed/structured properly.
Besides that, you also have several bugs in your code:
result[words + 1] = nullptr; must be result[words] = nullptr;
You need result[i][t] = '\0'; after the while loop in split
delete text[i] must be delete [] text[i]
You cannot assign to your result pointer memory from words, then free it and then return it for use by the caller.
There is at least one further bug in the second half of removeWord. It would be tedious to try to understand what you are trying to do there.
You might want to start with a simpler task. You also should proceed step-by-step and check each function for correctness independently first and not implement everything and then test. Also take a look at the tool valgrind for memory checking - if you use Linux.
The way you free memory correctly is to use RAII:
Only use new and new[] in constructors
Pair those with delete and delete[] in the corresponding destructor
Use automatic storage duration objects as much as possible
If you are specifically not using std::string and std::vector etc, for reasons of learning pointers, you will end up writing some small number of classes that resemble string and vector and unique_ptr, and then you go about programming as if you were using the std versions.
You have two issues. First is that result is assigned to a memory location in words. Second, is that you're storing the result of strcat in words[i] which will likely not have enough room (see strcat documentation).
result = new char[len(in_string)+1]; // +1 for space for null char
// the old loop reversed the word order -- if you want to keep doing
// that, make this a descending loop
for(int i=0; i<size(words); i++)
if(i != j && i != index)
strcat(result, words[i]);
free_memory(words);
return result;
So that when you free words, what result points to is also free'd. You would then need to free your result in main().
int main()
{
char text[] = "audi and volkswagen are the best car";
char * result = removeWord(text);
cout << result << endl;
delete[] result;
return 0;
}
I am trying to shrink an array of *bool but I am not sure if it is being deleted correctly.
This is my source code...
bool *oldStore;
void shrinkArray(int i)
{
int k;
bool *newStore;
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
for(; k<originalSize; k++)
{
delete[] oldStore[k];
}
delete[] oldStore;
oldStore = newStore;
}
For example, if I wanted to shrink the array to 5 and the original size of the array was 15, it would keep the first five and delete the last ten, however I am not too sure if my memory is being managed correctly.
Think about you method design before going into the coding specifics. I assume you have an ínt array that you new somewhere in your code.
Think about who "owns" this array? It's probably no good idea to create the int array at some place and to simply delete[] it somewhere else. Check out the following links: What is a smart pointer and when should I use one?
Think about what should happen to your newStore array. Is it supposed to replace the oldStore or do you want both arrays to exist in parallel. If you simply put the newStore on the heap who/when and where are you going to delete[] it again.
Simplest code would be:-
void shrinkArray(int i)
{
int k;
bool *newStore = new bool[i];
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
delete [] oldStore; //assuming oldstore was allocated using new []..
oldStore = newStore;
}
Your code is wrong. You declared pointer newStore but neither initialize it nor allocated memory that would be pointed to by this pointer
bool *newStore;
So the next loop has undefined behaviour.
for(k=0; k<i; k++)
{
newStore[k] = oldStore[k];
}
Moreover if each element of the array pointed to by pointer oldStore has type bool * that is in turn is a pointer then oldStore itself shall have type bool **
If so then the correct function could look like
void shrinkArray( int n )
{
if ( n < originalSize )
{
bool **newStore = new bool * [n];
int i = 0;
for ( ; i < n; i++ ) newStore[i] = oldStore[i];
for ( ; i < originalSize; i++ ) delete oldStore[i];
delete [] oldStore;
oldStore = newStore;
originalSize = n;
}
}
Take into account that oldStore also shall have type bool **.
Otherwise if each element of the original array has type bool then the code will look like
void shrinkArray( int n )
{
if ( n < originalSize )
{
bool *newStore = new bool [n];
int i = 0;
for ( ; i < n; i++ ) newStore[i] = oldStore[i];
// Or
// std::copy( oldStore, oldStore + n, newStore );
delete [] oldStore;
oldStore = newStore;
originalSize = n;
}
}
Take into account that it would be much better and simpler to use standard container std::vector<bool *> or std::vector<bool> depending on the type of the element of the container.
Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &
char *stringmult(int n)
{
char *x = "hello ";
for (int i=0; i<n; ++i)
{
char *y = new char[strlen(x) * 2];
strcpy(y,x);
strcat(y,x);
delete[] x;
x=y;
}
return x;
}
I'm trying to figure out what the flaws of this segment is. For one, it deletes x and then tries to copy it's values over to y. Another is that y is twice the size of x and that y never gets deleted. Is there anything that I'm missing? And also, I need to figure out how to get algorithm performance. If you've got a quick link where you learned how, I'd appreciate it.
y needs one more byte than strlen(x) * 2 to make space for the terminating nul character -- just for starters.
Anyway, as you're returning a newed memory area, it's up to the caller to delete it (eek).
What you're missing, it seems to me, is std::string...!-)
As for performance, copying N characters with strcpy is O(N); concatenating N1 characters to a char array with a previous strlen of N2 is O(N1+N2) (std::string is faster as it keeps the length of the string in an O(1)-accessible attribute!-). So just sum N+N**2 for N up to whatever your limit of interest is (you can ignore the N+ part if all you want is a big-O estimate since it's clearly going to drop away for larger and larger values of N!-).
For starters delete[] x; operates for the first time round the loop on some static memory. Not good.
It looks like an attempt to return a buffer containing 2^n copies of the string "hello ". So the fastest way to do that would be to figure out the number of copies, then allocate a big enough buffer for the whole result, then fill it with the content and return it.
void repeat_string(const std::string &str, int count, std::vector<char> &result)
{
result.resize(str.size() * count);
for (int n = 0; n < count; n++)
str.copy(&result[n * s.size()], s.size());
}
void foo(int power, std::vector<char> &result)
{
repeat_string("hello ", 1 << (power + 1), result);
}
no need to call strlen() in a loop - only call it once;
when new is called no space is requested for the null-character - will cause undefined behaviour;
should use strcpy instead of strcat - you already know where to copy the second string and findig the end of string by strcat requires extra computation;
delete[] is used on a statically allocated string literal - will cause undefined behaviour;
memory is constantly reallocated although you know the result length well in advance - memory reallocation is quite expensive
You should instead compute the result length at once and allocate memory at once and pass the char* as an in-parameter:
char* stringMult(const char* what, int n)
{
const size_t sourceLen = strlen( what );
int i;
size_t resultLen = sourceLen;
// this computation can be done more cleverly and faster
for( i = 0; i < n; i++ ) {
resultLen *= 2;
}
const int numberOfCopies = resultLen / sourceLen;
char* result = new char[resultLen + 1];
char* whereToWrite = result;
for( i = 0; i < numberOfCopies; i++ ) {
strcpy( whereToWrite, what );
whereToWrite += sourceLen;
}
return result;
}
Certain parts of my implementation can be optimized but still it is much better and (I hope) contains no undefined-behaviour class errors.
you have to add one while allocating space for Y for NULL terminating string
Check the code at below location http://codepad.org/tkGhuUDn
char * stringmult (int n)
{
int i;
size_t m;
for (i = 0, m = 1; i < n; ++i; m *= 2);
char * source = "hello ";
int source_len = strlen(source);
char * target = malloc(source_len*m+1) * sizeof(char));
char * tmp = target;
for (i = 0; i < m; ++i) {
strcpy(tmp, source);
tmp += source_len;
}
*tmp = '\0';
return target;
}
Here a better version in plain C. Most of the drawbacks of your code have been eliminated, i.e. deleting a non-allocated pointer, too many uses of strlen and new.
Nonetheless, my version may imply the same memory leak as your version, as the caller is responsible to free the string afterwards.
Edit: corrected my code, thanks to sharptooth.
char* string_mult(int n)
{
const char* x = "hello ";
char* y;
int i;
for (i = 0; i < n; i++)
{
if ( i == 0)
{
y = (char*) malloc(strlen(x)*sizeof(char));
strcpy(y, x);
}
else
{
y = (char*)realloc(y, strlen(x)*(i+1));
strcat(y, x);
}
}
return y;
}
Nobody is going to point out that "y" is in fact being deleted?
Not even one reference to Schlmeiel the Painter?
But the first thing I'd do with this algorithm is:
int l = strlen(x);
int log2l = 0;
int log2n = 0;
int ncopy = n;
while (log2l++, l >>= 1);
while (log2n++, n >>= 1);
if (log2l+log2n >= 8*(sizeof(void*)-1)) {
cout << "don't even bother trying, you'll run out of virtual memory first";
}