I'm trying to concatenate two arrays and at the end concatenate int, for example: result = arg + arg + 2;
I'm getting "read access violation" at + operator overloading.
I wrote the error and warning in comments below.
My code:
Main:
#include <iostream>
#include <string>
#include "CTable.h"
int main() {
CTable c_tab1, c_tab0;
c_tab0.SetNewSize(3);
c_tab1.SetNewSize(2);
c_tab0.SetValueAt(0, 22);
c_tab0.SetValueAt(1, 23);
c_tab0.SetValueAt(2, 24);
c_tab0.Print();
c_tab1.SetValueAt(0, 31);
c_tab1.SetValueAt(1, 32);
c_tab1.Print();
CTable c_tab3 = (c_tab0 + c_tab1 + 111);
c_tab3.Print();
return 0;
}
Class CTable:
#include <iostream>
#include <string>
using namespace std;
class CTable {
public:
CTable();
CTable(string sName, int iTableLen);
CTable(const CTable& pcOther);
CTable* pcClone();
~CTable();
void ShowName();
void ShowSize();
void SetName(string sName);
bool SetNewSize(int iTableLen);
void SetValueAt(int iOffset, int iNewVal);
void Print();
CTable& operator+(const CTable& pcNewTable);
CTable operator+(int iNewVal) const;
CTable& operator=(const CTable& pcNewVal) {
if (this != &pcNewVal) {
for (int i = 0; i < i_size; i++) {
this->piTable[i] = pcNewVal.piTable[i];
}
}
return *this;
}
private:
string s_name;
int i_size;
int* piTable;
const int SIZE = 10;
const string NAME = "Name";
};
#include <iostream>
#include <string>
#include "CTable.h"
#include <algorithm>
using namespace std;
CTable::CTable() {
s_name = NAME;
cout << "bezp: " << s_name << endl;
piTable = new int[SIZE];
i_size = SIZE;
}
CTable::CTable(string sName, int iTableLen) {
s_name = sName;
cout << "parametr: " << sName << endl;
piTable = new int[iTableLen];
i_size = iTableLen;
}
CTable::CTable(const CTable& pcOther) {
s_name = pcOther.s_name + "copied";
piTable = new int[pcOther.i_size];
i_size = pcOther.i_size;
for (int i = 0; i < pcOther.i_size; i++) {
piTable[i] = pcOther.piTable[i];
}
}
CTable::~CTable() {
delete[] piTable;
}
void CTable::SetName(string sName) {
s_name = sName;
}
bool CTable::SetNewSize(int iTableLen) {
if (iTableLen <= 0) {
cout << "Length has to be greater than 0" << endl;
return false;
}
int* pi_newTable = new int[iTableLen];
for (int i = 0; i < iTableLen; i++) {
pi_newTable[i] = piTable[i];
}
delete this->piTable;
this->i_size = iTableLen;
this->piTable = pi_newTable;
return true;
}
CTable* CTable::pcClone() {
CTable* ct = new CTable(s_name, i_size);
return ct;
}
void CTable::ShowName() {
cout << "Name: " << s_name << endl;
}
void CTable::ShowSize() {
cout << "Size: " << i_size << endl;
}
void CTable::SetValueAt(int iOffset, int iNewVal) {
if (iOffset >= this->i_size) {
return;
}
piTable[iOffset] = iNewVal;
}
void CTable::Print() {
for (int i = 0; i < i_size; i++) {
cout << piTable[i] << " ";
}
cout << endl;
}
CTable& CTable::operator+(const CTable& pcNewTable) {
CTable result("new_int", this->i_size);
result.i_size = (i_size + pcNewTable.i_size);
result.piTable = new int[i_size + pcNewTable.i_size];
for (int i = 0; i < i_size; i++) {
result.piTable[i] = piTable[i];
}
for (int i = 0; i < (pcNewTable.i_size); i++) {
result.piTable[i+i_size] = pcNewTable.piTable[i];
}
return result; //Warning C4172 returning address of local variable or temporary: result
}
CTable CTable::operator+(int iNewVal) const {
CTable result("new_int", this->i_size);
result.i_size = (i_size + 1);
result.piTable = new int[i_size + 1];
for (int i = 0; i < i_size; i++) {
result.piTable[i] = piTable[i]; //Exception thrown: read access violation. **this->piTable** was 0x1110122.
}
result.piTable[i_size + 1] = iNewVal;
return result;
}
What should I correct? I'm not sure about assigment operator overload, is it okay?
The member function SetNewSize has undefined behavior. In this loop
int* pi_newTable = new int[iTableLen];
for (int i = 0; i < iTableLen; i++) {
pi_newTable[i] = piTable[i];
}
it 1) uses uninitialized values because the array was not initialized and 2) iTableLen can be gretaer than the current value of i_size. You should at least zero initialize the array in constructors.
The copy assignment operator aslo has undefined behabior because the number of elements of the array of the object pcNewVal can be less than the number of elements of the array in the assigned object.
The first overloaded operator + also have undefined behavior. For starters as the warning says the operator returns reference to the local object result that will not be alive after exiting the operator. Secondly, there is a memory leak necause the array of the object is allocated anew and the previuous allocated memory in the constructor is not freed.
CTable result("new_int", this->i_size);
result.i_size = (i_size + pcNewTable.i_size);
result.piTable = new int[i_size + pcNewTable.i_size];
//...
The second overloaded operator + also has undefined behavior. As in the previous operator there is a memory leak.
In this statement
result.piTable[i_size + 1] = iNewVal;
there is an access memory outside the allocated array. There should be
result.piTable[i_size] = iNewVal;
Related
Honestly, I have no idea why CTable cannot convert to CTable? I'm trying to make overload operator + which returns concatenated two tables.
Error C2440 'initializing': cannot convert from 'CTable' to 'CTable'
Second error: Error (active) E0334 class "CTable" has no suitable copy constructor
#include <iostream>
#include <string>
#include "CTable.h"
int main() {
CTable c_tab_1, c_tab_0;
c_tab_0.vSetValueAt(0, 1);
c_tab_0.vPrint();
c_tab_0.bSetNewSize(4);
c_tab_0.vPrint();
c_tab_1.bSetNewSize(4);
c_tab_0.vSetValueAt(0, 1);
c_tab_0.vSetValueAt(1, 2);
c_tab_0.vSetValueAt(2, 3);
c_tab_0.vSetValueAt(3, 4);
c_tab_0.vPrint();
c_tab_1.vSetValueAt(0, 2);
c_tab_1.vSetValueAt(1, 3);
c_tab_1.vSetValueAt(2, 4);
c_tab_1.vSetValueAt(3, 5);
c_tab_1.vPrint();
c_tab_1.vSetValueAt(2, 123);
c_tab_0.vPrint();
c_tab_1.vPrint();
CTable c_tab_3 = c_tab_0 + c_tab_1; //Error C2440! <-----------------------
c_tab_3.vPrint();
return 0;
}
#include <iostream>
#include <string>
using namespace std;
class CTable {
public:
CTable();
CTable(CTable& pcOther);
CTable* pcClone();
~CTable();
bool bSetNewSize(int iTableLen);
void vSetValueAt(int iOffset, int iNewVal);
void vPrint();
CTable operator+(const CTable& pcNewTable);
private:
string s_name;
int i_size;
int* piTable;
const int SIZE = 10;
const string NAME = "Name";
};
#include <iostream>
#include <string>
#include "CTable.h"
using namespace std;
CTable::CTable() {
s_name = NAME;
cout << "bezp: " << s_name << endl;
piTable = new int[SIZE];
i_size = SIZE;
}
///
CTable::CTable(CTable& pcOther) {
s_name = pcOther.s_name + "_copy";
piTable = new int[pcOther.i_size];
i_size = pcOther.i_size;
for (int i = 0; i < pcOther.i_size; i++) {
piTable[i] = pcOther.piTable[i];
}
cout << "kopiuj: " << s_name << endl;
}
CTable::~CTable() {
delete[] piTable;
cout << "usuwam " << s_name << endl;
}
////
bool CTable::bSetNewSize(int iTableLen) {
if (iTableLen <= 0) {
return false;
}
int* pi_newTable = new int[iTableLen];
memcpy(pi_newTable, piTable, iTableLen);
delete this->piTable;
this->i_size = iTableLen;
this->piTable = pi_newTable;
return true;
}
///
void CTable::vSetValueAt(int iOffset, int iNewVal) {
if (iOffset >= this->i_size) {
return;
}
piTable[iOffset] = iNewVal;
}
void CTable::vPrint() {
for (int i = 0; i < i_size; i++) {
cout << piTable[i] << " ";
}
cout << endl;
}
CTable CTable::operator+(const CTable& pcNewTable) {
CTable result;
int greater_len = i_size < pcNewTable.i_size;
int smaller_len = i_size > pcNewTable.i_size;
int* greater_table = i_size > pcNewTable.i_size ? piTable : pcNewTable.piTable;
int* smaller_table = i_size <= pcNewTable.i_size ? piTable : pcNewTable.piTable;
result.i_size = greater_len;
result.piTable = new int[greater_len];
memcpy(result.piTable, greater_table, greater_len * sizeof(int));
for (int i = 0; i < smaller_len; i++) {
result.piTable[i] += smaller_table[i];
}
return result;
}
What should I correct?
Try to define
CTable(const CTable& pcOther)
{
.......
}
I made a dynamic array with template. The problem is that when I don't keep there pointers (for example: Tab<string> da;) my destructor doesn't have to clear it and throws error caused by delete arr[i];. My question is if I can put some if condition(in which I would put clear() method) which would tell me if my array keeps pointers. In the simplest way I can use clear() in main when I keeps there pointers, but my teacher wants me to make it like I wrote above.
I tried using is_pointer, but it doesn't work or I use it wrong.
Any suggestions?
#ifndef TABLICA_H
#define TABLICA_H
#include <iostream>
#include <type_traits>
using namespace std;
template<class T>
class Tab
{
public:
int size = 0;
int max_size = 1;
T* arr;
bool isDynamic = false;
Tab()
{
arr = new T[max_size];
}
~Tab()
{
clear();
delete[] arr;
}
void check_size()
{
if (size == max_size)
{
max_size = max_size * 2;
T* arr2 = new T[max_size];
for (int i = 0; i < size; i++)
{
arr2[i] = arr[i];
}
delete[] arr;
arr = arr2;
}
}
void push_back(const T& value)
{
check_size();
arr[size] = value;
size++;
}
T return_by_index(int index)
{
if (index<0 || index > size)
{
return NULL;
}
return arr[index];
}
bool replace(int index, const T& value)
{
if (index<0 || index > size)
{
return false;
}
arr[index] = value;
return true;
}
void print(int number)
{
cout << "Rozmiar obecny: " << size << endl;
cout << "Rozmiar maksymalny: " << max_size << endl;
cout << "Adres tablicy: " << arr << endl;
cout << "Kilka poczatkowych elementow tablicy " << "(" << number << ")" << endl;
for (int i = 0; i < number; i++)
{
cout << *arr[i] << endl;
}
}
void clear()
{
for (int i = 0; i < size; i++)
{
delete arr[i];
}
}
};
#endif
//Source:
#include <iostream>
struct object
{
int field1;
char field2;
object()
{
field1 = rand() % 10001;
field2 = rand() % 26 + 'A';
}
};
ostream& operator<<(ostream& out, const object& o)
{
return out << o.field1 << " " << o.field2;
}
int main()
{
Tab < object* >* da = new Tab < object* >();
delete da;
system("PAUSE");
return 0;
I'm currently building a library In C++. I have met this problem few days ago and I'm unable to fix it. I have shorten the code so it can be seen easier.
Below is my code:
class String
{
private:
mutable char* v;
mutable int l = 0;
public:
String()
{
l++;
v = new char[1];
*v = '\0';
}
String(const char* value)
{
int length = 0;
while (value[length])
length++;
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
}
String(const String& value)
{
int length = value.len();
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
}
int len() const
{
return l - 1;
}
char* val() const
{
return v;
}
char* operator=(const char* value) const
{
delete[] v;
int length = 0;
while (value[length])
length++;
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
return v;
}
char* operator=(const String& value) const
{
delete[] v;
int length = value.len();
l = length + 1;
v = new char[l];
for (int i = 0; i < length; i++)
v[i] = value[i];
v[l - 1] = '\0';
return v;
}
char operator[](const int& index) const
{
return v[index];
}
};
class StringArray
{
private:
union ArrayDef
{
public:
mutable String stringV;
mutable int intV;
ArrayDef()
{
}
ArrayDef(const String& value)
: stringV(value)
{
}
ArrayDef(const int& value)
: intV(value)
{
}
ArrayDef(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
}
String operator=(const String& value) const
{
stringV = value;
return stringV;
}
int operator=(const int& value) const
{
intV = value;
return intV;
}
ArrayDef operator=(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
return *this;
}
};
mutable ArrayDef* arrdef;
mutable int arrLen = 0;
public:
StringArray()
{
}
void add(const ArrayDef& value) const
{
ArrayDef temp[arrLen + 1];
for (int i = 0; i < arrLen; i++)
temp[i] = arrdef[i];
temp[arrLen] = value;
arrLen++;
delete[] arrdef;
arrdef = new ArrayDef[arrLen];
for (int i = 0; i < arrLen; i++)
arrdef[i] = temp[i];
}
int len() const
{
return arrLen;
}
ArrayDef val(const int& index) const
{
return arrdef[index];
}
};
And my driver code:
#include <iostream>
int main()
{
StringArray arr;
arr.add(String("Hello"));
arr.add(String("World"));
std::cout << "Length of the array: " << arr.len() << std::endl;
int indexOfString = 1;
int indexOfCharacter = 2;
char s = arr.val(indexOfString).stringV[indexOfCharacter];
std::cout << "arr[" << indexOfString << "][" << indexOfCharacter << "]: " << s << std::endl;
}
I have created two class, that is, String and StringArray class.
For String class, I need to always add a null character after the char pointer array for safety issue.
For StringArray class, I uses union because it's actually an array for multiple types.
It can be successfully compiled but it output some random character and it is different every time I run it.
Any answers will be appreciated, and please tell me why and how it don't works. Thank you.
From,
HaiQin.
This code is just a collection of antipatters that makes it difficult to study. What is the reason of making the internal data mutable? Why do you need to play with length and l where sometimes it is the length of the string, sometimes it is the size of array? The operator operator= returns char* which is a bad practice. Using const int& index as a parameter is a strange choice. You allocate arrays multiple times but you have no destructor that frees the memory.
Here your assignment operator returns a value, not reference!
ArrayDef operator=(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
return *this;
}
Next comes even more dangerous practice:
// Recollect that this is a union
ArrayDef(const ArrayDef& value)
{
intV = value.intV;
stringV = value.stringV;
}
You are assigning both fields of the union at the same time! Did you mean struct?
Try to fix that. Start with changing union to structure.
One of the things that certainly will not work is the ArrayDef copy constructor and operator=(const ArrayDef & value). This is because you may only use the active value in the union, not both at the same time. This is usually solved by using a tagged union. Is there a reason you cannot use the Standard Template Library?
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> arr;
arr.push_back(std::string("Hello"));
arr.push_back(std::string("World"));
std::cout << "Length of the array: " << arr.size() << std::endl;
constexpr int indexOfString = 1; // second string - starting from 0!
constexpr int indexOfCharacter = 2; // third character
char s = arr.at(indexOfString).c_str()[indexOfCharacter]; // using interfaces closest to the original
std::cout << "arr[" << indexOfString << "][" << indexOfCharacter << "]: " << s << std::endl;
}
I am fairly new to dynamic memory allocation and am having trouble. I'm thinking the problem is within my allocation function but I could be wrong. Here is the MyString.cpp file.
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include "MyString.h"
using namespace std;
MyString::MyString()
{
m_size = 0;
buffer_allocate(0);
}
MyString::MyString(const char * str)
{
m_size = strlen(str);
buffer_allocate(m_size);
for(int i = 0; i < m_size; i++)
{
m_buffer[i] = str[i];
}
}
MyString::MyString(const MyString & other_myStr)
{
m_size = other_myStr.size();
buffer_allocate(other_myStr.size());
for(int i = 0; i < other_myStr.size(); i++)
{
m_buffer[i] = other_myStr.c_str()[i];
}
}
void MyString::buffer_deallocate()
{
delete[] m_buffer;
m_size = 0;
}
void MyString::buffer_allocate(size_t size)
{
try
{
m_buffer = new char[size];
}
catch(bad_alloc& ex)
{
delete[] m_buffer;
}
}
MyString::~MyString()
{
buffer_deallocate();
}
size_t MyString::size() const
{
return m_size;
}
size_t MyString::length() const
{
return m_size - 1;
}
const char* MyString::c_str() const
{
char * arr = (char*) malloc(m_size + 1);
int i;
for(i = 0; i < m_size; i++)
{
arr[i] = m_buffer[i];
}
arr[i] = '\0';
return arr;
}
bool MyString::operator== (const MyString & other_myStr) const
{
for(int i = 0; (i < m_size) && (i < other_myStr.size()); i++)
{
if(m_buffer[i] != other_myStr.c_str()[i])
{
return false;
}
}
if(m_size != other_myStr.size())
{
return false;
}
return true;
}
MyString & MyString::operator= (const MyString & other_myStr)
{
buffer_deallocate();
buffer_allocate(other_myStr.size());
for(int i = 0; i < other_myStr.size(); i++)
{
m_buffer[i] = other_myStr.c_str()[i];
}
return *this;
}
MyString MyString::operator+ (const MyString & other_myStr) const
{
int length = this->size() + other_myStr.size();
char * temp = (char*)malloc(length);
int j = 0;
for(int i = 0; i < length; i++)
{
if(i < this->size())
{
temp[i] = m_buffer[i];
}
else
{
temp[i] = other_myStr.c_str()[j];
j++;
}
}
MyString rhs = MyString(temp);
return rhs;
}
char & MyString::operator[] (size_t index)
{
return m_buffer[index];
}
const char & MyString::operator[] (size_t index) const
{
return m_buffer[index];
}
std::ostream & operator<<(std::ostream & os, const MyString & myStr)
{
for(int i = 0; i < myStr.size(); i++)
{
os << myStr[i];
}
os << endl;
}
Like I said, the segmentation fault is happening after the entire program is being executed so my guess is that there is some memory leak issue. I appreciate the help in advance.
And here is the main function:
#include <iostream>
#include <string.h>
#include <stdlib.h>
#include "MyString.h"
using namespace std;
int main(void)
{
MyString dft;
if(dft.size() == 0)
{
cout << "Successful Default c-tor" << endl;
}
MyString param("Successful Parameter c-tor");
MyString copy(dft);
cout << param;
MyString ms_size_length("Size and length test:");
cout << ms_size_length;
cout << "Size of MyString: " << ms_size_length.size() << endl;
cout << "Length of MyString: " << ms_size_length.length() << endl;
MyString ms_toCstring("C-String equivalent successfully obtained!");
cout << ms_toCstring.c_str() << endl;
MyString ms_same1("The same"), ms_same2("The same");
if (ms_same1==ms_same2)
{
cout << "Same success" << endl;
}
MyString ms_different("The same (NOT)");
if (!(ms_same1==ms_different))
{
cout << "Different success" << endl;
}
MyString ms_assign("Before assignment");
ms_assign = MyString("After performing assignment");
MyString ms_append1("The first part");
MyString ms_append2(" and the second");
MyString ms_concat = ms_append1 + ms_append2;
cout << ms_concat;
MyString ms_access("Access successful (NOT)");
ms_access[17] = 0;
cout << ms_access;
}
One problem that I noticed is:
m_size = strlen(str);
buffer_allocate(m_size);
That allocates one less than the number of characters you need. As a consequence, you end up not copying the terminating null character to the object's m_buffer.
I suggest changing the constructor to:
MyString::MyString(const char * str)
{
m_size = strlen(str)+1;
buffer_allocate(m_size);
strcpy(m_buffer, str);
}
PS I did not look for other problems in your code. There may be more, or none.
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;
}