changes my vector to an array and have to use pointers - what does the errormessage say ? C++

for my homework i am supposed to change the vector from the registry class to an array and define it in the BankVector class. I did so andthe errormessage in the compiler is really... confusing. Im new with pointers soI am really confused about this. What is the mistake ? or are the mistakes haha SEND HELP PLEASE

#include <iostream>
#include <string>
#include <array>
#include <fstream>
using namespace std; 

class Bankaccount{

  private: 
    string accName; 
    double balance;  
    char type;

  public:
    Bankaccount(); 
    Bankaccount(string name, char credit);
    string getName(); 
    double getBalance(); 
    void setBalance(double transferMoney); 
    char getCredit(); 

}; 

Bankaccount::Bankaccount(){
  accName = " ";
  balance = 0; 
  type = 'n'; 
}

Bankaccount::Bankaccount(string name, char credit){
  accName = name; 
  balance = 0; 
  type = credit;
}

string Bankaccount::getName(){
  return accName; 
}

double Bankaccount::getBalance(){
  return balance; 
}

void Bankaccount::setBalance(double transferMoney){
  balance += transferMoney; 
}

char Bankaccount::getCredit(){
  return type;
}



class BankVector {

  private:
        Bankaccount* entries;
        unsigned int usedCapacity;      
        unsigned int maxCapacity;

    public:
        BankVector();
        ~BankVector();
        unsigned int size() const;
        Bankaccount& at(unsigned int index) const;
        void push_back(Bankaccount a);
        void erase(unsigned int index);

        class IndexError:public exception{

          const char* what() const throw(){ 
            return "error: Index out of range";
          }
    };

};

BankVector::BankVector(){
    entries = new Bankaccount;
    usedCapacity = 0; 
  maxCapacity = 0; 
}

BankVector::~BankVector(){
     delete[] entries; 
}

unsigned int BankVector::size() const{
    return usedCapacity;
}

Bankaccount& BankVector::at(unsigned int index) const{
  if(index > usedCapacity){
    throw IndexError();
  } else {
    return entries[index];
  }
}

void BankVector::push_back(Bankaccount a){
    if(usedCapacity == maxCapacity){
      Bankaccount* tmp = new Bankaccount[maxCapacity + 1];
    for(int i = 0; i < maxCapacity; i++){
      tmp[i] = entries[i];
    }
    delete entries; 
    for(int i = 0; i < maxCapacity; i++){
     entries[i] = tmp[i];
    }
    delete tmp; 
    entries[maxCapacity] = a; 
    } else {
      entries[usedCapacity + 1] = a;  
    }
}

void BankVector::erase(unsigned int index){
    if(index >= 0 && index < usedCapacity){
        for(int i = index; i < usedCapacity - 1; i++){
            entries[i] = entries[i + 1]; 
        }
    usedCapacity = usedCapacity - 1; 
    } else{
      throw IndexError(); 
    }
}


class Registry{
  public: 
    void addAcc(string name, char isCredit); 
    void removeAcc(string name); 
    void transaction(string name, double transMoney); 
    bool checkDupl(string name); 
    double checkBalance(string name);
    char checkCreditType(string name); 
    void print();

  private: 
    BankVector accountlist; 
    int i; 
    double balance = 0;
    char type; 

}; 

void Registry:: addAcc(string name, char isCredit){
  Bankaccount newAcc(name, isCredit); 
  accountlist.push_back(newAcc); 
}

void Registry::removeAcc(string name){
  for(i = 0; i < accountlist.size(); i++){
    if(accountlist.at(i).getName() == name){
      accountlist.erase(i); 
    }
  }
}

void Registry::transaction(string name, double transMoney){
  for(i = 0; i < accountlist.size(); i++){
    if(accountlist.at(i).getName() == name){
      accountlist.at(i).setBalance(transMoney); 
    }
  }
}

bool Registry::checkDupl(string name){
  for(i = 0; i < accountlist.size(); i++){
    if(accountlist.at(i).getName() == name){
      return true; 
    }
  }
  return false; 
}

