Получение ошибки сегментации после деструктора - PullRequest
6 голосов
/ 28 марта 2010

Я делаю небольшую программу по чтению файлов и проверке данных в рамках моего курса TAFE (высшее учебное заведение), включая даты проверки и подтверждения.

Я решил, что лучше всего это сделать с отдельным классом, а не интегрировать его в мой основной класс драйверов.

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

date.h

#ifndef DATE_H
#define DATE_H

#include <string>
using std::string;

#include <sstream>
using std::stringstream;

#include <cstdlib>
using std::exit;

#include <iostream>
using std::cout;
using std::endl;

class date {

    public:
        explicit date();
        ~date();
        bool before(string dateIn1, string dateIn2);
        int yearsBetween(string dateIn1, string dateIn2);
        bool isValid(string dateIn);
        bool getDate(int date[], string dateIn);
        bool isLeapYear(int year);
    private:
        int days[];

};
#endif

date.cpp

#include "date.h"

date::date() {

    days[0] = 31;
    days[1] = 28;
    days[2] = 31;
    days[3] = 30;
    days[4] = 31;
    days[5] = 30;
    days[6] = 31;
    days[7] = 31;
    days[8] = 30;
    days[9] = 31;
    days[10] = 30;
    days[11] = 31;

}

bool date::before(string dateIn1, string dateIn2) {

    int date1[3];
    int date2[3];

    getDate(date1, dateIn1);
    getDate(date2, dateIn2);

    if (date1[2] < date2[2]) {

        return true;

    } else if (date1[1] < date2[1]) {

        return true;

    } else if (date1[0] < date2[0]) {

        return true;

    }

    return false;

}

date::~date() {

    cout << "this is for testing only, plox delete\n";

}

int date::yearsBetween(string dateIn1, string dateIn2) {

    int date1[3];
    int date2[3];

    getDate(date1, dateIn1);
    getDate(date2, dateIn2);

    int years = date2[2] - date1[2];

    if (date1[1] > date2[1]) {

        years--;

    } 

    if ((date1[1] == date2[1]) && (date1[0] > date2[1])) {

        years--;

    }

    return years;

}

bool date::isValid(string dateIn) {

    int date[3];

    if (getDate(date, dateIn)) {

        if (date[1] <= 12) {

            int extraDay = 0;

            if (isLeapYear(date[2])) {

                extraDay++;

            }

            if ((date[0] + extraDay) <= days[date[1] - 1]) {

                return true;

            }

        }

    } else {

        return false;

    }

}

bool date::getDate(int date[], string dateIn) {

    string part1, part2, part3;

    size_t whereIs, lastFound;

    whereIs = dateIn.find("/");

    part1 = dateIn.substr(0, whereIs);

    lastFound = whereIs + 1;

    whereIs = dateIn.find("/", lastFound);

    part2 = dateIn.substr(lastFound, whereIs - lastFound);

    lastFound = whereIs + 1;

    part3 = dateIn.substr(lastFound, 4);

    stringstream p1(part1);
    stringstream p2(part2);
    stringstream p3(part3);

    if (p1 >> date[0]) {

        if (p2>>date[1]) {

            return (p3>>date[2]);

        } else {

            return false;

        }

        return false;

    }

}

bool date::isLeapYear(int year) {

    return ((year % 4) == 0);

}

и, наконец, тестовая программа

#include <iostream>
using std::cout;
using std::endl;

#include "date.h"

int main() {

    date d;

    cout << "1/1/1988 before 3/5/1990 [" << d.before("1/1/1988", "3/5/1990")
        << "]\n1/1/1988 before 1/1/1970 [" << d.before("a/a/1988", "1/1/1970")
        <<"]\n";

    cout << "years between 1/1/1988 and 1/1/1998 [" 
        << d.yearsBetween("1/1/1988", "1/1/1998") << "]\n";

    cout << "is 1/1/1988 valid [" << d.isValid("1/1/1988") << "]\n" 
        << "is 2/13/1988 valid [" << d.isValid("2/13/1988") << "]\n"
        << "is 32/12/1988 valid [" << d.isValid("32/12/1988") << "]\n";

    cout << "blerg\n";

}

Я оставил в некоторых посторонних операторах cout, которые я использовал, чтобы попытаться найти ошибку.

Заранее благодарю.

Ответы [ 5 ]

3 голосов
/ 28 марта 2010

Изменение:

private:
    int days[];

до:

private:
    int days[12];
3 голосов
/ 28 марта 2010

Проблема в том, что вы на самом деле никогда не инициализируете поле days в типе date. Это означает, что когда вы устанавливаете значения в конструкторе, вы обращаетесь к неинициализированной памяти.

Вам необходимо каким-то образом явно инициализировать значение days. Самое простое решение - использовать vector для типа или жестко закодировать размер массива до 12.

private:
  int days[12];

Или

private:
  std:vector<int> days;

...
date::date() {
  days.push_back(31);
  days.push_back(28);
  ...
}
2 голосов
/ 28 марта 2010

Вы не говорите, какой компилятор вы используете, но если я скомпилирую этот код, используя g ++ с флагами -Wall и -pedantic:

struct S {
    int a[];
};

int main() {
    S s;
}

Я получаю предупреждение:

warning: ISO C++ forbids zero-size array 'a'

Мораль в том, что вы всегда должны компилировать, используя как можно больше предупреждений компилятора - это может сэкономить вам массу времени и привести к более правильному коду.

1 голос
/ 28 марта 2010

Я согласен с предыдущими ответами на этот вопрос, но я бы добавил обоснование их правильности:

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

http://en.wikipedia.org/wiki/Segmentation_fault

Вам не был разрешен доступ к "days [0]" через days "[11]", поскольку компьютер не дал переменную "days []", для которой вы объявили достаточно памяти для хранения каких-либо элементов, таким образом, когда вы пытались доступ к указанным элементам, это бросило segfault.

Любые переменные , а не , объявленные с помощью оператора "new", помещаются в "стек", который представляет собой непрерывный фрагмент памяти, который компьютер выделил для использования программой. Чтобы хранить все данные в стеке смежными, компьютер будет выделять только тот объем памяти, который вам необходим для использования при каждом запросе, так что, если вы, например, запросите создание int, он даст вам достаточно память для хранения этого единственного целого.

Когда вы написали строку int days []; компьютер попытался оценить, сколько памяти ему потребуется, оценил его как пустой массив и дал достаточно памяти для хранения указанного пустого массива. Поскольку компьютер не давал вашему массиву никакого дополнительного пространства сверх того, что было необходимо для пустого массива, он знал, что память, к которой вы пытались обратиться в этом массиве, не была ему назначена, поэтому он вызвал ошибку сегментации и дал сбой.

Если вы еще не узнали о «стеке» и «куче» в своем классе информатики, то извините, если это немного ошеломляет, но я, возможно, слишком усложнил вещи, и я думаю, что вы, вероятно, скоро узнаете.

1 голос
/ 28 марта 2010
int days[];

Это нестандартное расширение. Вы должны указать размер массива, например:

static const MonthCount = 12;
int days[MonthCount];

На самом деле использовать массив. В противном случае у вас есть «массив нулевого размера» (не стандартный!). Ваша программа перебирает память каждый раз, когда вы используете какой-либо элемент вашего текущего массива.

...