2010-03-28 15 views
6

Sto facendo un piccolo file di lettura e un programma di convalida dei dati come parte del mio corso TAFE (un college universitario), Questo include il controllo e la convalida delle date.Errore di segmentazione dopo il distruttore

Ho deciso che sarebbe stato meglio farlo con una classe separata, piuttosto che integrarla nella mia classe di driver principale.

Il problema è che si verifica un errore di segmentazione (core dump) dopo l'esecuzione del mio programma di test. Vicino a quanto posso dire, l'errore si verifica quando il programma termina, spuntando dopo che il distruttore è stato chiamato. Finora non ho avuto fortuna a trovare la causa di questa colpa, e speravo che qualche anima illuminata potesse mostrarmi l'errore dei miei modi.

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); 

} 

e, infine, il programma di test

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

} 

ho lasciato in alcune dichiarazioni cout estranei, che ho' ho usato per cercare di individuare l'errore.

Grazie in anticipo.

+0

Posso sottolineano che l'attuazione di 'isLeapYear' è errata? '1900' non era un anno bisestile. Leggi: http://en.wikipedia.org/wiki/Leap_year –

risposta

1
int days[]; 

Questa è un'estensione non standard. È necessario specificare una dimensione per l'array, ad esempio:

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

Per disporre effettivamente di un array. Altrimenti hai un "array di dimensioni zero" (non standard!). Il tuo programma sta tranciando la memoria ogni volta che usi qualsiasi elemento dell'array attuale.

+0

Ok, bello, grazie per le risposte, funzionano, huzzah. vi ringrazio tutti, – user303491

3

Cambio:

private: 
    int days[]; 

a:

private: 
    int days[12]; 
3

Il problema è che non hai mai realmente inizializza il campo days nel tipo date. Ciò significa che quando si impostano i valori nel costruttore si accede alla memoria non inizializzata.

È necessario inizializzare in modo esplicito il valore days in qualche modo. La soluzione più semplice è quello di utilizzare un vector per il tipo o codificare la dimensione della matrice a 12.

private: 
    int days[12]; 

O

private: 
    std:vector<int> days; 

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

Sono d'accordo con le risposte precedenti a questa domanda, ma io aggiungerebbe la motivazione per la loro correttezza:

I guasti di segmentazione sono causati ogni volta che si tenta di accedere alla memoria a cui non si ha accesso.

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

Non è stato permesso di accedere a "giorni [0]" attraverso giorni "[11]" perché il computer non aveva dato i "giorni []" variabile che sono stati dichiarati memoria sufficiente per contenere tutti gli elementi , quindi quando hai provato ad accedere a tali elementi, ha generato un segfault.

Qualsiasi variabile non dichiarate con l'operatore "nuovo" vengono immessi sul "stack", che è un pezzo contiguo di memoria del computer è sezionata via per uso dal programma. Per mantenere contiguo tutto ciò che è contenuto nello stack, il computer fornirà esattamente la quantità di memoria necessaria per l'uso ogni volta che lo richiedi, in modo che se richiedi di creare un int, ad esempio, ti darà solo abbastanza memoria per memorizzare quel singolo int.

quando hai scritto la linea int giorni []; il computer ha tentato di valutare la quantità di memoria necessaria, lo ha valutato come un array vuoto e ha fornito abbastanza memoria per memorizzare detto array vuoto. Poiché il computer non ha fornito all'array spazio aggiuntivo oltre a quello necessario per un array vuoto, sapeva che la memoria a cui si tentava di accedere a quell'array non era stata assegnata, quindi ha generato un errore di segmentazione e si è arrestato in modo anomalo.

Se non hai ancora imparato lo "stack" e "heap" nella tua classe di informatica, scusa se questo è un po 'schiacciante, ma forse ho delle cose complicate, e penso che probabilmente lo farai presto.

+0

Grazie a tutti per l'aiuto regale, è molto apprezzata. – user303491

2

Tu non dici quale compilatore si sta utilizzando, ma se compilo il codice usando g ++ con le -Wall e -pedantic bandiere:

struct S { 
    int a[]; 
}; 

int main() { 
    S s; 
} 

ricevo il messaggio di avviso:

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

La morale è che dovresti sempre compilare usando il maggior numero possibile di avvertenze per il compilatore: può farti risparmiare tempo e ottenere un codice più corretto.

+0

+1 per incoraggiare l'uso di '-Wall'. Il compilatore è il migliore amico di uno sviluppatore e uno dovrebbe prestare attenzione alle sue invenzioni! –