【问题标题】:Validating Date of birth in C++在 C++ 中验证出生日期
【发布时间】:2015-01-10 13:13:45
【问题描述】:

我刚刚开始学习 C++。 在浏览本网站上的代码时,我遇到了一个验证用户输入日期的代码。但问题是它甚至可以采用未来的值,因此需要调整这个逻辑才能接受 DOB。 所以我决定使用“time()”函数获取当前时间,然后将其与输入的日期进行比较。首先,我在代码中添加了两行(在下面的代码中注释的那些)是

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(&amp;tNow); 时,代码会为任何未来的日期值提供正确的输出为“无效日期”......但为什么会发生这种情况。我得到正确的输出但我想知道为什么。

【问题讨论】:

  • 听起来你在某个地方遇到了未定义的行为,我只是无法真正发现在哪里。编译时有没有收到警告?
  • 我正在使用在线编译器 (tutorialspoint.com/compile_cpp_online.php) 来编译这段代码,它没有给出任何错误,它工作正常
  • 不,它没有显示任何警告。
  • 您可能需要从localtime 复制结果,因为它返回指向本地静态变量的指针。因此,当您将其称为增益时,您会得到相同的指针(您可以通过在指针返回时检查指针本身来检查它)。

标签: c++ time.h


【解决方案1】:

好的,所以问题是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);

同一主题还有其他几个变体,但这应该可以工作。

【讨论】:

    【解决方案2】:

    大多数localtime() 实现使用内部本地静态struct tm。返回的指针是指向此单个实例的指针,因此您的案例 normnow 指向同一个 struct tm 实例,第二个调用修改它。

    某些实现可能会使用线程本地存储,这样在不同线程中的使用至少会获得一个单独的struct tm,但这不会影响这种情况,也不是必需的行为。

    大多数documentation 对此都很清楚,例如链接中的参考资料说:

    返回值指向一个内部对象,其有效性或值可能会被任何后续调用 gmtime 或 localtime 更改。

    【讨论】:

      猜你喜欢
      • 2022-01-24
      • 1970-01-01
      • 1970-01-01
      • 2017-04-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多