I have a MultiString class that has some methods in it.
I am strugling with deleting my array of strings in the destructor, I get heap corruption.
Here is my class (some methods are cut)
class MultiString {
public:
//constructor destructor
MultiString(int);
~MultiString();
//methods
void Setat(int nindex, const char* str);
//attributes
char** buf;//pointer to vector
int str_nmb;//strings number
};
Constructor code:
MultiString::MultiString(int number)
{
str_nmb = number;
buf = new char* [number];
for (int i = 0; i < number; i++) buf[i] = NULL;
}
Setat code (used to set strings in array):
void MultiString::Setat(int nindex, const char* str)
{
if (nindex<0 || nindex>str_nmb || str == NULL) {
std::cout << "gg";
return;
}
char* tmp = new char[strlen(str)+1];
if (tmp == NULL) return;
if (buf[nindex] != NULL) delete buf[nindex]; //here delete works fine
buf[nindex] = tmp;
strcpy_s(buf[nindex], strlen(buf[nindex]), str);
std::cout << buf[nindex]<< std::endl;
}
Destructor code:
MultiString::~MultiString()
{
for (int i = 0; i < str_nmb; i++)
delete buf[i]; // heap corruption here
delete buf;
}
And my main():
int main()
{
MultiString* ms = new MultiString(3);
ms->etat(0, "qwerty");
ms->Setat(1, "asdfgh");
ms->Setat(2, "zxcvbn");
delete ms;
return 0;
}
char* tmp = new char[strlen(str)+1];
// ...
buf[nindex] = tmp;
strcpy_s(buf[nindex], strlen(buf[nindex]), str);
buf[nindex] points to the freshly allocated, but uninitialized memory area. Calling strlen on that is undefined behavior and likely what corrupts your heap. You probably want to call strlen(str) instead.
Apart from that you're making a few other mistakes:
Rule of 0/3/5 broken.
delete where delete[] would be necessary
Wrong bounds check (nindex>str_nmb)
What about Multistring(-5) ?
if (tmp == NULL) return; ... no, you shouldn't mute errors. Throw an exception or something.
Also .. why strcpy_s ? Use std::strncpy ... that's at least guaranteed to be available! Make sure the copied C string is null terminated!
Related
This is my code i have this error.I think it is a problem with my destructor.
Could you explain me this?
Destructor causes corruption of the heap
#pragma once
#include<iostream>
class Adresa
{
char *nume;
int numar;
char *localitate;
public:
Adresa();
Adresa(char *n, int nr, char*l);
Adresa(Adresa &adr);
void print()
{
printf("%s %d %s ", nume, numar, localitate);
}
~Adresa();
};
and
#include "Adresa.h"
#include<iostream>
Adresa::Adresa()
{
nume = new char();
localitate = new char();
numar = NULL;
}
Adresa::Adresa(char *n, int nr, char*l)
{
this->nume = _strdup(n);
this->localitate = _strdup(l);
this->numar = nr;
}
Adresa::Adresa(Adresa &adr)
{
this->nume = new char(strlen(adr.nume) + 1);
strcpy(nume, adr.nume);
this->numar = adr.numar;
this->localitate = new char(strlen(adr.localitate) + 1);
strcpy(localitate, adr.localitate);
}
Adresa::~Adresa()
{
if (nume != NULL)
{
delete[] nume;
}
if (localitate != NULL)
{
delete[] localitate;
}
}
and the output is this
enter image description here
What is the problem with my destructor?
You had mixed up java and C++. In new expression
what goes into parents AFTER type-id isn't the size of allocated block, it's a part of initializer.
char *s = new char(3);
allocates one character and assigns value of 3 to it.
What you had to write
char *s = new char[3];
only in this case it's legal to use delete[]
You can't use normal delete on such pointer. Well, you can but usually you should not, because it leads to undefined behaviour, e.g. will not deallocate whole array on some platforms.
I have the following function:
void stringcopy(char * to, char const * const from)
{
int size = 1;
while (from[size] != '\0') { ++size; }
if (to != 0) { delete [] to; }
to = new char[size];
for (int i = 0; i < size; i++) { to[i] = from[i]; }
}
As the name notes, it copies a string, using dynamic allocation.
I don't believe the way I use it ought to matter (as I'm trying to make this function robust), but here are some examples:
CD::CD(char * s1, char * s2, int n, double x)
{
stringcopy(performers, s1);
stringcopy(label, s2);
selections = n;
playtime = x;
}
and
CD::CD(const CD & d)
{
stringcopy(performers, d.performers);
stringcopy(label, d.label);
selections = d.selections;
playtime = d.playtime;
}
etc.
Unfortunately, I'm getting the following error message, when I use the function: pointer being freed was not allocated.
I assume it occurs do to if (to != 0) { delete [] to; }.
Why doesn't this line protect against deallocating non-allocated memory?
What you are doing here
if (to != 0) { delete [] to; }
to = new char[size];
is freeing the memory to which the local to variable points, allocating it newly and storing the string there.
This new local memory address (let's call it to1) is however never exposed to the outside world, as it's not returned from the function. The function get's a copy of the to address. In order to fix that you need to make to a double pointer. Or a reference to a pointer.
Hi there I need to Build something like a dictionary and each word according to my code can have 100 meanings, but maybe it has only 5 meanings then I will be allocating 95 extra space for nothing or maybe it has more than 100 meanings then the program will crash, I know the vector class is very easy and could be good use of, but the task is almost building my own vector class, to learn how it works. Thus **meanings and some other stuff remain the same and here is my code, Also I know I am causing memory leakage, how can I delete properly? :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Expression {
char *word_with_several_meanings; // like "bank", "class"
char **meanings; // a pointer to a pointer stores all meanings
int meanings_ctr; // meanings counter
//-----------FUNCTIONS------------------------------------------------
public:
void word( char* = NULL );
void add_meaning(char* = NULL);
char* get_word();
int get_total_number_of_meanings();
char* get_meaning(int meanx = 0);
Expression(int mctr = 0); // CTOR
~Expression(); // DTOR
};
Expression::Expression(int mctr ) {
meanings_ctr = mctr; // Setting the counter to 0
meanings = new char * [100]; // Allocate Space for 100 meanings
}
Expression::~Expression() {
delete [] meanings; // Deleting the memory we allocated
delete [] word_with_several_meanings; // Deleting the memory we allocated
}
void Expression::word( char *p2c )
{
word_with_several_meanings = new char[strlen(p2c)+1];
// copy the string, DEEP copy
strcpy(word_with_several_meanings, p2c);
}
void Expression::add_meaning(char *p2c)
{
//meanings = new char * [meanings_ctr+1];
meanings[meanings_ctr] = new char[strlen(p2c)+1];
strcpy(meanings[meanings_ctr++],p2c);
}
char * Expression::get_meaning( int meanx )
{
return *(meanings+meanx);
}
char * Expression::get_word()
{
return word_with_several_meanings;
}
int Expression::get_total_number_of_meanings()
{
return meanings_ctr;
}
int main(void) {
int i;
Expression expr;
expr.word("bank ");
expr.add_meaning("a place to get money from");
expr.add_meaning("b place to sit");
expr.add_meaning("4 letter word");
expr.add_meaning("Test meaning");
cout << expr.get_word() << endl;
for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
cout << " " << expr.get_meaning(i) << endl;
Expression expr2;
expr2.word("class");
expr2.add_meaning("a school class");
expr2.add_meaning("a classification for a hotel");
expr2.add_meaning("Starts with C");
cout << expr2.get_word() << endl;
for( i = 0; i<expr2.get_total_number_of_meanings(); i++)
cout << " " << expr2.get_meaning(i) << endl;
Expression expr3;
expr3.word("A long test ... ");
char str[] = "Meaning_ ";
for (int kx=0;kx<26;kx++)
{
str[8] = (char) ('A'+kx);
expr3.add_meaning(str);
}
cout << expr3.get_word() << endl;
for(i = 0; i < expr3.get_total_number_of_meanings(); i++)
cout << " " << expr3.get_meaning(i) << endl;
return 0;
}
When you are allocating a multi dimensional array with new then you are allocating it with a loop, e.g.
char **x = new char*[size]
for (int i = 0; i < N; i++) {
x[i] = new int[size];
}
So you also have to delete it in this fashion:
for (int i = 0; i < N; i++) {
delete[] x[i];
}
delete[] x;
Thus when you're having arbitrary sizes of your array you'll have to store them somewhere for using them within the destructor.
delete [] meanings; // Deleting the memory we allocated
won't get rid of your memory allocated, only the pointers themselves.
To free up the actual memory, you will need to iterate through your meanings array, and delete [] each element in it.
Something like:
for (int i = 0; i < meanings_ctr; ++i)
{
delete [] meanings[meanings_ctr];
meanings[meanings_ctr] = NULL;
}
delete [] meanings;
--
For the problem of what to do if you get more than 100 meanings (or in general when your collection is full), the standard technique is to allocate a new array that is double the size (which you can do since it is dynamic), copy your existing collection into that one, and then dispose of your existing one.
I'd use a simple linked list (this is simplified, not complete and untested; also there should be proper getters/setters and stuff):
class Meaning {
char text[20];
Meaning *next;
Meaning(const char *text) : next(0) {
strcpy(this->text, text);
}
}
class Word {
char text[20];
Meaning *first;
Meaning *last;
Word(const char *text) : first(0), last(0) {
strcpy(this->text, text);
}
~Word() {
Meaning *m = first, *n;
while(m) {
n = m->next;
delete m;
m = n;
}
}
void AddMeaning(const char *text) {
if (last) {
last = last->next = new Meaning(text);
}
else {
first = last = new Meaning(text);
}
}
void print() {
printf("%s:\n\t", text);
Meaning *m = first;
while (m) {
printf("%s, ", m->text);
m = m->next;
}
}
}
Basically, I'm passing a pointer to a character string into my constructor, which in turn initializes its base constructor when passing the string value in. For some reason strlen() is not working, so it does not go into the right if statement. I have checked to make sure that there is a value in the variable and there is.
Here is my code, I've taken out all the irrelevant parts:
Label class contents:
Label(int row, int column, const char *s, int length = 0) : LField(row, column, length, s, false)
{
}
Label (const Label &obj) : LField(obj)\
{
}
~Label()
{
}
Field *clone() const
{
return new Label(*this);
}
LField class contents:
LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = "", bool canEditVal = true)
{
if(strlen(valVal) > 0)
{
}
else
{
//This is where it jumps to, even though the value in
//valVal is 'SFields:'
val = NULL;
}
}
Field *clone() const
{
return new LField(*this);
}
LField(const LField &clone) {
delete[] val;
val = new char[strlen(clone.val) + 1];
strcpy(val, clone.val);
rowNum = clone.rowNum;
colNum = clone.colNum;
width = clone.width;
canEdit = clone.canEdit;
index = clone.index;
}
Screen class contents:
class Screen {
Field *fields[50];
int numOfFields;
int currentField;
public:
Screen()
{
numOfFields = 0;
currentField = 0;
for(int i = 0; i < 50; i++)
fields[i] = NULL;
}
~Screen()
{
for (int i = 0; i < 50; i++)
delete[] fields[i];
}
int add(const Field &obj)
{
int returnVal = 0;
if (currentField < 50)
{
delete[] fields[currentField];
fields[currentField] = obj.clone();
numOfFields += 1;
currentField += 1;
returnVal = numOfFields;
}
return returnVal;
}
Screen& operator+=(const Field &obj)
{
int temp = 0;
temp = add(obj);
return *this;
}
};
Main:
int main () {
Screen s1;
s1 += Label(3, 3, "SFields:");
}
Hopefully someone is able to see if I am doing something wrong.
<LANGUAGE FEATURE XXXX IS BROKEN>! ... No, it isn't.
Just before measuring the string, write in a puts(valVal), to ensure you are not mistaken about the contents of that variable.
Marcin at this point the problem will come down to debugging, I copied your code with some minor omissions and got the correct result.
Now it needs to be said, you should be using more C++ idiomatic code. For instance you should be using std::string instead of const char* and std::vector instead of your raw arrays.
Here is an example of what the LField constructor would look like with std::string:
#include <string> // header for string
LField(int rowNumVal,
int colNumVal,
int widthVal,
const std::string& valVal = "",
bool canEditVal = true)
{
std::cout << valVal;
if(valVal.length() > 0)
{
}
else
{
//This is where it jumps to, even though the value in
//valVal is 'SFields:'
//val = NULL;
}
}
Using these types will make your life considerably easier and if you make the change it may just fix your problem too.
PREVIOUS:
So you can be CERTAIN that the string is not being passed in correctly add a printline just before the strlen call. Once you do this work backward with printlines until you find where the string is not being set. This is a basic debugging technique.
Label(int row,
int column,
const char *s,
int length = 0) :
LField(row, column, length, s, false) {
}
LField(int rowNumVal,
int colNumVal,
int widthVal,
const char *valVal = "",
bool canEditVal = true)
{
std::cout << valVal << std::endl;
if(strlen(valVal) > 0)
{
}
else {
//This is where it jumps to, even though the value in
//valVal is 'SFields:'
val = NULL;
}
}
Whenever there is strange behavior like this, memory getting screwed up is almost always the culprit. Never mix new with delete[] OR new[] with delete. The latter is slightly worse than the former but they are both bad news. delete[] should only be used in conjunction with new[]. Mixing these allocation/deallocation notations will result in undefined behavior. Since you are never using new[], replace all of your delete[] calls with delete. It is also good practice and good manners to set your pointers to NULL after you delete them. It is highly unlikely that you will be the only one debugging this code and it would be extremely annoying to debug your pointers thinking that there is valid memory there, when in fact there isn't.
Mixing these notations inevitably lead to exploits and memory leaks.
There is a problem here:
LField(const LField &clone) {
delete[] val;
val = new char[strlen(clone.val) + 1];
val is uninitialized when the constructor is called, and you are deleting it.
I have a constructor, that receives a character pointer. If it is empty, I need to set its member variable to NULL, however, the program crashes on exit when I try to.
I have verified that it gets to the line where it sets it to NULL and that is the cause of the crash.
I've tried the following:
val = NULL;
val = 0;
val = "";
Those all cause a crash, however if I used:
val = new Char[1];
val = "o";
it didn't crash.
Is there something that I'm not doing?
Update:
Here is a quick update to my problem.
The destructor I'm using is:
~LField() {
if (val)
delete[] val;
}
If I take out:
if (val)
delete[] val;
then the program doesn't crash on exit with:
val = "";
Here is some more code as requested:
LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = "", bool canEditVal = true) {
if(strlen(valVal) > 0) {
//doesn't jump in here since valVal is empty
}
else {
val = ""; // this is where I'm trying to set a NULL value
}
}
LField(const LField &clone) {
if (val)
delete[] val;
val = new char[strlen(clone.val)];
strcpy(val, clone.val);
rowNum = clone.rowNum;
colNum = clone.colNum;
width = clone.width;
canEdit = clone.canEdit;
index = clone.index;
}
LField& operator=(const LField &lfieldobj) {
if (this != &lfieldobj) {
if (val)
delete[] val;
val = new char[strlen(lfieldobj.val)];
strcpy(val, lfieldobj.val);
rowNum = lfieldobj.rowNum;
colNum = lfieldobj.colNum;
width = lfieldobj.width;
canEdit = lfieldobj.canEdit;
index = lfieldobj.index;
}
return *this;
}
Modified:
LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = NULL, bool canEditVal = true) {
if(valVal != NULL) {
}
else {
val = NULL;
}
}
LField(const LField &clone) {
delete[] val;
if (clone.val != NULL) {
val = new char[strlen(clone.val) + 1];
strcpy(val, clone.val);
}
else
val = NULL;
rowNum = clone.rowNum;
colNum = clone.colNum;
width = clone.width;
canEdit = clone.canEdit;
index = clone.index;
}
LField& operator=(const LField &lfieldobj) {
if (this != &lfieldobj) {
delete[] val;
if (lfieldobj.val != NULL) {
val = new char[strlen(lfieldobj.val) + 1];
strcpy(val, lfieldobj.val);
}
else
val = NULL;
rowNum = lfieldobj.rowNum;
colNum = lfieldobj.colNum;
width = lfieldobj.width;
canEdit = lfieldobj.canEdit;
index = lfieldobj.index;
}
return *this;
}
~LField() {
delete[] val;
}
I've updated the code. Now val is either allocated memory with new[] or it is NULL, so there shouldn't be a problem with delete[]. However, it still crashes on exit.
In the copy constructor you try to delete[] an uninitialized pointer:
LField(const LField &clone) {
//good code here, then...
if (val) //<+ some random address here
delete[] val;//<-undefined behavior
}
just don't do that, skip the whole construct. The copy constructor is invoked on an unitilialized object, there're no resources to "free" yet.
Also you try to delete[] a string literal, that's undefined behavior. Try the following change:
LField(int rowNumVal, int colNumVal, int widthVal, const char *valVal = "", bool canEditVal = true) {
if(strlen(valVal) > 0) {
//doesn't jump in here since valVal is empty
}
else {
val = new char[1];
*val = 0;
}
}
also the following is a buffer overrun:
val = new char[strlen(whatever)]; <-forgot to +1 for the null terminator
strcpy(val, whatever);
also checking for a null pointer before delete[] is unnecessary - delete[] on a null pointer is legal and has no effect.
Oh dear, where to start??
a:
LField(const LField &clone) {
if (val)
delete[] val;
This is daft, as val is undefined. You will be calling delete[] on random memory.
b:
val = new char[strlen(clone.val)];
strcpy(val, clone.val);
c-type Strings need a null terminator. You need to new[] and additional byte.
Probably somewhere in your code you are trying to access(dereference) val which still refers to NULL.
Make sure no where in your code you are doing this
val=NULL; //in the constructor
//somewhere in your code
char ch= *val; //This would be Undefined Behavior
EDIT
You are calling delete[] on val whose value is ""(string literal), that is undefined behavior.
Some examples of UB
1)
char *p="hello";
delete p; //UB
delete []p; //UB
2)
char *p==new char[20]("Hello");
delete p; //UB
delete []p; //fine
3)
char *p=new char('a');
delete []p; //UB
delete p; //fine
Calling
delete[] NULL;
delete[] 0;
is ok, you don't even need the null-check.
But calling
delete[] "whatever";
is not OK since this char* wasn't allocated with new[].
Note that calling string function like strlen() like it is done in your constructor is illegal in a null reference.
You access val in your constructor before it is assigned the first time. This can also cause undefined behaviour.
I'm with Prasoon Saurav. The code you showed looks good, so the problem is somewhere else.
Try this:
Change it back to val = 0;
Remove all your code except the constructor, the destructor, and a declaration of an object of that class. Comment out everything else. I'd wager good repuation that it won't crash.
Slowly uncomment your other code and retry the program. When it crashes again, you've found the culprit.