меняет мой вектор на массив и должен использовать указатели - что говорит сообщение об ошибке?C ++ - PullRequest
0 голосов
/ 23 октября 2018

для моей домашней работы я должен изменить вектор из класса реестра на массив и определить его в классе BankVector.Я так и сделал, и сообщение об ошибке в компиляторе действительно ... сбивает с толку.Я новичок с указателями, так что я действительно запутался в этом.В чем ошибка?или это ошибки ха-ха ОТПРАВИТЬ ПОМОЩЬ ПОЖАЛУЙСТА

#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; 
}

Вот что печатает компилятор:

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 ]

0 голосов
/ 23 октября 2018

В вашем классе BankVector есть несколько грубых ошибок.Вот несколько исправленная и (надеюсь) правильная версия с методами-членами, встроенными для ясности.

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];
    }
};
0 голосов
/ 23 октября 2018

Давайте разберемся с вашей функцией push_back:

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

Пока все хорошо.Вы создали новый массив с одним дополнительным пробелом.(бонус: читайте о том, почему это плохая идея )

delete entries;

Хорошо, вам не нужен старый массив, но, как уже было выделено в разделе комментариев, вы должен использовать delete[] entries;, поскольку он был выделен с new[].

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

Вот где это становится диким.Вы просто удалили entries, но теперь вы разыменовываете неверный указатель и записываете в память.То, что вы на самом деле хотели сделать, это заменить весь цикл на entries = tmp;.Это просто отбрасывает старый указатель, который больше не действителен, и сохраняет новый, который является действительным.

delete tmp; 

NOOOOO!Мало того, что вы использовали delete[], но вы не хотите этого делать.Это только что уничтожило последнюю оставшуюся копию вашего массива.Теперь, где ваши данные?Удалите эту строку.

entries[maxCapacity] = a; 

Да, это вроде работает, но вы забыли одну вещь: maxCapacity должно быть увеличено при изменении размера массива (или, по крайней мере, где-то ).Эта строка технически исправна, но семантически неверна.У вас есть другая переменная usedCapacity, которая говорит вам, где хранить данные.Теоретически, вы должны увеличивать maxCapacity на некоторый коэффициент каждый раз, когда вы изменяете размер, что означает, что он обычно не указывает на следующий свободный слот.Поэтому вы должны сделать это вместо этого:

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

Надеюсь, это поможет вам начать.Есть и другие ошибки.Например, вы используете неправильный new в конструкторе BankVector.На самом деле, вы не должны выделять на всех.Емкость начинается с нуля, поэтому просто установите указатель в NULL.

В случае сомнений выполните код с помощью отладчика.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...