2015-01-10 2 views
1

Я только начал изучать C++. Просматривая коды на этом сайте, я натолкнулся на код, который проверяет дату, введенную пользователем. Но проблема в том, что она может принимать даже будущие значения, поэтому эту логику нужно настроить, чтобы работать на прием DOB. , поэтому я решил использовать текущее время, используя функцию «время()», а затем сравнив его с введенной датой. Начнем с того, я добавил две строки в коде (те, которые комментируются в коде ниже), которыеValidating Дата рождения в C++

time(&tNow); 

и

const struct tm *now = localtime(&tNow); 

вот мой код:

#include <iostream> 
#include <sstream> 
#include <ctime> 

using namespace std; 
// function expects the string in format dd/mm/yyyy: 
bool extractDate(const std::string& s, int& d, int& m, int& y){ 
    std::istringstream is(s); 
    char delimiter; 
    if (is >> d >> delimiter >> m >> delimiter >> y) { 
     struct tm t = {0}; 
     t.tm_mday = d; 
     t.tm_mon = m - 1; 
     t.tm_year = y - 1900; 
     t.tm_isdst = -1; 

     // normalize: 
     time_t when = mktime(&t); 

     time_t tNow; 

     // time(&tNow); 

      const struct tm *norm = localtime(&when); 

     // const struct tm *now = localtime(&tNow);  /* when I uncomment this line the code        
     //             does not accept future date */ 



     // validate (is the normalized date still the same?): 
     return (norm->tm_mday == d && 
       norm->tm_mon == m - 1 && 
       norm->tm_year == y - 1900); 
    } 
    return false; 
} 


int main() { 

    std::string s("11/01/2015"); 
    int d,m,y; 

    if (extractDate(s, d, m, y)) 
     std::cout << "date " 
        << d << "/" << m << "/" << y 
        << " is valid" << std::endl; 
    else 
     std::cout << "date is invalid" << std::endl; 
} 

Когда я раскомментирую const struct tm *now = localtime(&tNow);, код дает правильный результат как «неверная дата» для любых будущих значений даты ... но почему это происходит. Я получаю правильный вывод, но я хочу знать, почему.

+1

Похоже, вы где-то сталкивались с неопределенным поведением, я просто не могу определить, где именно. Получали ли вы предупреждения при компиляции? –

+0

Я использую онлайн-компилятор (http://www.tutorialspoint.com/compile_cpp_online.php), чтобы скомпилировать этот код и не давать никаких ошибок, он работает нормально – Priyanka

+0

нет, он не показывает никаких предупреждений. – Priyanka

ответ

4

Хорошо, проблема заключается в том, что localtime возвращает тот же буфер, когда вы вызываете его несколько раз. Вам нужно скопировать результат (или использовать localtime_r, который принимает дополнительный параметр, но он не такой портативный).

Вот мой сеанс отладки вашего кода (с незакомментированной секцией):

(gdb) p norm 
$1 = (const tm *) 0x7ffff75aca60 <_tmbuf> 
(gdb) p now 
$2 = (const tm *) 0x7ffff75aca60 <_tmbuf> 

Так я решил это так:

const struct tm norm = *localtime(&when); 

    const struct tm now = *localtime(&tNow); 


    // validate (is the normalized date still the same?): 
    return (norm.tm_mday == d && 
     norm.tm_mon == m - 1 && 
     norm.tm_year == y - 1900); 

Есть несколько других вариантов на эту же тему, но это должно сработать.

1

В большинстве случаев использование локальных статических struct tm. Возвращаемый указатель является указателем на этот единственный экземпляр, поэтому в вашем случае norm и now указывается на тот же экземпляр struct tm, а второй вызов изменяет его.

Некоторые реализации могут использовать нить локальное хранилище так, что использование в различных потоках, по крайней мере получает отдельный struct tm, но это не влияет на этот случай, и не требуется поведение.

Наиболее documentation ясно на этом, например, ссылка связаны говорит:

возвращаемое значение указывает на внутренний объект, действительность или значение может быть изменено с помощью любого последующего вызова gmtime или LocalTime.