double Registry::checkBalance(string name){
    for(i = 0; i < accountlist.size(); i++){
      if(accountlist.at(i).getName() == name){
        balance = accountlist.at(i).getBalance();
      }
    }
  return balance;
}

char Registry::checkCreditType(string name){
  for(i = 0; i < accountlist.size(); i++){
      if(accountlist.at(i).getName() == name){
        type = accountlist.at(i).getCredit();
      }
    }
  return type;
}

void Registry::print(){
  for(i = 0; i < accountlist.size(); i++){
    if(accountlist.at(i).getBalance() >= 0){
      cout << accountlist.at(i).getName() << " owns " << accountlist.at(i).getBalance() << " euros" << endl; 
    } else if(accountlist.at(i).getBalance() < 0){
      cout << accountlist.at(i).getName() << " owes " << accountlist.at(i).getBalance() << " euros" << endl; 
    }
  }
}


int main(){
  Registry account;
  ifstream inFS; 
  string file, command, fileName;
  char creditType; 
  double moneyVal = 0; 
  int i = 0; 

  cout << "Enter the name of the records file: ";
  cin >> file; 

  inFS.open(file); 
  if(!inFS.is_open()){
    cout << "Could not open file " << file;
    return 0;
  }

  while(!inFS.eof()){
    i++;

    try{

      inFS >> command >> fileName; 

      if(command == "c"){
        inFS >> creditType;
        if(account.checkDupl(fileName) == true){
          throw runtime_error(": account already exists"); 
        } else {
          account.addAcc(fileName, creditType); 
        }
      }

      if(command == "r"){
        if(account.checkDupl(fileName) == false){
          throw runtime_error(": account does not exist");
        } else if(account.checkDupl(fileName) == true){
          if(account.checkBalance(fileName) >= 0){
            account.removeAcc(fileName);
          } else if(account.checkBalance(fileName) < 0){
            throw runtime_error(": account holds negative balance"); 
          }
        }
      }

      if(command == "t"){
        inFS >> moneyVal;
        if(account.checkDupl(fileName) == true){
          if((account.checkBalance(fileName) + moneyVal) >= 0){
            account.transaction(fileName, moneyVal);  
          } else if((account.checkBalance(fileName) + moneyVal) < 0){
            if(account.checkCreditType(fileName) == 'y'){
              account.transaction(fileName, moneyVal);  
            } else if(account.checkCreditType(fileName) == 'n'){
              throw runtime_error(": account cannot hold negative balance"); 
            }
          }
        }else{
          throw runtime_error(": account does not exist");
        }
      }  
    }

    catch(runtime_error& excpt){
      cout << "error on line " << to_string(i) << excpt.what() << endl; 
    }
  }

  cout<< endl; 
  account.print();

  return 0; 
}

Thas what the compiler prints:

What is does that bug say: Enter the name of the records file:  records1.bank 

