【问题标题】:Using pointer destination in strftime (C)在 strftime (C) 中使用指针目标
【发布时间】:2017-01-18 02:20:41
【问题描述】:

首先,道歉:C 的新手,而且总体上在编码方面相当绿色。

问题:尝试使用 strftime() 在 C 中创建时间戳。 这有效:

    #include <time.h>
    ...
    char timestamp[14];
    ...[code to define timestruct]
    strftime(timestamp,15,"%Y%m%d%H%M%S", timestruct);

但是 this 给出了分段错误:

    #include <time.h>
    ...
    char *timestamp;
    ...[code to define timestruct]
    strftime(timestamp,15,"%Y%m%d%H%M%S", timestruct);

显然,我有一个可行的解决方案,所以基本上一切都很好。但是为什么以timestamp为指针的版本不起作用呢?

提前致谢。

【问题讨论】:

  • 尝试首先在第二种情况下分配时间戳。也就是说,做char *timestamp = malloc(14)
  • 第二种情况下调用strftime(timestamp,15,...时指针timestamp是多少?
  • @gowrath 知道了,谢谢。
  • @chux 例如“20160909204853”加上可能是终止\0

标签: c string time


【解决方案1】:

因为在第二个示例中,timestamp 是一个未初始化的指针:当strftime 写入时为 segv。

如果要使用指针,请使用malloc分配内存

char *timestamp = malloc(20);  // 20 is maybe too much, better safe than sorry

如果您想在本地使用timestamp 而不将其返回给调用者,我会推荐第一种解决方案,因为它不涉及分配/解除分配。更快更安全(没有可能的内存泄漏)

【讨论】:

    【解决方案2】:

    strftime() 需要timestamp 中的缓冲区来写入格式化字符串。它不会为该缓冲区本身分配内存。当您使用 char timestamp[14] 时,您有一个 14 字符的缓冲区,并且一切正常,您应该为 max 参数发送 14 而不是 15,以避免写入超过 timestamp 的末尾。当您使用char *timestamp 时,虽然只有一个包含随机值但没有分配内存的指针。 strftime() 将取消引用该随机指针并尝试写入它所指的内存中的任何位置,然后会发生什么取决于该内存的位置。如果它不存在或无法访问,你会得到一个分段错误,如果它碰巧存在并且是可写的,它似乎可以工作,但实际上你只是在其他地方损坏了一些未知的东西,这可能会导致稍后弹出随机错误.如果您想使用char * 而不是timestamp 的char 数组,您还需要使用malloc() 或类似方法来分配内存并将结果分配给timestamp,以便在调用之前指向分配的内存strftime().

    【讨论】:

      【解决方案3】:

      C 中的指针要求您在堆上为它们分配空间。在第一种情况下,当您声明 char timestamp[14] 时,括号中的 14 告诉编译器在堆栈上分配 14 个字节作为时间戳。所以你可以将它用于短于 14 个字节的字符串,你会没事的。

      在第二种情况下,您声明 char *timestamp 但不为其分配任何内存。因此,当strftime 尝试写入它时,它正在写入它无法访问的无效内存,因此您会遇到段错误。要解决此问题,您需要通过说char *timestamp = malloc(14) 为时间戳分配内存。这会将时间戳指向它可以使用的堆上分配的 14 个字节。这种方法的问题是你必须在使用完之后通过调用free(timestamp)手动释放内存。

      如果timestamp 是一个不需要存在的时间长于其所在函数范围的局部变量,则首选第一种方法,因为它会自动被清理。

      【讨论】:

        【解决方案4】:

        两个测试都会导致未定义的行为 (UB)。

        1. 第一个误导strftime() 告诉它缓冲区大小比原来大一个。在缓冲区外写入​​是UB。 OP报告它“有效”,但这是UB的一种可能性。这是糟糕的代码,应该重写

          char timestamp[14];
          //                  v
          strftime(timestamp,15,"%Y%m%d%H%M%S", timestruct);
          
          // Use this instead
          
          char timestamp[15 /* or more */];
          strftime(timestamp, sizeof timestamp,"%Y%m%d%H%M%S", timestruct);
          
        2. 第二个显然没有给timestamp 一个值,所以它传递给strftime() 的未定义数据告诉它在某处。这是 UB,因为 timestamp 有一个未定义的值。这是糟糕的代码,应该重新编写以首先分配内存。

          char *timestamp;
          ...
          strftime(timestamp, 15, "%Y%m%d%H%M%S", timestruct);
          
          // Use this instead
          
          #define timestamp_N 15
          {
          char *timestamp = malloc(timestamp_N);
          assert(timestamp);  //  Check allocation
          ...
          strftime(timestamp, timestamp_N, "%Y%m%d%H%M%S", timestruct);
          ... // Use timestamp
          free(timestamp);
          }
          

        进一步:1)年份字段(+ 1900)不限于0000到9999。15不足以稳健使用"%Y%m%d%H%M%S"。 2)没有必要对缓冲区大小如此吝啬。建议使用 32 等可以处理 64 位 tm_year 字段的缓冲区大小。 3) 结果不显示时区。为 UTC 附加 Z。 4) 审核标准ISO 8601

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2010-10-30
          • 1970-01-01
          • 2013-08-02
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多