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.
Related
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!
I have a class that has two field one of them is a pointer and another is int value to hold length of string sets in constructor.
class MyString
{
char* m_pchString;
int m_nLength;
public:
MyString(const char* pchString="")
{
m_nLength = strlen(pchString) + 1;
m_pchString = new char(m_nLength);
strcpy_s(m_pchString,m_nLength, pchString);
}
MyString(const MyString &Source)
{
m_nLength = Source.m_nLength;
if (Source.m_pchString)
{
m_pchString = new char(m_nLength);
strcpy_s(m_pchString,m_nLength,Source.m_pchString);
}
else
{
m_pchString = 0;
}
}
~MyString()
{
delete[] m_pchString;
m_pchString = 0;
}
char* GetString()
{
return m_pchString;
}
int GetLength()
{
return m_nLength;
}
};
Then use it in console application and create an object cHello .afterward create another object an assign it by cHello within a block
int main()
{
MyString cHello ("Hello,World");
{
MyString cCopy = cHello;
}
std::cout << cHello.GetString();
}
When the lifetime of cCopy ends, the destructor of cCopy gives me an error. What is the problem in this code?
The expression m_pchString = new char(m_nLength) allocates one character, and initializes it to the value m_nLength. It does not allocate an array of m_nLength elements.
That means you will go way out of bounds when copying the string into the memory pointed to by m_pchString, and you will have undefined behavior.
If you want to allocate an array or more than one elements you need to use square brackets [], as in
m_pchString = new char[m_nLength];
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.
The following code instead of returning a pointer back to an audioResource it returns
something else which is invalid, i've gone through with a debugger and the problem is with this line
return *list_it;
Here is my function:
AudioResource* AudioManager::getResource(const unsigned int ID)
{
std::list<AudioResource*>::iterator list_it;
for(list_it = m_resources.begin(); list_it!= m_resources.end(); list_it++)
{
if((*list_it)->getID()==ID)
{
std::cout<<*(*list_it)->getFileName();
return *list_it;
}
}
return nullptr;
}
O and I have tried putting it as (*list_it) but i got the same results =s
How it is populated...
Resource* AudioManager::addResource(const unsigned int ID,
const std::string fileName, const unsigned int scope,
const std::string type)
{
AudioResource* temp;
if(type == "AUDIO_TYPE_SAMPLE")
{
temp = new AudioResource(ID,fileName,scope,
RESOURCE_AUDIO,AUDIO_TYPE_SAMPLE);
m_resources.push_back(temp);
}
else if(type == "AUDIO_TYPE_STREAM")
{
temp = new AudioResource(ID,fileName,scope,
RESOURCE_AUDIO,AUDIO_TYPE_STREAM);
m_resources.push_back(temp);
}
return temp;
}
call to get resource
cout<<AudioManager::getInstance()->getResource(IDnum)->getFileName();
If type is neither of the two values an uninitialized pointer is added to m_resources:
AudioResource* temp;
if(type == "AUDIO_TYPE_SAMPLE")
{
temp = new AudioResource(ID,fileName,scope,RESOURCE_AUDIO,AUDIO_TYPE_SAMPLE);
}
else if(type == "AUDIO_TYPE_STREAM")
{
temp = new AudioResource(ID,fileName,scope,RESOURCE_AUDIO,AUDIO_TYPE_STREAM);
}
m_resources.push_back(temp);
Initialize temp to NULL and only add to m_resources if temp != NULL.
Also, the function returns the same uninitialized pointer.
You return nullptr in case the ID doesn't exist, but you never check against it at the call site, which will give you a null pointer access if the ID doesn't exist and which will likely create problems.
AudioManager::getInstance()->getResource(IDnum)->getFileName();
Change that to
AudioResource* res = AudioManager::getInstance()->getResource(IDnum);
if(res)
std::cout << res->getFileName();
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.