Segmentation Fault when trying to create a dynamically allocated char array - c++

This is my code:
#include<iostream>
#include<string.h>
using namespace std;
class Zichara
{
private:
char *name;
int price;
void copy(const Zichara &from)
{
name = new char[strlen(from.name) + 1];
strcpy(name, from.name);
price = from.price;
}
public:
Zichara(const char *name, int price) {
this->name = new char[strlen(name) + 1];
strcpy(this->name, name);
this->price = price;
}
Zichara(const Zichara &from)
{
copy(from);
}
~Zichara() {
delete [] name;
}
friend class PlaninarskiDom;
};
class PlaninarskiDom {
private:
char name[15];
int prices[2];
char star;
bool isZichara;
Zichara *zich;
void copy(const PlaninarskiDom &from) {
strcpy(name, from.name);
star = from.star;
isZichara = from.isZichara;
zich = from.zich;
for(int i = 0; i < 2; i++) {
prices[i] = from.prices[i];
}
}
public:
PlaninarskiDom(const char *name = "", int prices = 0, const char star = '\0') {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = 0;
this->prices[1] = 0;
}
PlaninarskiDom(const char *name, int *prices, const char star) {
strcpy(this->name, name);
this->star = star;
isZichara = 0;
zich = 0;
this->prices[0] = prices[0];
this->prices[1] = prices[1];
}
PlaninarskiDom(const PlaninarskiDom &from) {
copy(from);
}
~PlaninarskiDom() {
delete [] zich;
}
PlaninarskiDom& operator = (const PlaninarskiDom &from) {
if(this == &from) return *this;
delete [] zich;
copy(from);
return *this;
}
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
void operator --() {
if((int)star >= 65 && (int)star <= 70) {
++star;
if((int)star == 69) {
++star;
}
}
}
bool operator <= (char c) {
return star >= c;
}
void presmetajDnevenPrestoj(int day, int month, int &price) {
if(day < 0 || day > 31 || month < 0 || month > 12) {
throw 99;
}
else if(month >= 4 && month <= 8) {
price = prices[0];
}
else {
price = prices[1];
}
if(isZichara) {
price += zich->price;
}
}
friend ostream& operator << (ostream &, const PlaninarskiDom &);
};
ostream& operator << (ostream &os, const PlaninarskiDom &rhs) {
cout << rhs.name << " klasa:" << rhs.star << endl;
if(rhs.isZichara) {
cout << " so zichara" << endl;
}
return os;
}
int main(){
PlaninarskiDom p; //креирање на нов објект од класата планинарски дом
//во следниот дел се вчитуваат информации за планинарскиот дом
char imePlaninarskiDom[15],mestoZichara[30],klasa;
int ceni[12];
int dnevnakartaZichara;
bool daliZichara;
cin>>imePlaninarskiDom;
for (int i=0;i<2;i++) cin>>ceni[i];
cin>>klasa;
cin>>daliZichara;
//во следниот дел се внесуваат информации и за жичарата ако постои
if (daliZichara) {
cin>>mestoZichara>>dnevnakartaZichara;
PlaninarskiDom pom(imePlaninarskiDom,ceni,klasa);
Zichara r(mestoZichara,dnevnakartaZichara);
pom.setZichara(r);
p=pom;
}
else{
PlaninarskiDom *pok=new PlaninarskiDom(imePlaninarskiDom,ceni,klasa);
p=*pok;
}
//се намалува класата на планинарскиот дом за 2
--p;
--p;
int cena;
int den,mesec;
cin>>den>>mesec;
try{
p.presmetajDnevenPrestoj(den,mesec,cena); //тука се користи функцијата presmetajDnevenPrestoj
cout<<"Informacii za PlaninarskiDomot:"<<endl;
cout<<p;
if (p<='D')
cout<<"Planinarskiot dom za koj se vneseni informaciite ima klasa poniska ili ista so D\n";
cout<<"Cenata za "<<den<<"."<<mesec<<" e "<<cena; //се печати цената за дадениот ден и месец
}
catch (int){
cout<<"Mesecot ili denot e greshno vnesen!";
}
}
I ran a debugger on this code and it highlighted this:
name = new char[strlen(from.name) + 1];
This is the line of code as the line where the Seg Fault comes from.
This is an exercise for a class I have and I have to do it using dynamic memory allocation.
I've done this exact same thing many times before and there was no such error, so I have no idea why it is appearing, and I couldn't find an answer to this question on Google so far, so I apologize if somewhere out there it does exist.
Thanks everyone for the suggestions, this has been fixed!

