Can anyone tell me what's wrong with me destructor ? If I remove it all working well.
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <conio.h>
class DynString
{
private :
char *string;
int size;
public :
DynString(const char *tab)
{
string = new char[strlen(tab)];
size = strlen(tab);
if (string != NULL)
{
strcpy(this->string, tab);
}
}
DynString(const DynString& s)
{
string = new char[s.size];
if (string != NULL)
{
strcpy(string, s.string);
size = s.size;
}
else size = 0;
}
int Size() const
{
return size;
}
const char* CStr()
{
return string;
}
DynString& operator +=(const char* tab)
{
char *bufor = new char[size + strlen(tab)];
if (bufor != NULL)
{
strcpy(bufor, string);
strncat(bufor, tab, strlen(tab));
string = new char[strlen(bufor) + sizeof(char)];
}
if (string != NULL)
{
strcpy(string, bufor);
size = strlen(string);
}
return *this;
}
DynString& operator !()
{
unsigned int size = strlen(string);
for (unsigned int i = 0; i < size; i++)
{
if (string[i] >= 97 && string[i] <= 122)
{
string[i] -= 32;
}
else if (string[i] >= 65 && string[i] <= 90)
{
string[i] += 32;
}
}
return *this;
}
~DynString();
};
DynString::~DynString()
{
if (size == 0)
{
delete string;
}
else
{
delete[] string;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
DynString string("Test words.");
printf("String %s\n", string.CStr());
printf("Characters: %i\n", string.Size());
DynString copy = string;
printf("Copy %s\n", copy.CStr());
printf("Characters: %i\n", copy.Size());
copy += " - first fragment -";
copy += " second fragment.";
printf("Copy %s\n", string.CStr());
printf("Characters: %i\n", string.Size());
printf("Copy %s\n", copy.CStr());
printf("Characters: %i\n", copy.Size());
!string;
printf("String %s\n", string.CStr());
printf("\nEnd.");
_getch();
return 0;
}
You should define your destructor in the following way:
DynString::~DynString()
{
delete[] string;
string = nullptr;
}
However, I would not stick with manual memory management and use smart pointer instead.
Your destructor shall be:
if(string!=NULL)
{
delete[] string;
}
Or just
delete[] string;
(given that delete[]ing a NULL pointer is safe).
Remember: everything allocated with new[] must be destructed with delete[]; everything allocated with new must be destructed with delete.
EDIT:
Also, you should allocate string with strlen(tab)+1 space, to accomodate the terminating null byte (for the copy constructor, this means s.size+1).
Related
This question already has answers here:
What is The Rule of Three?
(8 answers)
Rule-of-Three becomes Rule-of-Five with C++11? [closed]
(9 answers)
Is the Rule of 5 (for constructors and destructors) outdated?
(5 answers)
Closed 8 months ago.
So I created my own String class that's just supposed to make dealing with char arrays easier, but I found when passing it to a constructor for another class, Folder, I get a runtime error _CrtIsValidHeapPointer(block), which I understand to be an error with me deallocating dynamic memory.
But what I find super funky, is Microsoft Visual Studio will let me pass a string literal to the Folder constructor in place of a String object. Doing so only gives me the same error as before. As well, I only get the _CrtIsValidHeapPointer(block) error when passing a String to a Folder constructor. Creating a String on its own and accessing any of its variables / functions works perfectly fine.
Edit: All constructors declared have been instantiated in the below .cpp files, there is no hidden constructor that should be taking a const char*
main.cpp:
#include "main.h"
#include <iostream>
int main()
{
char someText[5] = "test";
String text(someText);
Folder folder(text, NULL);
cout << folder.getName().getChars();
}
String.cpp:
#include "String.h"
String::String(char* newChars)
{
chars = newChars;
while (chars[size - 1] != '\0')
size++;
chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = newChars[i];
}
}
String::String(const char* newChars)
{
while (newChars[size - 1] != '\0')
size++;
chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = newChars[i];
}
}
String::String()
{
chars = new char[1];
chars[0] = '\0';
}
String::~String()
{
delete[] chars;
}
void String::append(String newString)
{
int newSize = size + newString.size - 1;
char* newChars = new char[newSize];
for (int i = 0; i < size - 1; i++)
{
newChars[i] = chars[i];
}
for (int i = 0; i < newString.size; i++)
{
newChars[size - 1 + i] = newString.chars[i];
}
delete[] chars;
chars = newChars;
size = newSize;
return;
}
bool String::equals(String string2)
{
if (size != string2.size)
return false;
else
{
for (int i = 0; i < size; i++)
{
if (chars[i] != string2.chars[i])
return false;
}
}
return true;
}
char* String::getChars()
{
return chars;
}
void String::setChars(char* newChars)
{
delete[] chars;
chars = newChars;
return;
}
void String::setChars(const char* newChars)
{
size = 1;
while (newChars[size - 1] != '\0')
size++;
delete[] chars;
chars = new char[size];
for (int i = 0; i < size; i++)
{
chars[i] = newChars[i];
}
return;
}
Folder.cpp:
#include "Folder.h"
Folder::Folder(String newName, Folder* newParent)
{
name = newName;
parent = newParent;
return;
}
Folder::Folder(Folder* newParent)
{
parent = newParent;
return;
}
String Folder::getName()
{
return name;
}
Folder* Folder::getParent()
{
return parent;
}
vector<Folder>* Folder::getChildren()
{
return &children;
}
void Folder::setName(String newName)
{
name = newName;
return;
}
void Folder::setParent(Folder* newParent)
{
parent = newParent;
}
I created a user-defined String class and some file handling function. I tried using g++ on ubuntu to compile this piece of code and gdb to debug several times before. The error was thrown in line
s2.diskIn(iflile);
Interface:
class String {
long unsigned int len;
char *cStr;
public:
String(const String &);
explicit String(const char * const = NULL);
void diskIn(std::ifstream &);
void diskOut(std::ofstream &);
const char *getString();
String operator = (const String);
~String();
};
Copy constructor
String::String(const String &ss) {
if (ss.cStr == NULL) {
cStr = NULL; len = 0;
} else {
len = ss.len;
cStr = new char[len + 1];
strcpy(cStr, ss.cStr);
}
}
Default/ Assignment Constructor
String::String(const char * const p) {
if (p == NULL) {
cStr = NULL; len = 0;
} else {
len = strlen(p);
cStr = new char[len + 1];
strcpy(cStr, p);
}
}
Error function:
void String::diskIn(std::ifstream &fin) {
String temp;
fin.read((char *)&temp.len, sizeof(int));
temp.cStr = new char[len + 1];
int i;
for (i = 0; i < temp.len; i++)
fin.get(temp.cStr[i]);
temp.cStr[i] = '\0';
*this = temp;
}
Copy assignment operator
String String::operator = (const String ss) {
if (cStr != NULL) {
delete[] cStr;
cStr = NULL;
len = 0;
}
if (ss.cStr != 0) {
len = ss.len;
cStr = new char[len + 1];
strcpy(cStr, ss.cStr);
}
return *this;
}
Destructor
String::~String() {
delete[] cStr;
}
int main() {
String s2;
std::ifstream ifile("document.txt");
s2.diskIn(ifile); //Error was thrown here
std::cout << s2.getString() << "\n";
ifile.close();
return EXIT_SUCCESS;
}
I showed my codes and i have an error reading character of string. Everything is okey in my debugger until the NULL.
*Warning C4715 `String::equas`: not all control paths return a value*
I can not use it because I am using a NULL pointer for the parameter.
How can I solve this problem?
Thanks a lot and have a nice day!
Header:
class String
{
public:
String();
bool empty();
String(char * other_str);
bool equals(const String other_str);
private:
char* m_str;
};
My Codes:
#include "String.hpp"
#include <string>
#include<iostream>
int my_len(const char* p) {
int c = 0;
while (*p != '\0')
{
c++;
*p++;
}
return c;
}
String::String()
:m_str(NULL)
{
}
String::String(char * other_str)
{
}
bool String::empty()
{
return true;
}
bool String::equals(const String other_str)
{
if (m_str == NULL && other_str.m_str == NULL) {
return true;
}
if (m_str == NULL && other_str.m_str != NULL) {
return false;
}
if (m_str != NULL && other_str.m_str == NULL) {
return false;
}
if (m_str != NULL && other_str.m_str != NULL) {
int mystrlen = my_len(m_str);
int myrhslen = my_len(other_str.m_str);
if (mystrlen != myrhslen)
{
return false;
}
else
{
for (int i = 0; i < mystrlen; i++)
{
if (m_str[i] != other_str.m_str[i])
{
return false;
}
else {
return true;
}
}
}
}
}
i will add this codes:
int mylen(const char* p) {
int c = 0;
while (*p != '\0')
{
c++;
*p++;
}
return c;
}
void my_cpy(char dest, const char* src) {
int i = 0;
while (src[i] != '\0') {
dest[i] = src[i];
i++;
}
dest[i] = '\0';
}
char mytrdup(const char *s) {
char* d = (char*)malloc((my_len(s) + 1) * sizeof(char));
if (d == NULL) {
return NULL;
}
else{
my_cpy(d, s);
}
return d;
}
String empty_string2(NULL);
This will invokde the constructor version :
String::String(char* other_str) {}
which does nothing, leaving the m_str pointer dangling/uninitialized. You should change this constructor somehow, either by copying the string and setting the m_str pointer accordingly, or by setting m_str to the same address as the parameter. Either case it depends on what you want to achieve.
Besides, many other problems exist in your code. I notice already this one in you implemented function my_len. you should change *p++ into p++. I wonder how this passed the compilation btw, since the parameter is a const char*.
Finally, the compiler's warning is correct and very clear, although it is not the source of the problem you are facing for the time being.
EDIT: to make a duplicate copy of the string, you can write you constructor like this:
String::String(const char* other_str)
{ m_str = (other_str ? strdup(other_str) : other_str); }
And besides, preferably use null_ptr instead of NULL in your code. Since C++11, this is the standard for null pointers.
I add TEST_TRUE and then that work correctly.
i am using this codes.
Maybe it easy but now i can not. Please help me about this. I am looking always NULL in this function.
How can i solve this problem? I can not do it.
Thanks a lot.
Codes:
int my_len(const char* p) {
int c = 0;
while (*p != '\0')
{
c++;
*p++;
}
return c;
}
String::String()
:m_str(NULL)
{
}
String::String(char * other_str)
{
}
{
int mystrlen = my_len(m_str);
int myrhslen = my_len(other_str.m_str);
if (mystrlen != myrhslen)
{
return false;
}
else
{
for (int i = 0; i < mystrlen; i++)
{
if (m_str[i] != other_str.m_str[i])
{
return false;
}
}
return true;
}
}
}
Your non-default constructor has an empty implementation:
String::String(char * other_str)
{
}
So here m_str is left uninitialized.
You could maybe copy the string, if that is your intention like so:
String::String(char * other_str)
{
m_str = strdup(other_str);
}
But then you will have to manage the memory allocated by strdup yourself, e.g. in the destructor:
String::~String()
{
if (m_str != NULL)
free(m_str);
}
I am implementing my version of the basic String class, however I am running into an issue that I have never seen before and have no idea how to properly debug. My code is pasted below. All functions have their header counterparts. My test is simply creating one object using the convert constructor.
A4String obj1("this");
My problem is I get an Access violation reading location exception thrown. My research has indicated that I may be trying to access memory outside of Visual Studio's allotment. I'm having trouble finding where this pointer error exists though. I have placed breakpoints through every step of the convert constructor and subsequent function calls within however my program doesn't throw the exception until it returns to main, seemingly after my program has executed completely.
#include "A4String.h"
A4String::A4String() {
data = new char[5];
data[0] = '\0';
capacity = 5;
}
A4String::~A4String() {
if (capacity != 0)
delete[] data;
}
//Copy Constructor
A4String::A4String(const A4String &right) {
cout << "copy" << endl;
data = new char[right.capacity + 1];
strcpy(data, right.data, capacity);
capacity = right.capacity;
}
//Convert Constructor
A4String::A4String(const char *sptr) {
cout << "convert" << endl;
capacity = (strlen(sptr)) + 1;
data = new char[capacity + 1];
strcpy(sptr, data, capacity);
}
//Assignment
A4String& A4String::operator = (const A4String & right) {
//if (capacity != 0) delete[] data;
data = new char[right.capacity + 1];
strcpy(data, right.data, capacity);
capacity = right.capacity;
return *this;
}
//Equivalence
bool A4String::operator == (const A4String &right) const {
return (strcmp(data, right.data)) == 0;
}
int A4String::length() const {
return capacity;
}
void A4String::addChar(char) {
//Not implemented yet
}
string A4String::toString() {
string str = "";
int i = 0;
while (data[i] != '\0') {
str += data[i];
i++;
}
return str;
}
void A4String::strcpy(const char *source, char* destination, int size)
{
for (int i = 0; i < 20; i++)
destination[i] = '\0';
int index = 0;
while (source[index] != '\0')
{
destination[index] = source[index];
index++;
}
destination[index] = '\0';
}
int A4String::strcmp(char *str1, char *str2)
{
if (*str1 < *str2)
return -1;
if (*str1 > *str2)
return 1;
if (*str1 == '\0')
return 0;
return strcmp(str1 + 1, str2 + 1);
return 0;
}
int A4String::strlen( char *s)
{
char *start;
start = s;
while (*s != 0)
{
++s;
}
return s - start;
}
The problem is your A4String::strcpy, the line
for (int i = 0; i < 20; i++)
destination[i] = '\0';
The destination has less than 20 characters, so it crashes.
Use of the hard code number 20 in the A4String::strcpy is not right. I suggest changing it to size.
void A4String::strcpy(const char *source, char* destination, int size)
{
// for (int i = 0; i < 20; i++)
for (int i = 0; i < size; i++)
destination[i] = '\0';
int index = 0;
// Add an additional check here also.
// while (source[index] != '\0' )
while (source[index] != '\0' && index < size)
{
destination[index] = source[index];
index++;
}
destination[index] = '\0';
}
Disclaimer Fixing the above function may not fix your crashing problem even though the use of 20 is most likely crashing your program. In other words, there might be other problems in your code too.