sleep() и time() не работают должным образом внутри цикла for

Я пытаюсь создать массив указателей на структуру tm, причем каждая структура имеет значение tm_sec на 2 секунды больше, чем предыдущее.

#include <stdio.h>
#include <time.h>
#include <unistd.h> /* sleep() */

int main(signed int argc, char **argv) {
    struct tm *collection[5];

    for(struct tm **p = collection; p < collection + 5; p += 1) {
        sleep(2);
        const time_t timeNow = time(NULL);
        *p = gmtime(&timeNow);
    }

    for(struct tm **p = collection; p < collection + 5; p += 1) {
        if(p != collection + 4) {
            puts((**p).tm_sec == (**(p + 1)).tm_sec ? "equal" : "not equal");
        }

        puts(asctime(*p));
    }
}

Выполнение длится около 10 секунд, что кажется нормальным, но в результате получается:

equal
Sat Jul 28 01:42:15 2018
equal
Sat Jul 28 01:42:15 2018    
equal
Sat Jul 28 01:42:15 2018    
equal
Sat Jul 28 01:42:15 2018    
Sat Jul 28 01:42:15 2018

Скомпилировано с помощью GCC 7.3.0 на linux64. Не знаю, что я делаю неправильно.

примечание: изначально у меня не было первого цикла for при вставке первого элемента, но я удалил его здесь для простоты. Это не имеет значения.


person bool3max    schedule 28.07.2018    source источник
comment
Возвращаемый указатель из gmtime относится к статическому буферу; см. справочную страницу.   -  person o11c    schedule 28.07.2018
comment
@ o11c Спасибо, я заменил его на gmtime_r: gmtime_r(&timeNow, *p), но по какой-то причине он выдает ошибку после первых 2 секунд..   -  person bool3max    schedule 28.07.2018
comment
Не нужно использовать массив указателей, просто используйте массив структур.   -  person o11c    schedule 28.07.2018
comment
@o11c Да... спасибо!   -  person bool3max    schedule 28.07.2018
comment
OT: когда параметры до main() не будут использоваться, то используйте подпись: int main( void )   -  person user3629249    schedule 30.07.2018
comment
относительно: if(p != collection + 4) это использует функцию указателя + значения, где «значение» (умноженное на размер того, на что указывает указатель) — это то, что фактически добавляется   -  person user3629249    schedule 30.07.2018


Ответы (1)


Со страницы руководства:

В POSIX.1-2001 говорится: «Функции asctime(), ctime(), gmtime() и localtime() должны возвращать значения в одном из двух статических объектов: разбивочная временная структура и массив типа char. любой из функций может перезаписать информацию, возвращаемую в любом из этих объектов любой из других функций». Это может произойти в реализации glibc.

Для однопоточных программ просто разыменуйте указатели:

#include <stdio.h>
#include <time.h>
#include <unistd.h> /* sleep() */

int main(signed int argc, char **argv) {
    struct tm collection[5];

    for (struct tm *p = collection; p < collection + 5; p++) {
        sleep(2);
        const time_t timeNow = time(NULL);
        *p = *gmtime(&timeNow);
    }

    for(struct tm *p = collection; p < collection + 5; p++) {
        if(p != collection + 4) {
            puts((*p).tm_sec == (*(p + 1)).tm_sec ? "equal" : "not equal");
        }

        puts(asctime(p));
    }
}

Для многопоточных программ вам нужно будет использовать gmtime_r и asctime_r

person o11c    schedule 28.07.2018