You call this method:
void setZichara(Zichara &z) {
if(isZichara == 0) {
zich->copy(z);
isZichara = 1;
}
}
but you never allocate zich so you invoke UB calling a method on nullptr
Note: your PlaninarskiDom::copy() is incorrect as well, as you just assign pointer from another object aka shallow copy, which will lead to multiple destruction, though most probably you did not hit this issue yet. You should do deep copy instead or use std::shared_ptr is you plan to share ownership. Anyway if you are not limited by conditions using smart pointers are preferable when dealing with dynamically allocated objects. Or using special containers like std::vector or std::string which do proper memory management for you.

Related

Compilation error in C++ when using an assignment operator =?

I have written a program which was given to me as a homework assignment (it's a bit longer). The issue is that it compiles in CodeBlocks but it does not compile in Visual Studio 2017 it says - binary '=': no operator found which takes a right-hand operand of type 'CAutomobile' (or there is no acceptable conversion.
I would like to ask why is that because I could not myself find the error? I tried commenting the operator =function but still the error remained.
#include <iostream>
#include <algorithm>
#include <string>
#include <stdlib.h>
using namespace std;
class CVehicle {
string name;
int year;
public:
CVehicle() {
name = "Car";
year = 1990;
}
CVehicle(string n, int y) {
name = n;
year = y;
}
CVehicle(const CVehicle& vc) {
name = vc.name;
year = vc.year;
}
void setName(string n) {
name = n;
}
void setYear(int y) {
year = y;
}
string getName() {
return name;
}
int& getYear() {
return year;
}
virtual void Print(ostream& os) = 0;
};
class CAutomobile :public CVehicle {
double litres;
public:
CAutomobile() :CVehicle() {
litres = 7.2;
}
CAutomobile(string nm, int yr, double l) :CVehicle(nm, yr) {
litres = l;
}
void setLitres(double l) {
l = litres;
}
double& getLitres() {
return litres;
}
void Print(ostream& os) override {
os << getName() << endl;
os << getYear() << endl;
os << litres << endl;
}
friend bool operator< (CAutomobile a1, CAutomobile a2) {
if (a1.litres < a2.litres) {
return true;
}
return false;
}
CAutomobile operator= (CAutomobile& at) {
CAutomobile au;
au.getName() = at.getName();
au.getYear() = at.getYear();
au.getLitres() = at.getLitres();
return au;
}
CAutomobile operator+(CAutomobile aut) {
CAutomobile a;
a.getLitres() = getLitres() + aut.getLitres();
return a;
}
friend ostream& operator<< (ostream& o, CAutomobile a) {
o << a.getName() << endl;
o << a.getYear() << endl;
o << a.getLitres() << endl;
return o;
}
};
int main()
{
CAutomobile a[] = {
CAutomobile(),
CAutomobile("Wolkswagen",1970,80.5),
CAutomobile("Fiat",1979,21.9),
CAutomobile("Opel",1978,13.7)
};
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
cout << "Name" << ' ' << a[i].getName() << endl;
cout << "Year" << ' ' << a[i].getYear() << endl;
cout << "Litres" << ' ' << a[i].getLitres() << endl;
}
int range = 2016 - 1990 + 1;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++) {
a[i].setLitres(rand() % 100 + 1);
a[i].setYear(rand() % range + 1996);
}
//сортираме масива по литри и извеждаме
//най малкия (първия) му елемент
for (int i = 0; i < sizeof(a-1); i++) {
for (int j = 0; j < sizeof(a-1); j++) {
if (a[j].getLitres() > a[j + 1].getLitres()) {
swap(a[j], a[j + 1]);
}
}
}
cout << a[0] << endl;
CAutomobile k = a[0] + a[3];
cout << k.getLitres() << endl;
}
CAutomobile::operator = is completely wrong. It takes a non-const reference and assignes its field to a new object. Instead it should take a const reference and modify current object.
CAutomobile & operator =(CAutomobile const & other)
{
assert(this != ::std::addressof(other)); // check for self-assignment
SetName(other.getName());
SetYear(other.getYear());
SetLitres(other.getLitres());
return *this;
}
This will bring up another problem: getters are not const-qualified, so they should be fixes as well:
string const & getName(void) const {
return name;
}
int const & getYear(void) const {
return year;
}

Repeating words in string class

