析构函数后获取分段错误

时间:2010-03-28 08:07:05

标签: c++ segmentation-fault destructor

我正在制作一个小文件阅读和数据验证程序,作为我的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 个答案:

答案 0 :(得分:3)

变化:

private:
    int days[];

为:

private:
    int days[12];

答案 1 :(得分:3)

问题是您实际上从未初始化类型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 :(得分:2)

您没有说明您使用的是哪种编译器,但是如果我使用带有-Wall-pedantic标志的g ++编译此代码:

struct S {
    int a[];
};

int main() {
    S s;
}

我收到警告信息:

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

道德观点是你应该总是使用尽可能多的编译器警告进行编译 - 它可以节省大量时间并产生更正确的代码。

答案 3 :(得分:1)

int days[];

这是非标准扩展名。您必须指定数组的大小,例如:

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

实际上要使用一个数组。否则你有一个“零大小的数组”(不标准!)。每次使用当前数组的任何元素时,你的程序都会在内存上进行操控。

答案 4 :(得分:1)

我同意此问题的先前答案,但我会补充其正确性的理由:

每当您尝试访问不允许访问的内存时,都会导致分段错误。

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

您不能通过“[11]”天访问“days [0]”,因为计算机没有给出“days []”变量,您声明了足够的内存来容纳任何元素,因此当您尝试访问所述元素,它引发了一个段落错误。

使用“new”运算符声明的任何 not 变量都放在“堆栈”上,这是计算机已分开供程序使用的连续内存块。为了使存储在堆栈中的所有内容保持连续,计算机将只提供您在请求时使用所需的内存量,因此,如果您请求创建int,例如,它只会给您足够的用于存储单个int的内存。

当你写行int days [];计算机试图评估它需要多少内存,将其评估为空数组,并为您提供足够的内存来存储所述空数组。因为计算机没有给你的数组提供超出空数组所需的额外空间,所以它知道你试图在该数组中访问的内存没有分配给它,因此它抛出了一个分段错误并崩溃了。

如果你还没有在计算机科学课上学过“堆栈”和“堆”,那么对不起,如果这有点压倒性的,但我可能会过于复杂化,我想你很快就会这样。