Странное поведение mktime() при использовании передаваемого параметра, созданного malloc

Ниже у меня есть четыре функции.
first() и second() инициализируют только год, mon и mday структуры tm.
first_p() и second_p выделяют память с помощью malloc, затем назначают год, mon и mday.
Все функции вызывают mktime() в конце.

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

void first()
{
    int year1 = 2020, month1 = 4, day1 = 23;
    struct tm date1 = {.tm_year = year1-1900, .tm_mon = month1-1, .tm_mday = day1};
    mktime(&date1);
    printf("%s", asctime(&date1));
}

void second()
{
    int year2 = 2021, month2 = 5, day2 = 24;
    struct tm date2 = {.tm_year = year2-1900, .tm_mon = month2-1, .tm_mday = day2};
    mktime(&date2);
    printf("%s", asctime(&date2));
}

void first_p()
{
    int year1 = 2020, month1 = 4, day1 = 23;
    struct tm *date1 = (struct tm *) malloc (sizeof(struct tm));
    date1->tm_year = year1 - 1900;
    date1->tm_mon = month1 -1;
    date1->tm_mday = day1;
    mktime(date1);
    printf("%s", asctime(date1));
}

void second_p()
{
    int year2 = 2021, month2 = 5, day2 = 24;
    struct tm *date2 = (struct tm *) malloc (sizeof(struct tm));
    date2->tm_year = year2 - 1900;
    date2->tm_mon = month2 - 1;
    date2->tm_mday = day2;
    mktime(date2);
    printf("%s", asctime(date2));
}

Я пробовал разные перестановки при вызове этих функций в main():

1) first_p() и second_p() показывают случайную дату и время.

int main()
{
    first();
    second();
    first_p();
    second_p();

    return 0;
}
Thu Apr 23 00:00:00 2020
Mon May 24 00:00:00 2021
Thu Sep 30 23:09:20 66488
Wed Aug 31 14:44:48 66489

2) только second_p() показывает случайную дату и время.

int main()
{
    first_p();
    second_p();
    first();
    second();

    return 0;
}
Thu Apr 23 00:00:00 2020
Sun Dec  8 01:26:16 -103880
Thu Apr 23 00:00:00 2020
Mon May 24 00:00:00 2021

3) Только second_p() показывает случайную дату и время.

int main()
{
    first_p();
    first();
    second();
    second_p();

    return 0;
}
Thu Apr 23 00:00:00 2020
Thu Apr 23 00:00:00 2020
Mon May 24 00:00:00 2021
Thu Oct  9 04:53:52 60110

4) first_p() и second_p() показывают случайную дату и время.

int main()
{
    first();
    first_p();
    second_p();
    second();

    return 0;
}
Thu Apr 23 00:00:00 2020
Sat Sep 25 12:05:36 182934
Fri Aug 26 03:41:04 182935
Mon May 24 00:00:00 2021

Что я наблюдаю:

  • Прямая инициализация структуры, а затем передача ее в mktime() в любом месте не имеет странного поведения.
  • Allocating memory using malloc, then assigning the values and later passing it to mktime() has two behaviours:
    • If mktime() is being called for the first time, then there is no strange behavior.
    • иначе он показывает показывает случайную дату и время. Иногда годы отрицательные!

Я что-то упустил из mktime(), который отвечает за такое поведение?

Изменить:
я добавил free(date1); и free(date2); в конце first_p() и second_p(). Теперь вызов *_p() функций одна за другой не отображает случайную дату и время. Однако вызов функции first() или second() перед ними показывает случайную дату и время для первой функции *_p(), в то время как функции, следующие за ней, не показывают, т.е. для случаев 1), 3) и 4), перечисленных выше.

Однако я не могу освободить его, так как они мне нужны где-то еще (почему мне пришлось использовать malloc в первую очередь). Есть ли способ достичь этого?


person Navaneeth P    schedule 23.04.2020    source источник
comment
Заполните все поля структуры. malloc не делает этого за вас; он не устанавливает память в ноль или иным образом инициализирует ее для вас. (Определение структуры внутри функции также не инициализирует ее по умолчанию, но если вы задаете начальные значения для некоторых полей, другие инициализируются нулем.)   -  person Eric Postpischil    schedule 23.04.2020
comment
память mallocd не инициализирована. Установите его на ноль или вызовите calloc.   -  person Paul Ogilvie    schedule 23.04.2020


Ответы (1)


У вас есть квазислучайные (неопределенные) значения часов, минут, секунд и флаг перехода на летнее время в данных malloc(), поэтому вы получаете неопределенные результаты обратно из mktime().

Используйте calloc() вместо malloc() или обнулите поля самостоятельно.

Кроме того, рассмотрите возможность установки члена tm_isdst на -1, чтобы позволить системе определить, подходит ли для дат летнее или стандартное время.

person Jonathan Leffler    schedule 23.04.2020
comment
Спасибо! Использование calloc() решило проблему. Однако я до сих пор не понимаю, почему при первом вызове mktime() нет такого случайного поведения, независимо от того, использую ли я malloc() или calloc(), то есть в случаях 3) и 4), которые я упомянул. - person Navaneeth P; 23.04.2020
comment
Когда локальные переменные инициализируются назначенными инициализаторами, поля, не инициализированные явно, неявно (но окончательно) обнуляются. С памятью malloc() вы не знаете, что у вас есть — использование calloc() эффективно использует memset() для обнуления памяти, поэтому вы можете сделать то же самое. Вы можете установить поля года, месяца, дня, часа, минуты, секунды и летнего времени на ноль (или другое известное значение), и для работы требуется mktime(). Он не будет обращать внимание на поля «день года» или «день недели» при определении времени, но установит их, используя информацию о времени. - person Jonathan Leffler; 23.04.2020
comment
В остальном неопределенное поведение неопределенно — все может случиться. Иногда данные, возвращаемые malloc(), могут быть в основном нулевыми просто потому, что. - person Jonathan Leffler; 23.04.2020