So I have to write a string class, and I need help with reading from a file into a vector of string classes I've created. It somewhat works, as it reads from the file but it repeats the the word read in a few times depending on which word it's on.
// .h
/*Class description:
A string class. Various functions for the class.
String is passed into objects of the class. Reads
and writes to files.*/
#ifndef MYString12_H
#define MYString12_H
#include <fstream>
using namespace std;
class MYString12
{
public:
MYString12();
MYString12(const MYString12 & mstr);
MYString12(const char* ptr);
~MYString12();
MYString12& operator = (const MYString12& argStr);
friend MYString12 operator + (const MYString12& str1, const MYString12& str2);
char operator [] (int index);
bool operator > (const MYString12& argStr2);
bool operator < (const MYString12& argStr2);
bool operator == (const MYString12& argStr);
friend istream& operator >> (istream& istr, MYString12& argStr);
friend ostream& operator << (ostream& istr, MYString12& argStr);
int length() const;
int capacity()const;
char at(int index);
const char* c_str()const;
static int getCurrentCount();
static int getCreatedCount();
private:
char* str;
int cap = 20;
int end;
const int compareTo(const MYString12& argStr);
static int currentCount;
static int createdCount;
};
#endif
Here is class cpp file
// MYString12.cpp
#include "stdafx.h"
#include "MYString12.h"
#include <iostream>
#include <iomanip>
#include <math.h>
#include <cstdlib>
using namespace std;
int MYString12::createdCount = 0;
int MYString12::currentCount = 0;
// default constructor
MYString12::MYString12()
{
cap = 20;
end = 0;
str = new char[cap];
str[end] = '\0';
createdCount++;
currentCount++;
}
// copy constructor
MYString12::MYString12(const MYString12& mstr)
{
this->end = mstr.end;
this->cap = mstr.cap;
this->str = new char[mstr.cap];
while (end >= cap) {
cap += 20;
}
for (int i = 0; i < end; i++) {
str[i] = mstr.str[i];
}
//mstr.str[end] = '\0';
createdCount++;
currentCount++;
}
// constructor with string passed in
MYString12::MYString12(const char* ptr)
{
int i = 0;
while (ptr[i] != '\0') {
end++;
i++;
}
while (end >= cap) {
cap += 20;
}
str = new char[cap];
for (int j = 0; j < end; j++) {
str[j] = ptr[j];
}
createdCount++;
currentCount++;
}
// destructor
MYString12::~MYString12()
{
delete[] str;
currentCount--;
}
// overloaded assignment operator
GAString12& GAString12::operator = (const GAString12& mstr)
{
if (this == &mstr) {
return *this;
}
this->end = mstr.end;
this->cap = mstr.cap;
while (end >= cap) {
cap += 20;
}
for (int i = 0; i < end; i++) {
str[i] = mstr.str[i];
}
//mstr.str[end] = '\0';
return *this;
}
// overloaded concatanation operator
MYString12 operator + (const MYString12& str1, const MYString12& str2)
{
int temp = str1.end + str2.end + 1;
char tempArray[200];
int i = 0;
int j = 0;
while (i < temp)
{
if (i < str1.end)
{
tempArray[i] = str1.str[i];
i++;
} else {
tempArray[i] = str2.str[j];
i++;
j++;
}
}
tempArray[i] = '\0';
MYString12 concatenatedObj(tempArray);
return concatenatedObj;
}
// overloaded index operator
char MYString12::operator [] (int index)
{
return str[index];
}
// overloaded greater than operator
bool MYString12::operator > (const MYString12& argStr)
{
if ((*this).compareTo(argStr) > 0)
{
return true;
}
else {
return false;
}
}
// overloaded less than operator
bool MYString12::operator < (const MYString12& argStr)
{
if ((*this).compareTo(argStr) < 0)
{
return true;
}
else {
return false;
}
}
// overloaded equals equals operator
bool MYString12::operator == (const MYString12& argStr)
{
if ((*this).compareTo(argStr) == 0)
{
return true;
}
else {
return false;
}
}
// compares ascii values of objStr and argStr
const int MYString12::compareTo(const MYString12& argStr)
{
int asciiSubtraction = 0;
int limit = 0;
if (end <= argStr.end)
{
limit = end;
}
else {
limit = argStr.end;
}
int i = 0;
while (i <= limit && (str[i] == argStr.str[i])) {
i++;
}
asciiSubtraction = str[i] - argStr.str[i];
return asciiSubtraction;
}
// overloaded extraction operator
istream& operator >> (istream& istr, MYString12& argStr)
{
char temp[100];
istr >> temp;
argStr = GAString12(temp);
return istr;
}
// overloaded insertion operator
ostream& operator << (ostream& ostr, MYString12& argStr)
{
int i = 0;
while (argStr.str[i] != '\0')
{
ostr << argStr.str;
i++;
}
return ostr;
}
// returns size of passed in string
int MYString12::length() const
{
return end;
}
// returns size of memory allocated
int MYString12::capacity() const
{
return cap;
}
// returns a char of string at passed index
char MYString12::at(int index)
{
if (index < 0 || index > end) {
return '\0';
}
else {
return str[index];
}
}
// returns passed in string as c string
const char* MYString12::c_str() const
{
createdCount++;
currentCount++;
return str;
}
// returns the amount of alive instances of class
int MYString12::getCurrentCount()
{
return currentCount;
}
// returns the amount of overall created instances of class
int MYString12::getCreatedCount()
{
return createdCount;
}
And here is main
// main
int main()
{
vector<MYString12> word(100);
ifstream fin;
fin.open("infile3.txt");
if (fin.fail()) {
cout << "Error." << endl;
exit(1);
}
int wordCount = 0;
while (fin >> word[wordCount]) {
cout << word[wordCount];
system("pause");
wordCount++;
}
word.resize(wordCount);
fin.close();endl;
return 0;
}
It doesn't print out to the console any of the words. Nothing is printed. Why doesn't it print?

