So I was trying to implement String class and I got an error saying segmentation fault. I think there is memory leak in my constructor. Can you please tell me what I am doing wrong? Thank you.
here is the constructor code and I am not permitted to use any standard library functionality.
String(const char* chars){
int i = 0;
if(chars){
while(chars[i]){
i++;
}
}
len = i;
str = new char[len - 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
};
And also this is my full code:
#include <iostream>
using namespace std;
class String{
public:
char* str;
int len;
String(){
str = new char[0];
len = 0;
};
String(const char* chars){
int i = 0;
if(chars){
while(chars[i]){
i++;
}
}
len = i;
str = new char[len - 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
};
String(const String& s){
if(s.isEmpty() == false){
len = s.len;
str = new char[len];
for(int i = 0; i < len; i++){
str[i] = s.str[i];
}
}
};
~String() noexcept{
if(len > 0)
delete[] str;
};
bool isEmpty() const noexcept{
if(len == 0){
return true;
}
else{
return false;
}
}
unsigned int length() const noexcept{
return len;
}
const char* toChars() const noexcept{
char* temp = new char[len];
int c = 0;
while(temp[c] != '\0'){
temp[c] = str[c];
c++;
}
return temp;
}
};
int main()
{
const char* chars = "Boo is snoring";
String s;
String t{chars};
cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl;
return 0;
}
The problem with your String(const char* chars) constructor is on this statement:
str = new char[len - 1];
You are allocating less memory then you need, so your for loop is going out of bounds of the allocated memory. You need to allocate at least len number of chars, not len - 1 number of chars:
str = new char[len];
If you intend str to be null-terminated, you need to allocate len + 1 number of chars instead, and then insert a null terminator after the loop is finished:
str = new char[len + 1];
for(int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = '\0';
You are making a similar mistake in your toChars() method. You are not null-terminating the output, which is required by the operator<< that you are passing the memory to afterwards:
const char* toChars() const {
char* temp = new char[len + 1];
for(int c = 0; c < len; ++c){
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
Note that I removed the noexcept on toChars(). This is because new[] is not noexcept, it can throw a std::bad_alloc exception if it can't allocate memory, which you are not catching. noexcept means the method doesn't throw any exception at all, but that is not the case here.
There are other problems with your code, too:
Your destructor leaks memory if len is 0, ie if your Default constructor is called, or your Converting constructor is called with a null/empty string. If you call new[], you need to call delete[], regardless of the len used.
Your Copy constructor is not initializing str or len if the String being copied is empty.
In main(), you are not delete[]'ing the memory that toChars() returns.
optional for this particular situation, but in general, you are missing a Copy Assignment operator. And, since you are clearly using C++11 or later, you should also add a Move constructor and a Move Assignment operator as well. See the Rule of 3/5/0.
Try this instead (with no additional library functions added, per request):
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const {
char* temp = new char[len + 1];
for(unsigned int c = 0; c < len; ++c) {
temp[c] = str[c];
}
temp[len] = '\0';
return temp;
}
};
int main()
{
String t{"Boo is snoring"};
const char *chars = t.toChars();
cout << "t.len : " << t.length() << endl << "toChar() : " << chars << endl;
delete[] chars;
return 0;
}
Although, a simpler way to implement toChars() would look like this instead:
#include <iostream>
using namespace std;
class String {
public:
char* str = nullptr;
unsigned int len = 0;
String() = default;
String(const char* chars) {
if (chars) {
unsigned int i = 0;
while (chars[i]) {
++i;
}
len = i;
str = new char[len + 1];
for(int j = 0; j < len; ++j) {
str[j] = chars[j];
}
str[len] = '\0';
}
}
String(const String& s) {
if (!s.isEmpty()) {
len = s.len;
str = new char[len + 1];
for(int i = 0; i < len; ++i){
str[i] = s.str[i];
}
str[len] = '\0';
}
}
~String() noexcept {
delete[] str;
}
String& operator=(const String &s) {
if (&s != this) {
String tmp(s);
char *tmpstr = tmp.str;
unsigned int tmplen = tmp.len;
tmp.str = str;
tmp.len = len;
str = tmpstr;
len = tmplen;
}
return *this;
}
bool isEmpty() const noexcept {
return (len == 0);
}
unsigned int length() const noexcept {
return len;
}
const char* toChars() const noexcept {
return str ? str : "";
}
};
int main()
{
String t{"Boo is snoring"};
cout << "t.len : " << t.length() << endl << "toChar() : " << t.toChars() << endl;
return 0;
}
You get crash cause you allocate len - 1 chars new char[len - 1], but copy len chars for(int j = 0; j < len; j++) and do not copy zero-char in the end.
The first constructor should be
String(const char* chars) {
len = 0;
if (chars) {
while (chars[len])
len++;
}
str = new char[len + 1];
for (int j = 0; j < len; j++){
str[j] = chars[j];
}
str[len] = 0;
};
I hope you are able to update the second constructor properly.
The destructor should be
~String() noexcept{
delete[] str;
}
I hope you are able to fix other issues.
Related
#include <iostream>
#include <string>
#include <cstdlib>
using namespace std;
class String
{
private:
char* s;
int size;
public:
String()
{
s = NULL;
size = 0;
}
String(const char* str)
{
size = strlen(str);
s = new char[size];
for (int i = 0; i < size; i++)
s[i] = str[i];
}
String(const String& obj)
{
size = obj.size;
s = new char[size];
for (int i = 0; i < size; i++)
s[i] = obj[i];
}
String(int x)
{
size = x;
s = new char[size];
}
char& operator[](int i)
{
return *(s + i);
}
const char operator[](int i) const
{
return *(s + i);
}
String& operator+(const char& str) // append a char at the end of string
{
int newsize = size + 1;
String newstr(size);
for (int i = 0; i < size; i++)
{
newstr.s[i] = s[i];
}
newstr.s[size] = str;
delete[]s;
s = newstr.s;
size = newsize;
return *this;
}
String& operator+(char*& str) // append a string at the end of string
{
int newsize = size + strlen(str);
String newstr(newsize);
for (int i = 0; i < size; i++)
{
newstr.s[i] = s[i];
}
for (unsigned i = 0; i < strlen(str); i++)
{
newstr.s[size + i] = str[i];
}
delete[]s;
s = newstr.s;
size = newsize;
return *this;
}
operator int() const
{
int m;
m = size;
return m;
}
};
int main()
{
String s1("abcd");
String s2;
s2 = s1 + 'e';
cout << s2[3];
cout << s2[4];
char* c = (char*)"asdfgh";
s2 = s1 + c;
cout << s2[3];
cout << s2[4];
cout << s2[8];
}
My code runs perfectly until the statement char* c = (char*)"asdfgh". After this statement, I am not getting actual output. s2[3] after the statement char* c = (char*)"asdfgh" is supposed to give 'd' in the output, and similarly s2[4] is supposed to give 'a' in the output, and s2[8] is supposed to give 'g' in the output. But, the problem is, when I run this program, I am not getting these actual values.
Kindly look into this and tell me where I need to make changes.
Both of your operator+ implementations are wrong.
You are modifying the String object that is being added to, and then returning a reference to that object. You need to instead return a new String object that is the concatenation of the added-to and added-from String objects, without modifying the added-to String at all. What you have implemented would be more appropriate for an operator+= instead.
See What are the basic rules and idioms for operator overloading? for more details.
That said, there are some other problems with your code, as well. For instance, you are missing a destructor and a copy assignment operator, per the Rule of 3/5/0. You could also consider adding a move constructor and move assignment operator, as well.
Try something more like this:
#include <iostream>
#include <cstring>
#include <utility>
using namespace std;
class String
{
private:
char* s;
size_t size;
public:
String()
{
s = nullptr;
size = 0;
}
String(const char* str)
{
size = strlen(str);
s = new char[size+1];
for (int i = 0; i < size; ++i)
s[i] = str[i];
s[size] = '\0';
}
String(const String& str)
{
size = str.size;
s = new char[size+1];
for (int i = 0; i < size; ++i)
s[i] = str[i];
s[size] = '\0';
}
String(String&& str)
{
size = str.size; str.size = 0;
s = str.s; str.s = nullptr;
}
String(size_t x)
{
size = x;
s = new char[size+1];
s[size] = '\0';
}
~String()
{
delete[] s;
}
void swap(String& other)
{
std::swap(s, other.s);
std::swap(size, other.size);
}
String& operator=(char ch)
{
String newstr(1);
newstr[0] = ch;
newstr.swap(*this);
return *this;
}
String& operator=(const char* str)
{
String(str).swap(*this);
return *this;
}
String& operator=(const String& str)
{
if (this != &str)
String(str).swap(*this);
return *this;
}
String& operator=(String&& str)
{
String(std::move(str)).swap(*this);
return *this;
}
char& operator[](size_t i)
{
return s[i];
}
const char operator[](size_t i) const
{
return s[i];
}
String operator+(char ch)
{
/*
String newstr(*this);
newstr += ch;
return newstr;
*/
String newstr(size + 1);
for (int i = 0; i < size; ++i)
{
newstr[i] = s[i];
}
newstr[size] = ch;
return newstr;
}
String operator+(const char* str)
{
/*
String newstr(*this);
newstr += str;
return newstr;
*/
size_t slen = strlen(str);
String newstr(size + slen);
for (size_t i = 0; i < size; ++i)
{
newstr[i] = s[i];
}
for (size_t i = 0; i < slen; ++i)
{
newstr[size + i] = str[i];
}
return newstr;
}
String& operator+=(char ch)
{
String newstr(size + 1);
for (size_t i = 0; i < size; ++i)
{
newstr[i] = s[i];
}
newstr[size] = ch;
newstr.swap(*this);
return *this;
}
String& operator+=(const char* str)
{
size_t slen = strlen(str);
if (slen > 0)
{
String newstr(size + slen);
for (size_t i = 0; i < size; ++i)
{
newstr[i] = s[i];
}
for (size_t i = 0; i < slen; ++i)
{
newstr[size + i] = str[i];
}
newstr.swap(*this);
}
return *this;
}
size_t getSize() const
{
return size;
}
};
int main()
{
String s1("abcd");
String s2;
s2 = s1 + 'e';
cout << s2[3];
cout << s2[4];
s2 = s1 + "asdfgh";
cout << s2[3];
cout << s2[4];
cout << s2[8];
}
The reason it fails is actually earlier
String s1("abcd");
String s2;
s2 = s1 + 'e';
becuase your operator+ changes its lhs and then returns a reference to itself s2 is now a copy of s1. But they both point to the same 's' char array, things go bang shortly after that.
This would be fixed if you had an operator= that does the same as your copy constructor, but you dont have that
And as Remy points out, your operator+ semantics are wrong anyway. You should return 'newStr'
I have nearly finished creating my own custom string class. However, it seems not going well when the program did not return the output that I was expected. In detail:
Input:
string a = "Hello"
string b = "World!"
Expected output:
HelloWorld!
!dlroWolleH
Actual output:
Hello
Here is my code:
#ifndef _STRING
#define _STRING
#include<iostream>
#include<cstring>
class string {
private:
char* s = nullptr;
unsigned int size = 0;
public:
string();
~string() { delete s; };
string(char* );
string(const char* );
string(const string&);
friend std::ostream& operator << (std::ostream&, string&);
friend string operator +(string, string);
string& operator = (const string&);
string& operator = (const char&);
string& inverse();
char* inconst();
char* output() const{
return s;
}
};
#endif
string::string() :s{ nullptr } {
size = 1;
s = new char[size];
s[0] = '\0';
}
string::string(char* source) {
if (source == nullptr) {
size = 1;
s = new char[size];
s[0] = '\0';
}
else {
size = strlen(source) + 1;
s = new char[size];
s[size - 1] = '\0';
for (size_t k = 0; k < (size - 1); k++) {
s[k] = source[k];
}
}
}
string::string(const char* source) {
if (source == nullptr) {
size = 1;
s = new char[size];
s[0] = '\0';
}
else {
size = strlen(source) + 1;
s = new char[size];
s[size - 1] = '\0';
for (size_t k = 0; k < (size - 1); k++) {
s[k] = source[k];
}
}
}
string::string(const string& t) {
size = t.size;
s = new char[size];
s[size - 1] = '\0';
for (size_t k = 0; k < (size - 1); k++) {
s[k] = t.s[k];
}
}
string& string::operator=(const string& source) {
delete[] s;
size = source.size;
s = new char[size];
s[size - 1] = '\0';
for (size_t k = 0; k < (size - 1); k++) {
s[k] = source.s[k];
}
return *this;
}
string& string::operator=(const char&source) {
const char* t = &source;
if (t == nullptr) {
size = 1;
s = new char[size];
s[0] = '\0';
}
else {
size = strlen(t) + 1;
s = new char[size];
s[size - 1] = '\0';
for (size_t k = 0; k < (size - 1); k++) {
s[k] = t[k];
}
}
return* this;
}
string operator +(string a, string b) {
string t;
t.size = a.size + b.size;
t.s = new char[t.size + 1];
strncpy_s(t.s, a.size + 1, a.s, a.size);
strncpy_s(t.s + a.size, b.size + 1, b.s, b.size);
return t;
}
std::ostream& operator << (std::ostream& os, string& source) {
os << source.output();
return os;
}
char* string::inconst() {
char* t;
t = new char[size + 1];
for (size_t k = 0; k < size; k++)
{
t[k] = s[size - 1 - k];
}
t[size] = '\0';
return t;
}
string& string::inverse() {
this->s = this->inconst();
return*this;
}
int main(){
string a = "Hello";
string b = "World!";
string c = a + b;
std::cout << c << std::endl;
std::cout << c.inverse() << std::endl;
system("pause");
return 0;
}
It seems like that I have caught some errors at concatenation part ( overloading operator + assignment) since I can receive the output i want when i output separated variable a or b like std::cout << b << std::endl; but I cannot find out exactly what I was wrong. Please help me fix my code and thanks for helping me
Your string does store the terminating null character at s[size - 1].
Then in inconst you take the null character not into account, but pretend that size is number of characters in the string.
char* string::inconst() {
char* t;
t = new char[size + 1]; // why +1 here ?
for (size_t k = 0; k < size; k++)
{
t[k] = s[size - 1 - k];
}
t[size] = '\0'; // why another \0 ?
return t;
}
The first iteration assigns s[size-1] to t[0], ie in the end the string stored in t looks like this:
t[0] t[1] ... t[size] t[size+1]
\0 s[size-2] ... s[0] \0
You need to decide if size does count the null terminator or not and then be consistent about that.
Presumably this won't be the last time you need to do debugging, hence I propose to instrument the operator<< to print more information and not rely on the char* overload. Write a loop that prints character by character. If I didnt miss anything and my answer is correct you will see the contents of your string as explained above.
There are more issues in your code, the one I spotted is operator= not handling self assignment correctly. When you do
string s;
s = s;
Then your operator= first deletes the buffer and then copies from it. Just in case you are not convinced that this is an issue (because who would write s=s, thats silly, no?), consider for example a function void foo(string& a, string b&) { a = b; }.
On a more stylistic note, I suggest you to rename the method. inverse suggests that it would return a new string, while invert would make it clear that it modifies the string. (And I have no clue what inconst is supposed to mean.)
I am trying to move a part of my code from main function to the additional void function, but I keep getting a problem with deleting allocated memory in the end. By that moment my program did not printed out my array as it should have. So i am looking for a tip how i can fix this.
#include "pch.h"
#include <iostream>
using namespace std;
void push(char* C, int size, istream &in);
void print_str(char* word, int length);
int main()
{
char* C = new char[0];
int size = 0;
cout << "input your text: ";
push(C, size, cin);
print_str(C, size);
delete[] C;
return 0;
};
void print_str(char* word, int length) {
for (int k = 0; k < length; k++)
{
cout << word[k];
}
cout << " ";
};
void push(char* C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = C[i];
delete[] C;
C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
C[0] = current;
}
size++;
}
}
Breakpoint
push changes the value of C, so it must return the new value so that the other code can see the change. Like this (for instance)
int main() {
...
C = push(C, size, cin);
...
}
char* push(char* C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = C[i];
delete[] C;
C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
C[0] = current;
}
size++;
}
return C;
}
you need to define c as pointer to pointer , because changing c in push scope won't change value of c in main
here's the changed code
#include "pch.h"
#include <iostream>
using namespace std;
void push(char** C, int size, istream& in);
void print_str(char* word, int length);
int main()
{
char* C = new char[0];
int size = 0;
cout << "input your text: ";
push(&C, size, cin);
print_str(C, size);
delete[] C;
return 0;
};
void print_str(char* word, int length) {
for (int k = 0; k < length; k++)
{
cout << word[k];
}
cout << " ";
};
void push(char** C, int size, istream& in) {
while (1) {
char current = in.get();
if (current == '\n')
break;
else {
char* text1 = new char[size];
for (int i = 0; i < size; i++)
text1[i] = (*C)[i];
delete[] C;
*C = new char[size + 1];
for (int i = 0; i < size; i++)
C[i + 1] = text1[i];
delete[] text1;
(*C)[0] = current;
}
size++;
}
}
also you can make more efficient algorithms to reach your end ,instead of allocating and deallocating memory for each character witch is costy
I have four parts to this code. One of them is a DVD class and the others are HarryPotterDVD.h, HarryPotterDVD.cpp and HarryPotterDVDDriver.cpp. When I compile the code, it compiles without giving me any errors whatsoever, but when I try to run the compiled executable, I get an Abort(core dumped) error. I think it is because of the way I used the inherited functions. Could you guys please help me figure out how to solve the problem.
DVD.cpp
#include "DVD.h"
DVD::DVD() {
id =0;
title = new char[1];
title[0] = '\0';
director = new char[1];
director[0] = '\0';
}
DVD::DVD(unsigned int i, const char* t, const char* dir) {
id = i;
int len;
for(len = 0; t[len] !='\0'; ++len);
title = new char[len+1];
for(int i = 0; i < len+1; i++) {title[i]=t[i];}
int len2;
for(len2=0; dir[len2] !='\0'; ++len2);
director = new char[len2+1];
for(int j = 0; j<len2+1; j++) {director[j] = dir[j];}
}
DVD::DVD(const DVD &d): id(d.id) {
int len;
for(len=0; d.title[len] !='\0'; ++len);
title = new char[len+1];
for(int j = 0; j < len+1; j++) {
title[j] = d.title[j];
}
int len2;
for(len2=0; d.director[len2] != '\0'; ++len2);
director = new char[len2+1];
for(int j = 0; j<len2 +1; j++) {
director[j] = d.director[j];
}
}
DVD::~DVD() {
if (title) {
delete [] title;
}
if (director) {
delete [] director;
}
}
int DVD::getID() {
return id;
}
char* DVD::getTitle() {
return title;
}
char* DVD::getDirector() {
return director;
}
void DVD::display() {
cout << '[' << id << '.' << ' ' << title << '/' << director << ']' << endl;
}
void DVD::setID(unsigned int i) {
id = i;
}
void DVD::setTitle(const char* t) {
delete [] title;
int len;
for(len = 0; t[len] !='\0'; ++len);
title = new char[len+1];
for(int i = 0; i < len+1; i++) {title[i]=t[i];}
}
void DVD::setDirector(const char* dir) {
delete [] director;
int len2;
for(len2=0; dir[len2] !='\0'; ++len2);
director = new char[len2+1];
for(int j = 0; j<len2+1; j++) {director[j] = dir[j];}
}
DVD& DVD::operator= (const DVD& arg) {
id = arg.id;
int len;
for(len = 0; arg.title[len] !='\0'; ++len);
title = new char[len+1];
for(int i = 0; i < len+1; i++) {title[i]=arg.title[i];}
int len2;
for(len2=0; arg.director[len2] !='\0'; ++len2);
director = new char[len2+1];
for(int j = 0; j<len2+1; j++) {director[j] = arg.director[j];}
return *this;
}
HarryPotterDVD.h
#ifndef _HarryPotterDVD_
#define _HarryPotterDVD_
#include<iostream>
#include "DVD.h"
using namespace std;
class HarryPotterDVD : public DVD {
int episode;
char * antagonist;
public:
HarryPotterDVD(unsigned int i, char* t, char* dir, int n, char* ant);
HarryPotterDVD();
HarryPotterDVD(HarryPotterDVD& d);
~HarryPotterDVD();
int getEpisode();
char* getAntagonist();
void display();
void setEpisode(unsigned int e);
void setAntagonist(const char* c);
HarryPotterDVD& operator= (HarryPotterDVD& arg);
};
#endif
HarryPotterDVD.cpp
#include "HarryPotterDVD.h"
#include<iostream>
using namespace std;
HarryPotterDVD::HarryPotterDVD(unsigned int i, char* t, char* dir, int n, char* ant): DVD( i , t , dir) {
episode = n;
int len;
for(len = 0; ant[len] !='\0'; ++len);
antagonist = new char[len+1];
for(int j = 0; j < len+1; j++) {antagonist[j]=ant[j];}
}
HarryPotterDVD::HarryPotterDVD(HarryPotterDVD &d) {
DVD::setID(d.DVD::getID());
DVD::setTitle(d.DVD::getTitle());
DVD::setDirector(d.DVD::getDirector());
episode = d.episode;
int len;
for(len = 0; d.antagonist[len] != '\0'; len++);
antagonist = new char[len + 1];
for(int i = 0; i < len; i++){
antagonist[i] = d.antagonist[i];
}
antagonist[len+1] = '\0';
}
HarryPotterDVD::HarryPotterDVD() {
episode = -1;
char* tmp = "";
antagonist = tmp;
}
HarryPotterDVD::~HarryPotterDVD(){
delete [] antagonist;
}
int HarryPotterDVD::getEpisode(){
return episode;
}
char * HarryPotterDVD::getAntagonist(){
return antagonist;
}
void HarryPotterDVD::display(){
cout << "[" << DVD::getID() << ". HP" << episode;
cout << ":" << DVD::getTitle() << "/" << DVD::getDirector();
cout << "/" << antagonist << "]" << endl;
}
void HarryPotterDVD::setEpisode(unsigned int e){
episode = e;
}
void HarryPotterDVD::setAntagonist(const char * c){
delete [] antagonist;
int len;
for(len = 0; c[len] != '\0'; len++);
antagonist = new char[len + 1];
for(int i = 0; i < len; i++){
antagonist[i] = c[i];
}
antagonist[len+1] = '\0';
}
HarryPotterDVD& HarryPotterDVD::operator= (HarryPotterDVD &d){
delete [] antagonist;
episode = d.episode;
int len3;
for(len3 = 0; d.antagonist[len3] != '\0'; len3++);
antagonist = new char[len3 + 1];
for(int i = 0; i < len3; i++){
antagonist[i] = d.antagonist[i];
}
antagonist[len3+1] = '\0';
DVD::operator=(d);
/*
setID(d.getID());
int len;
for(len = 0; d.getTitle()[len] != '\0'; len++);
char * tit = new char[len+1];
for(int i = 0; i < len; i++){
tit[i] = d.getTitle()[i];
}
tit[len] = '\0';
setTitle(tit);
int len2;
for(len2 = 0; d.getDirector()[len2] != '\0'; len2++);
char* dire = new char[len2+1];
for(int i = 0; i < len2; i++){
dire[i] = d.getDirector()[i];
}
dire[len2] = '\0';
setDirector(dire);
*/
return* this;
}
HarryPotterDVDDriver.cpp
#include<iostream>
using namespace std;
#include"DVD.h"
#include"HarryPotterDVD.h"
int main() {
HarryPotterDVD h1;
HarryPotterDVD h2(1, "Chamber of Secrets", "Chris Columbus", 2, "Tom Riddle");
HarryPotterDVD h3(h2);
h1 = h3;
cout << h2.getEpisode() << endl;
cout << h2.getAntagonist() << endl;
h3.display();
h1.setEpisode(5);
h1.setAntagonist("Prabesh");
h1.display();
}
In the default constructor of HarryPotterDVD, you are assigning a random pointer to member variable antagonist which is not created with new[]
HarryPotterDVD::HarryPotterDVD() {
episode = -1;
char* tmp = "";
antagonist = tmp;
}
In the operator=()function, when the statement h1=h3; is being executed, you are deleting the antagonist using delete[] which is causing the segmentation fault.
delete is null-safe. So, in your default constructors, you can just make the pointers to nullptr and delete of them during assigning won't cause any errors. If you change this way, your issue should go away.
HarryPotterDVD::HarryPotterDVD() {
episode = -1;
antagonist = nullptr;
}
When I run my code i get a segmentation fault for calling the default constructor, but not every time I call it. It faults when I try to dynamically allocate new memory after overloading the + operator. I know seg faults happen with misuse of pointers but I call the def. constructor prior in the code and it works.
here is a git repo with main and header if needed:
#include <iostream>
#include "proj1-5-MyString.h"
#include <cmath>
using namespace std;
MyString::MyString() {
capacity = 10;
size = 0;
data = new char[capacity];
data[size] = '\0';
}
//Constructor
MyString::MyString(const char *input) {
this->capacity = 10;
this->size = 0;
this->data = new char[this->capacity];
for (int count = 0; input[count] != '\0'; count++) {
if (count >= this->capacity) {
this->capacity *= 2;
char *temp = new char[this->capacity];
for (int i = 0; i < this->size; i++) {
temp[i] = this->data[i];
}
delete[] this->data;
this->data = temp;
delete[] temp;
}
this->data[count] = input[count];
this->size = count + 1;
}
while ((double) this->size < 0.25 * ((double) (this->capacity))) {
this->capacity = (int)floor(this->capacity / 2);
}
this->data[this->size + 1] = '\0';
}
//Constructor with an initialization character string
MyString::~MyString() {
delete[] this->data;
data = NULL;
}
//Destructor
MyString::MyString(const MyString &that) {
this->data = new char[this->capacity];
this->capacity = that.capacity;
this->size = that.size;
for(int i = 0; i < size; i++){
this->data[i] = that.data[i];
}
while(this->size < 0.25 * (double)(this->capacity)){
this->capacity = (int)((double)that.capacity / 2.0);
}
}
//Copy constructor
MyString &MyString::operator=(const MyString &input) {
if (this->data != input.data) {
delete[] this->data;
this->capacity = input.capacity;
this->size = input.size;
int charCount = 0;
for ( charCount; charCount < input.size; charCount++) {
if (charCount >= this->capacity) {
this->capacity *= 2;
char *temp = new char[this->capacity];
for (int j = 0; j < charCount; j++) {
temp[j] = this->data[j];
}
delete[] this->data;
this->data = temp;
delete[] temp;
}
this->data[charCount] = input.data[charCount];
this->size = charCount + 1;
}
}
return *this;
}
//Overloaded assignment operator, make a copy of MyString object
bool MyString::operator==(const MyString &otherString) const {
int i = 0;
bool same = true;
if (this->size == otherString.size) {
while (i < otherString.size) {
if (this->data[i] == otherString.data[i]) {
same = i <= size;
} else {
same = false;
}
i++;
}
} else {
same = false;
}
return same;
}
//overloaded equivalence relational operator
char &MyString::operator[](int val) {
return this->data[val];
}
//overloaded [ ] should return a char by reference
void MyString::operator+=(const MyString &otherStr) {
*this = *this + otherStr;
}
//overloaded += operator, use to concatenate two MyStrings
MyString MyString::operator+(const MyString &otherStr) const {
//SEGFAULT HERE
MyString doubleString;
cout << doubleString.capacity << endl;
while (doubleString.capacity < (this->size + otherStr.size)) {
doubleString.capacity *= 2;
}
for (int i = 0; i < max(this->size, otherStr.size); i++) {
doubleString.data[i] = this->data[i];
doubleString.data[i + this->size] = otherStr.data[i];
}
doubleString.size = this->size + otherStr.size;
return doubleString;
}
//Create a new MyString object that is the concatenation of two MyString
//objects
void MyString::getline(istream &in, char delimit) {
delimit = '\n';
int size = 10;
char buffer[size];
int charNum = 0;
while (in.get(buffer[charNum++])) {
if (buffer[charNum - 1] == delimit) {
break;
}
if (charNum >= size) {
char *temp = new char[size * 2];
for (int j = 0; j < size; j++) {
temp[j] = data[j];
}
delete[] data;
data = temp;
delete[] temp;
}
}
}
//reads an entire line from a istream. Lines are terminated with delimit
//which is newline ā\nā by default
int MyString::length() const {
return this->size;
}
//return the length of the string
ostream &operator<<(ostream &out, MyString &stringWord) {
for (int i = 0; i < stringWord.size; i++) {
out << stringWord.data[i];
}
return out;
}
//overloaded insertion operator
For instance, if you have this code:
MyString s0 = "ABC";
MyString s1 = "DEF";
auto s2 = s0 + s1;
The first problem is in the constructor of MyString. Your strings are not \0 terminated.
This can be fixed quite easiely though:
MyString::MyString(const char *input)
{
this->capacity = 10;
this->size = 0;
//this->data = new char[this->capacity]; //<- Old
this->data = new char[this->capacity](); //<- New
There are multiple places where you don't initialize the allocated char array. Please check your code and do so. Either via the char() constructor or various other ways (std::fill, memset, ...).
Please remember to debug your own code before posting a question. You can spot this in the debugger pretty easiely.