2010-03-28 52 views
6

我正在制作一个小文件读取和数据验证程序作为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语句,我一直在用来尝试找出错误。

我提前感谢你。

+0

我可以指出'isLeapYear'的实现是错误的吗? '1900'不是闰年。阅读:http://en.wikipedia.org/wiki/Leap_year – 2010-03-28 14:05:29

回答

1
int days[]; 

这是一个非标准扩展。您必须指定阵列的大小,例如:

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

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

+0

好吧,很酷,谢谢你的答案,他们的工作,huzzah。 谢谢大家, – user303491 2010-03-28 09:01:07

3

变化:

private: 
    int days[]; 

到:

private: 
    int days[12]; 
3

的问题是,你从来没有真正在类型date初始化days领域。这意味着当您在构造函数中设置值时,您正在访问未初始化的内存。

您需要以某种方式明确初始化days值。最简单的解决方法是使用一个vector的类型或硬编码数组的大小为12

private: 
    int days[12]; 

或者

private: 
    std:vector<int> days; 

... 
date::date() { 
    days.push_back(31); 
    days.push_back(28); 
    ... 
} 
1

我与以前这个问题的答案同意,但我会增加其正确性的基本原理:

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

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

你不允许访问“的日子[0]”通过天“[11]”因为电脑没有给你宣布足够的内存来容纳任何元素的“天[]”变量,因此当你试图访问这些元素时,它会抛出一个段错误。

任何变量而不是声明与“新”操作符被放置在“堆栈”,这是一个连续的内存块计算机已经分开了供程序使用。为了让所有存储在堆栈中的内容保持连续,计算机只会提供您需要的内存量,只要您请求它就可以使用,例如,如果您请求创建一个int,则只会给您提供足够的内存内存来存储单个int。

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

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

+0

谢谢大家的帮助,非常感谢。 – user303491 2010-03-30 01:49:19

2

你不说你正在使用的编译器,但如果我用G ++与-Wall-pedantic标志编译此代码:

struct S { 
    int a[]; 
}; 

int main() { 
    S s; 
} 

我得到的警告消息:

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

道德是,你应该总是使用尽可能多的编译器警告进行编译 - 它可以节省你的时间,并导致更正确的代码。

+0

+1,以鼓励使用'-Wall'。编译器是开发人员最好的朋友,应该注意它的咆哮! – 2010-03-28 14:06:58