Класс для реализации стека с массивом Dynami c, дает ошибку сегментации в кодировщике кода - PullRequest
0 голосов
/ 18 марта 2020

Я попытался реализовать стек с динамическим c массивом и добавить код в грейдер кода, но он продолжает давать мне ошибки сегментации. Я думаю, что где-то нет границ массива, но я не могу его разрешить. Любые идеи?

#include <iostream>

using namespace std;
template <typename T>
class stack {
  public:
     int length;
     T *data;
     int top=0;
    stack (int size) {
      length=size;
      data=new T[length]();
      top=0;
    }
    stack (const stack &s) {
      length=s.size();
      data=new T[length]();
      if(s.data!=NULL){
        for(int i=0; i<length; i++){
          data[i]=s.data[i];top++;
        }}
    }
    ~stack () {
        if(data!=NULL){
        delete[] data;}
        data=NULL;
    }
    bool empty () {
      return top==0;
    }
    void push (const T &x) {
      data[top]=x;
      top++;
    }
    T pop () {
      return data[--top];
    }
    int size ()const{
      return top;}
    friend ostream & operator << (ostream &out,const stack &s) {
      if(s.size()==0){
        out<<"[]";}
      else{
        out<<'[';
        for(int i=0; i<s.size()-1; i++){
          out<<s.data[i]<<", ";
        }
        out<<s.data[s.size()-1]<<']';}
      return out;
    }
    const stack & operator = (const stack &s){
      top=s.top;
      for(int i=0; i<length; i++){
        data[i]=s.data[i];}
      return *(this);
    }
};

Пример добавления, которое грейдер вносит в код, таков:

#ifndef CONTEST
int main(){
stack<int> s(10);
cout << "s is empty: "<< s << endl;
s.push(42);
cout << "s has one element: " << s << endl;
s.push(17);
s.push(34);
cout << "s has more elements: " << s << endl;
cout << "How many? " << s.size() << endl;
stack<int> t(5);
t.push(7);
cout << "t: " << t << endl;
t = s;
cout << "popping from s: " << s.pop() << endl;
s.push(8);
stack<int> a(s);
t.push(99);
a.push(77);
cout << "s: " << s << endl;
cout << "t: " << t << endl;
cout << "a: " << a << endl;
// now with doubles...
stack<double> c(4);
c.push(3.14);
c.push(1.414);
cout << "c contains doubles " << c << endl;
// and with characters...
stack<char> k(4);
k.push('$');
cout << "k contains a character " << k << endl;
}
#endif

И предполагается вывести это:

s is empty: []
s has one element: [42]
s has more elements: [42, 17, 34]
How many? 3
t: [7]
popping from s: 34
s: [42, 17, 8]
t: [42, 17, 34, 99]
a: [42, 17, 8, 77]
c contains doubles [3.14, 1.414]
k contains a character [$]

Ответы [ 2 ]

2 голосов
/ 18 марта 2020

Ваш оператор копирования (operator=) делает что-то значительно отличающееся от вашего конструктора копирования. На самом деле, он на самом деле не копирует объект, а только элементы из data. Но там не учитывается разное количество элементов.

Назначение t = s; вызывает ошибку сегментации.

const stack & operator = (const stack &s){
    top=s.top; // s.top could be larger than the current size, no checks?
    for(int i=0; i<length; i++) { //this->length == 10, but
        data[i]=s.data[i];}       //s.data contains only 7 elements!
    return *(this);
}

Технически это неопределенное поведение, к счастью, оно проявляется в ошибке сегментации здесь.


Оператор копирования обычно делает то же самое, что и конструктор копирования. Некоторые ссылки для справки и примеров кода: Правило 5/3/0 и Что такое идиома копирования и обмена?

1 голос
/ 18 марта 2020

Это минимальный код, который воспроизводит ошибку:

int main() {
    stack<int> s(10);
    s.push(42);
    stack<int> a(s);
    a.push(77);
}

ваша size функция возвращает juste top, а не size:

int size()const {
    return top;
}  

Поэтому в ваш конструктор копирования, вы создаете пространство для top elements:

stack(const stack &s) {
        length = s.size();
        data = new T[length]();
//...
}  

В вашем случае вы не можете написать:

a.push(77);  

Поскольку вы выделяете s.top элементов и ваш массив имеет нет больше места Вы пишете из связи, которая вызывает ошибку сегментации

...