Copy Constructor for dynamically allocated array

Trying to familiarize myself with the "Rule of 3" and Im having trouble getting a Copy Constructor to work. One of the class private members is returning 0 when it should have a value of 3.
Im not sure as to why when the Copy Constructor function is performed, a value of 0 is supplied to that classes private member. The member in question is theSize which is returned via the size() function in class.cpp.
class.h
class Catalog {
public:
Catalog (int maxCapacity = 100)
int size() const;
int capacity() const;
void add (Book b);
Catalog(const Catalog& c);
~Catalog();
Catalog& operator= (constCatalog& c) {
if (this != &c) {
delete[] books;
books = new Book[theCapacity];
*books = *(c.books);
}
return *this;
}
private:
Book* books;
int theCapacity;
int theSize;
};
class.cpp
Catalog::Catalog(int maxCapacity) {
theCapacity = maxCapacity;
theSize = 0;
books = new Book[theCapacity];
}
int Catalog::size() const {
return theSize();
}
int Catalog::capacity() const {
return theCapacity;
}
void Catalog::add (Book b)
{
if (theSize < theCapacity || contains(b.getID())) {
if (theSize == 0) {
books[0] = b;
theSize++;
}
else {
if (!contains(b.getID())) {
int i = theSize;
for (; i && b < books[i-1]; --i) {
books[i] = books[i - 1];
}
books[i] = b;
for (; i; --i) {
books[i - 1] = books[i - 1];
}
theSize++;
}
else {
for (int i = 0; i < theSize; ++i) {
if (b == books[i]) {
books[i] = b;
}
}
}
}
// Debugging only
/*for (int i = 0; i < theSize; i++) {
//cout << books[i] << endl;
}*/
}
}
bool Catalog::contains(std::string bookID) const
{
for (int i = 0; i < theSize; ++i)
{
if (books[i].getID() == bookID)
return true;
}
return false;
}
Catalog::Catalog(const Catalog& c) {
books = new Book[c.theSize];
for (int i = 0; i < c.theSize; i++) {
books[i] = c.books[i];
}
Catalog::~Catalog() {
delete[] books;
}
Later in main.cpp when I call c1.size() where c1 is the result of return c in another function that through use of the debugger comes from the Copy Constructor and then goes to the Destructor. However, c1.size() is returning as 0 though the Copy Constructor theSize = c.size() has a value of 3 when stepped through.
book.cpp
using namespace std;
/**
* Create a book.
*
* #param id the Gutenberg ID for this book
* #param authorInfo the author of the book
* #param title the title of the book
*/
Book::Book (std::string theId, std::string authorInfo, std::string theTitle)
: id(theId), authorName(authorInfo), title(theTitle)
{
}
bool Book::operator< (const Book& b) const
{
return id < b.id;
}
bool Book::operator== (const Book& b) const
{
return (id == b.id);
}
std::ostream& operator<< (std::ostream& out, const Book& b)
{
cout << b.getID() << "\t"
<< b.getAuthor() << "\t"
<< b.getTitle();
return out;
}
std::istream& operator>> (std::istream& in, Book& b)
{
string line;
getline (in, line);
if (!in.good())
return in;
int tab1 = line.find ("\t");
int tab2 = line.find ("\t", tab1+1);
string id = line.substr(0, tab1);
string author = line.substr (tab1+1, tab2-tab1-1);
string title = line.substr(tab2+1);
b.setID (id);
b.setAuthor (author);
b.setTitle (title);
return in;
}
main.cpp
using namespace std;
Catalog readCatalog(const string& fileName)
{
Catalog c;
ifstream in (fileName);
in >> c;
in.close();
return c;
}
Catalog mergeCatalogs (const Catalog& cat1, const Catalog& cat2)
{
Catalog result (cat1.size() + cat2.size());
int i = 0;
int j = 0;
while (i < cat1.size() && j < cat2.size())
{
Book b1 = cat1.get(i);
Book b2 = cat2.get(j);
if (b1.getID() < b2.getID())
{
result.add(b1);
++i;
}
else
{
result.add(b2);
++j;
}
}
while (i < cat1.size())
{
result.add(cat1.get(i));
++i;
}
while (j < cat2.size())
{
result.add(cat2.get(j));
++j;
}
return result;
}
void mergeCatalogFiles (const string& catalogFile1, const string& catalogFile2)
{
Catalog c1, c2;
c1 = readCatalog(catalogFile1);
cout << catalogFile1 << " contained " << c1.size() << " books." << endl;
c2 = readCatalog(catalogFile2);
cout << catalogFile2 << " contained " << c2.size() << " books." << endl;
Catalog c3 = mergeCatalogs (c1, c2);
cout << "Their merge contains " << c3.size() << " books." << endl;
cout << c3 << flush;
}
int main (int argc, char** argv)
{
if (argc != 3)
{
cerr << "Usage: " << argv[0] <<
"catalogFile1 catalogFile2" << endl;
return -1;
}
string file1 = argv[1];
string file2 = argv[2];
mergeCatalogFiles (file1, file2);
if (Counted::getCurrentCount() == 0)
{
cout << "No memory leak detected." << endl;
return 0;
}
else
{
cout << "Memory leak detected: " << Counted::getCurrentCount() << endl;
return -2;
}
}
Follow rule of zero: use std::vector<Book> to replace the array pointer and the size.
Your capacity is a limit on the size.
When at capacity. use equal range to find where to insert, replace last element then std rotate.
Managing both resources and business logic in the same class is bug prone. Do one thing at a time.
Try something more like this instead:
class Catalog
{
public:
Catalog (int maxCapacity = 100);
Catalog(const Catalog& c);
~Catalog();
int size() const;
int capacity() const;
void add (const Book &b);
Book* find(const std::string &bookID) const;
Catalog& operator= (Catalog c);
private:
Book* books;
int theCapacity;
int theSize;
void swap(Catalog &c);
};
#include "class.h"
#include <algorithm>
Catalog::Catalog(int maxCapacity)
{
theCapacity = maxCapacity;
theSize = 0;
books = new Book[theCapacity];
}
Catalog::Catalog(const Catalog& c)
{
theCapacity = c.theCapacity;
books = new Book[theCapacity];
for(int i = 0; i < c.theSize;; ++i)
books[i] = c.books[i];
theSize = c.theSize;
}
Catalog::~Catalog()
{
delete[] books;
}
Catalog& Catalog::operator= (const Catalog &c)
{
if (this != &c)
Catalog(c).swap(*this);
return *this;
}
void Catalog::swap(Catalog &c)
{
std::swap(books, c.books);
std::swap(theSize, c.theSize);
std::swap(theCapacity, c.theCapacity);
}
int Catalog::size() const
{
return theSize;
}
int Catalog::capacity() const
{
return theCapacity;
}
void Catalog::add (const Book &b)
{
Book *book = find(b.getID());
if (book) {
*book = b;
}
else if (theSize < theCapacity)
{
int i;
for (i = theSize; i && b < books[i-1]; --i) {
books[i] = books[i - 1];
}
books[i] = b;
++theSize;
}
// Debugging only
/*
for (int i = 0; i < theSize; ++i) {
cout << books[i] << endl;
}
*/
}
Book* Catalog::find(const std::string &bookID) const
{
for (int i = 0; i < theSize; ++i)
{
if (books[i].getID() == bookID)
return &books[i];
}
return 0;
}
That being said, this would be much simpler and easier to manage if you use std::vector and STL algorithms. Let the STL do the hard work for you:
#include <vector>
class Catalog
{
public:
Catalog (int initialCapacity = 100);
int size() const;
int capacity() const;
void add (const Book &b);
Book* find(const std::string &bookID) const;
private:
std::vector<Book> books;
};
#include "class.h"
#include <algorithm>
Catalog::Catalog(int initialCapacity)
{
books.reserve(initialCapacity);
}
int Catalog::size() const
{
return books.size();
}
int Catalog::capacity() const
{
return books.capacity();
}
void Catalog::add (const Book &b)
{
Book *book = find(b.getID());
if (book) {
*book = b;
}
else {
books.insert(std::upper_bound(books.begin(), books.end(), b), b);
}
// Debugging only
/*
for (Book &book: books) {
cout << book << endl;
}
*/
}
Book* Catalog::find(const std::string &bookID) const
{
auto iter = std::find_if(books.begin(), books.end(), [&bookID](const Book &b){ return (b.getID() == bookID); });
if (iter != books.end())
return &*iter;
return 0;
}

Access violation reading c++ [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
/Unhandled exception at 0x00AB6591 in Building.exe: 0xC0000005: Access violation reading location 0x00000000./
#pragma warning (disable : 4996)
#include<iostream>
#include<string>
#include<cassert>
using namespace std;
class Building
{
private:
int height;
int area;
char*address;
public:
Building();
Building(int, int, char*);
~Building();
Building(const Building &);
Building & operator=(const Building&);
int getHeight()const;
int getArea()const;
char* getAddress()const;
void print()const;
void setHeight(int);
void setArea(int);
void setAddress(char*);
};
Building::Building()
{
height = 0;
area = 0;
address = new char[1];
address = NULL;
}
Building::Building(int h, int ar, char* a)
{
height = h;
area = ar;
address = new char[strlen(a)+1];
assert(address != NULL);
address = NULL;
}
Building::~Building()
{
delete[]address;
}
Building::Building(const Building & b)
{
height = b.height;
area = b.area;
address = new char[strlen(b.address) + 1];
assert(address != NULL);
strcpy(address,b.address);
}
Building & Building::operator=(const Building& b)
{
if (this != &b)
{
delete[]address;
height = b.height;
area = b.area;
address = new char[strlen(b.address) + 1];
assert(address != NULL);
strcpy(address, b.address);
}
return *this;
}
int Building::getHeight()const
{
return height;
}
int Building::getArea()const
{
return area;
}
char* Building::getAddress()const
{
return address;
}
void Building::print()const
{
cout << "Height = " << getHeight() << endl << "Area = " << getArea() << endl << "Address = " << getAddress() << endl;
}
void Building::setHeight(int h)
{
height = h;
}
void Building::setArea(int ar)
{
area = ar;
}
void Building::setAddress(char* adr)
{
strcpy(address, adr);
}
//==========================================================================================================
class House :public Building
{
private:
int floors;
char*name;
public:
House();
House(int,int,char*,int=0, char* =" ");
~House();
House(const House&);
House& operator=(const House&);
int getFloors()const;
char* getName()const;
void setFloors(int);
void setName(char*);
void print()const;
};
House::House()
{
floors = 0;
name = new char[1];
assert(name != NULL);
name = NULL;
}
House::House(int h, int ar, char* adr, int f, char* n) :Building(h, ar, adr)
{
floors = f;
name = new char[strlen(n) + 1];
assert(name != NULL);
strcpy(name, n);
}
House::~House()
{
delete[]name;
}
House::House(const House& h) :Building(h)
{
floors = h.floors;
name = new char[strlen(h.name) + 1];
assert(name != NULL);
strcpy(name, h.name);
}
House& House::operator=(const House&h)
{
if (this != NULL)
{
Building::operator=(h);
delete[]name;
floors = h.floors;
name = new char[strlen(h.name) + 1];
assert(name != NULL);
strcpy(name, h.name);
}
return*this;
}
int House::getFloors()const
{
return floors;
}
char* House::getName()const
{
return name;
}
void House::setFloors(int f)
{
floors = f;
}
void House::setName(char* na)
{
strcpy(name, na);
}
void House::print()const
{
Building::print();
cout << "Floors: " << getFloors() << endl << "Name: " << getName() << endl;
}
//=============================================================================================================
House getBigger(House m[], int size)// a house with bigger avarage height of a floor
{
House temp;
int max = 0;
int index = 0;
for (int i = 0; i < size; i++)
{
int avH = (m[i].getHeight() / m[i].getFloors());
if (avH >= max)
{
max = avH;
index = i;
}
}
return m[index];
}
//=============================================================================================================
int main()
{
House h1(16,400,"Bla street",4,"Marion");
h1.print();
House h2;
h2.setHouse();
h2.print();
House h3;
h3.setHouse();
h3.print();
House arr[] = { h1, h2, h3 };
House h4;
h4=getBigger(arr, 3);
h4.print();
system("pause");
return 0;
}
I have problem with my program for building and a house. It is simple maybe but I don't know why throws exception. I think that my try for user input is wrong anywhere.
Your Building constructors both set address to null. If you are trying to print the address anywhere, your code will give you that error.

Strange Seg Fault

I'm sorry, I know this is the umpteenth seg fault post on Stack Overflow, but I've tried for a few days to fix this code and I'm stumped, so I decided to turn to you guys. I hope you can help!
Anyway, I'm getting a strange segfault in this code:
account.h (Note, I'm not allowed modify the account.h file in anyway, as per the assignment. :)
class account
{
public:
typedef char* string;
static const size_t MAX_NAME_SIZE = 15;
// CONSTRUCTOR
//account();
account (char* i_name, size_t i_acnum, size_t i_hsize);
account (const account& ac);
// DESTRUCTOR
~account ( );
// MODIFICATION MEMBER FUNCTIONS
void set_name(char* new_name);
void set_account_number(size_t new_acnum);
void set_balance(double new_balance);
void add_history(char* new_history);
// CONSTANT MEMBER FUNCTIONS
char* get_name () const;
size_t get_account_number ( ) const;
double get_balance( ) const;
size_t get_max_history_size( ) const;
size_t get_current_history_size ( ) const;
string* get_history() const;
friend std::ostream& operator <<(std::ostream& outs, const account& target);
private:
char name[MAX_NAME_SIZE+1]; //name of the account holder
size_t ac_number; //account number
double balance; //current account balance
string* history; //Array to store history of transactions
size_t history_size; //Maximum size of transaction history
size_t history_count; //Current size of transaction history
};
account.cxx:
#include <string.h>
#include <cassert>
#include <cstdlib>
#include <iostream>
#include "account.h"
using namespace std;
account::account(char* i_name, size_t i_acnum, size_t i_hsize)
{
assert(strlen(i_name) <= MAX_NAME_SIZE);
strcpy(name, i_name);
ac_number = i_acnum;
history_size = i_hsize;
balance = 0;
history_count = 0;
history = new string[history_size];
}
account::account(const account& ac)
{
strcpy(name, ac.name);
ac_number = ac.ac_number;
balance = ac.balance;
history = new string[ac.history_size];
for(size_t i = 0; i < ac.history_count; i++)
{
history[i] = new char[strlen(ac.history[i]) + 1];
strcpy(history[i], ac.history[i]);
}
history_count = ac.history_count;
history_size = ac.history_size;
}
account::~account()
{
delete[] history;
}
void account::set_name(char* new_name)
{
assert(strlen(new_name) <= MAX_NAME_SIZE);
strcpy(name, new_name);
}
void account::set_account_number(size_t new_acnum) {ac_number = new_acnum;}
void account::set_balance(double new_balance) {balance = new_balance;}
void account::add_history(char* new_history)
{
assert(history_count < history_size);
history[history_count] = new char[strlen(new_history) + 1];
strcpy(history[history_count], new_history);
history_count++;
}
char* account::get_name() const
{
char* blah = new char[MAX_NAME_SIZE + 1];
strcpy(blah, name);
return blah;
}
size_t account::get_account_number ( ) const {return ac_number;}
double account::get_balance( ) const{return balance;}
size_t account::get_max_history_size( ) const {return history_size;}
size_t account::get_current_history_size ( ) const {return history_count;}
account::string* account::get_history() const
{
string* blah = new string[history_size];
for(size_t i = 0; i < history_count; i++)
{
blah[i] = new char[strlen(history[i]) + 1];
strcpy(blah[i], history[i]);
}
return blah;
}
std::ostream& operator<< (std::ostream& outs, const account& target)
{
outs << "Name: " << target.name << "\n"
<< "Account Number: " << target.ac_number << "\n"
<< "Balance: " << "$" << target.balance << "\n"
<< "History: ";
for(size_t i = 0; i < target.history_count; i++)
{
outs << target.history[i] << "\n";
}
outs << "Current History Size: " << target.history_count << "\n";
outs << "Max History Size: " << target.history_size << "\n";
return outs;
}
bankledger.h
class bank_ledger
{
public:
static const int MAX_ACC_SIZE = 15;
bank_ledger(int mo, int mc);
bank_ledger(const bank_ledger& copyledger);
~bank_ledger();
void create_account(char* i_name, size_t i_acnum, size_t i_hsize);
void close_account(double accnum);
double balance_of(double accnum);
void deposit(double accnum, double money);
void withdraw(double accnum, double money);
void transfer(double accnum1, double accnum2, double money);
void print_account_history(double accnum);
void print_account_details(double accnum);
void print_current_details();
void print_closed_details();
account* lookup(double accnum);
private:
account** open;
account** closed;
int max_open;
int max_closed;
int num_open;
int num_closed;
};
bankledger.cxx:
#include <cstdlib>
#include <iostream>
#include <cassert>
#include "account.h"
#include "bank_ledger.h"
using namespace std;
bank_ledger::bank_ledger(int mo = 30, int mc = 30)
{
max_open = mo;
max_closed = mc;
open = new account*[max_open];
closed = new account*[max_closed];
num_open = 0;
num_closed = 0;
}
bank_ledger::bank_ledger(const bank_ledger& copyledger)
{
int i;
max_open = copyledger.max_open;
max_closed = copyledger.max_closed;
num_open = copyledger.num_open;
num_closed = copyledger.num_closed;
open = new account*[num_open];
closed = new account*[num_closed];
for(i = 0; i < max_open; i++)
{
if (i < num_open)
open[i] = copyledger.open[i];
}
for(i = 0; i < max_closed; i++)
{
if (i < num_closed)
closed[i] = copyledger.closed[i];
}
}
bank_ledger::~bank_ledger()
{
for(int i = 0; i < num_open; i++)
{
delete open[i];
}
for(int i = 0; i < num_closed; i++)
{
delete closed[i];
}
delete[] open;
delete[] closed;
}
account* bank_ledger::lookup(double accnum)
{
for(int i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == accnum)
{
return *open + i;
}
if(closed[i]->get_account_number() == accnum)
{
return *closed + i;
}
}
}
void bank_ledger::create_account(char* i_name, size_t i_acnum, size_t i_hsize)
{
assert(num_open < max_open);
open[num_open] = new account(i_name, i_acnum, i_hsize);
open[num_open]->add_history("Account Created");
num_open++;
}
void bank_ledger::close_account(double accnum)
{
int i;
double temp = -1;
cout << *(open[0]) << endl << "Good Idea" << endl;
account* acc = lookup(accnum);
for(i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == acc->get_account_number())
{
temp = i;
closed[num_closed] = open[i];
for(i = temp; i < num_open - 1; i++)
{
open[i] = open[i+1];
}
closed[num_closed]->add_history("Account Closed");
num_open--;
num_closed++;
return;
}
}
}
double bank_ledger::balance_of(double accnum)
{
return lookup(accnum)->get_balance();
}
void bank_ledger::deposit(double accnum, double money)
{
account* acc = lookup(accnum);
acc->set_balance(acc->get_balance() + money);
acc->add_history("Deposited $");
}
void bank_ledger::withdraw(double accnum, double money)
{
account* acc = lookup(accnum);
acc->set_balance(acc->get_balance() - money);
acc->add_history("Withdrew $");
}
void bank_ledger::transfer(double accnum1, double accnum2, double money)
{
withdraw(accnum2, money);
deposit(accnum1, money);
}
void bank_ledger::print_account_history(double accnum)
{
account* acc = lookup(accnum);
account::string *hist = acc->get_history();
cout << "History of " << acc->get_name() << "'s account: " << endl;
for (int i = 0; i < acc->get_current_history_size(); i++) cout << hist[i] << endl;
}
void bank_ledger::print_account_details(double accnum)
{
account* acc = lookup(accnum);
cout << *acc;
cout << "\n";
}
void bank_ledger::print_current_details()
{
for(int i = 0; i < num_open; i++)
{
cout << *open[i] << "\n";
}
}
void bank_ledger::print_closed_details()
{
for(int i = 0; i < num_closed; i++)
{
cout << *closed[i] << "\n";
}
cout << "\n";
}
sample_test_input2.cxx
#include <cstdlib>
#include <iostream>
#include "account.h"
#include "bank_ledger.h"
using namespace std;
int main()
{
bank_ledger bl(30, 30);
bl.create_account("name1", 1, 30);
bl.create_account("name2", 2, 30);
bl.create_account("name3", 3, 30);
bl.create_account("name4", 4, 30);
bl.print_current_details();
bl.close_account(2);
return 0;
}
Valgrind and GDB both say that *(open[i]) is uninitialized. Here's the exact output from Valgrind:
==7082== Use of uninitialised value of size 8
==7082== at 0x1000018C6: account::get_account_number() const (account.cxx:74)
==7082== by 0x10000246B: bank_ledger::lookup(double) (bank_ledger.cxx:85)
==7082== by 0x1000027D0: bank_ledger::close_account(double) (bank_ledger.cxx:105)
==7082== by 0x100003117: main (sample_test_input2.cxx:17)
==7082==
==7082== Invalid read of size 8
==7082== at 0x1000018C6: account::get_account_number() const (account.cxx:74)
==7082== by 0x10000246B: bank_ledger::lookup(double) (bank_ledger.cxx:85)
==7082== by 0x1000027D0: bank_ledger::close_account(double) (bank_ledger.cxx:105)
==7082== by 0x100003117: main (sample_test_input2.cxx:17)
==7082== Address 0x10 is not stack'd, malloc'd or (recently) free'd
It goes from main to bankledgrer::close_account, to bankledger::lookup and then it crashes at if(open[i]->get_account_number() == accnum)
If I stick cout << *(open[i]) right before that line, it prints it out fine.
I'm afraid I'm at a loss. Any help would be appreciated. If you want me to include the header files, or clarify anything please let me know.
PS. Also, I know this code is very C, but that's the way my professor wants it, even though it's a C++ class. Go figure. :\
In this method:
account* bank_ledger::lookup(double accnum)
{
for(int i = 0; i < num_open; i++)
{
if(open[i]->get_account_number() == accnum)
{
return *open + i;
}
if(closed[i]->get_account_number() == accnum)
{
return *closed + i;
}
}
}
You are assuming there are at least the same amount of closed accounts than the amount of open accounts. You should iterate through the open and closed arrays in different loops, since you're trying to access closed[i], being i = 1,2,3..., and closed does not contain any valid pointers(just a bunch of NULL pointers). This should work(unless i'm missing something else):
account* bank_ledger::lookup(double accnum) {
for(int i = 0; i < num_open; i++) {
if(open[i]->get_account_number() == accnum)
return open[i];
}
for(int i = 0; i < num_closed; i++) {
if(closed[i]->get_account_number() == accnum)
return closed[i];
}
return 0;
}