*** Error in `./main': free(): invalid pointer: 0x0000000001a466c8 *** ======= Backtrace: ========= /lib/x86_64-linux-gnu/libc.so.6(+0x70bfb)[0x7f1e40109bfb] /lib/x86_64-linux-gnu/libc.so.6(+0x76fc6)[0x7f1e4010ffc6] /lib/x86_64-linux-gnu/libc.so.6(+0x7780e)[0x7f1e4011080e] ./main[0x402466] ./main[0x402685] ./main[0x402f28] /lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf1)[0x7f1e400b92e1] ./main[0x401f8a] ======= Memory map: ======== 00400000-00405000 r-xp 00000000 08:01 11032506                           /home/runner/main 00604000-00605000 r--p 00004000 08:01 11032506                           /home/runner/main 00605000-00606000 rw-p 00005000 08:01 11032506                           /home/runner/main 01a32000-01a64000 rw-p 00000000 00:00 0                                  [heap] 7f1e3c000000-7f1e3c021000 rw-p 00000000 00:00 0  7f1e3c021000-7f1e40000000 ---p 00000000 00:00 0  7f1e40099000-7f1e4022e000 r-xp 00000000 08:01 2562779                    /lib/x86_64-linux-gnu/libc-2.24.so 7f1e4022e000-7f1e4042e000 ---p 00195000 08:01 2562779                    /lib/x86_64-linux-gnu/libc-2.24.so 7f1e4042e000-7f1e40432000 r--p 00195000 08:01 2562779                    /lib/x86_64-linux-gnu/libc-2.24.so 7f1e40432000-7f1e40434000 rw-p 00199000 08:01 2562779                    /lib/x86_64-linux-gnu/libc-2.24.so 7f1e40434000-7f1e40438000 rw-p 00000000 00:00 0  7f1e40438000-7f1e40450000 r-xp 00000000 08:01 2562842                    /lib/x86_64-linux-gnu/libpthread-2.24.so 7f1e40450000-7f1e4064f000 ---p 00018000 08:01 2562842                    /lib/x86_64-linux-gnu/libpthread-2.24.so 7f1e4064f000-7f1e40650000 r--p 00017000 08:01 2562842                    /lib/x86_64-linux-gnu/libpthread-2.24.so 7f1e40650000-7f1e40651000 rw-p 00018000 08:01 2562842                    /lib/x86_64-linux-gnu/libpthread-2.24.so 7f1e40651000-7f1e40655000 rw-p 00000000 00:00 0  7f1e40655000-7f1e4066c000 r-xp 00000000 08:01 2574182                    /usr/local/lib64/libgcc_s.so.1 7f1e4066c000-7f1e4086b000 ---p 00017000 08:01 2574182                    /usr/local/lib64/libgcc_s.so.1 7f1e4086b000-7f1e4086c000 r--p 00016000 08:01 2574182                    /usr/local/lib64/libgcc_s.so.1 7f1e4086c000-7f1e4086d000 rw-p 00017000 08:01 2574182                    /usr/local/lib64/libgcc_s.so.1 7f1e4086d000-7f1e40970000 r-xp 00000000 08:01 2562808                    /lib/x86_64-linux-gnu/libm-2.24.so 7f1e40970000-7f1e40b6f000 ---p 00103000 08:01 2562808                    /lib/x86_64-linux-gnu/libm-2.24.so 7f1e40b6f000-7f1e40b70000 r--p 00102000 08:01 2562808                    /lib/x86_64-linux-gnu/libm-2.24.so 7f1e40b70000-7f1e40b71000 rw-p 00103000 08:01 2562808                    /lib/x86_64-linux-gnu/libm-2.24.so 7f1e40b71000-7f1e40ce4000 r-xp 00000000 08:01 2574242                    /usr/local/lib64/libstdc++.so.6.0.25 7f1e40ce4000-7f1e40ee4000 ---p 00173000 08:01 2574242                    /usr/local/lib64/libstdc++.so.6.0.25 7f1e40ee4000-7f1e40eee000 r--p 00173000 08:01 2574242                    /usr/local/lib64/libstdc++.so.6.0.25 7f1e40eee000-7f1e40ef0000 rw-p 0017d000 08:01 2574242                    /usr/local/lib64/libstdc++.so.6.0.25 7f1e40ef0000-7f1e40ef3000 rw-p 00000000 00:00 0  7f1e40ef3000-7f1e40f16000 r-xp 00000000 08:01 2562761                    /lib/x86_64-linux-gnu/ld-2.24.so 7f1e41104000-7f1e41109000 rw-p 00000000 00:00 0  7f1e41112000-7f1e41116000 rw-p 00000000 00:00 0  7f1e41116000-7f1e41117000 r--p 00023000 08:01 2562761                    /lib/x86_64-linux-gnu/ld-2.24.so 7f1e41117000-7f1e41118000 rw-p 00024000 08:01 2562761                    /lib/x86_64-linux-gnu/ld-2.24.so 7f1e41118000-7f1e41119000 rw-p 00000000 00:00 0  7ffcdc330000-7ffcdc351000 rw-p 00000000 00:00 0                          [stack] 7ffcdc360000-7ffcdc363000 r--p 00000000 00:00 0                          [vvar] 7ffcdc363000-7ffcdc365000 r-xp 00000000 00:00 0                          [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall] exit status -1   

2 answers

  • answered 2018-10-22 21:39 paddy

    Let's break down the guts of your push_back function:

    Bankaccount* tmp = new Bankaccount[maxCapacity + 1];
    for(int i = 0; i < maxCapacity; i++){
        tmp[i] = entries[i];
    }
    

    So far, so good. You have created a new array with one extra space. (bonus: read about why this is a bad idea)

    delete entries;
    

    Okay, so you don't need the old array, but as already highlighted in the comments section, you must use delete[] entries; since it was allocated with new[].

    for(int i = 0; i < maxCapacity; i++){
        entries[i] = tmp[i];
    }
    

    Here's where it gets wild. You just deleted entries, but now you are dereferencing an invalid pointer and writing to memory. What you actually wanted to do is replace that entire loop with entries = tmp;. That just discards the old pointer that's no longer valid, and stores the new one that is valid.

    delete tmp; 
    

    NOOOOO! Not only should you have used delete[], but you don't want to do this. That just destroyed the last remaining copy of your array. Now where is your data? Remove this line.

    entries[maxCapacity] = a; 
    

    Yeah it sort of works, but you forgot one thing: maxCapacity should have been incremented when you resized the array (or at least somewhere). This line is technically okay, but semantically incorrect. You have another variable usedCapacity which tells you where to store the data. In theory, you should be increasing maxCapacity by some factor each time you resize, which means it is generally not pointing to the next free slot. So you should do this instead:

        // Better approach...
        entries[usedCapacity] = a;
        ++usedCapacity;
        ++maxCapacity;  // <- this line should actually go earlier when you resize
    

    I hope this gets you started. There are other mistakes. For example, you use the wrong new in the BankVector's constructor. Actually, you should not allocate at all. The capacity starts at zero, so just set the pointer to NULL.

    When in doubt, step through your code with a debugger.

  • answered 2018-10-22 21:42 Walter

    There are several blunders in your BankVector class. Here is a somewhat cleaned-up and (hopefully) correct version with member methods inlined for clarity.

    class BankVector {
        Bankaccount* entries = nullptr;    // provide default initialisers
        unsigned int usedCapacity = 0;      
        unsigned int maxCapacity = 0;
    
        void grow()                        // double maxCapacity
        {
            maxCapacity = maxCapacity? 2*maxCapacity : 1;
            Bankaccount*tmp = new Bankaccount[maxCapacity];
            for(unsigned int i=0; i!=usedCapacity; ++i)
                tmp[i] = entries[i];
            delete[] entries;
            entries = tmp;
        }
    
      public:
        BankVector() = default;            // use default initialisers
    
        ~BankVector()
        { delete[] entries; }
    
        unsigned int size() const
        { return usedCapacity; }
    
        unsigned int capacity() const
        { return maxCapacity; }
    
        Bankaccount const& at(unsigned int index) const   // const access
        {
            if(index >= size())
                throw std::range_error("BankVector::at(): index=" +
                    std::to_string(index) + " >= size()=" + std::to_string(size()));
            return entries[index];
        }
    
        Bankaccount & at(unsigned int index)   // non-const access
        {
            if(index >= size())
                throw std::range_error("BankVector::at(): index=" +
                    std::to_string(index) + " >= size()=" + std::to_string(size()));
            return entries[index];
        }
    
        void push_back(Bankaccount const&a)
        {
            if(size() >= capacity())
                grow();
            entries[usedCapacity++] = a;
        }
    
        void remove(unsigned int index)    // fast but not order-preserving
        {
            if(index < usedCapacity)
                entries[index]=entries[--usedCapacity];
        }
    
        void erase(unsigned int index)     // order-preserving but slow
        {
            if(index >= size())
                throw std::range_error("BankVector::erase(): index=" +
                    std::to_string(index) + " >= size()=" + std::to_string(size()));
            usedCapacity--;
            for(unsigned int i=index; i!=usedCapacity; ++i)
                entries[i] = entries[i+1];
        }
    };