Why does difftime() result in different result when using mktime handling pointer and non-pointer?

StackOverflow https://stackoverflow.com//questions/25048439

  •  21-12-2019
  •  | 
  •  

Question

I try to use

    difftime(time_t end, time_t mktime(start) ) 

to calculate the difference between two different time in two different ways. Just for curiosity!And I found it results in different results, failure and success. I don't know why it happened?

Why does it result in different results in two cases as following?

    // Failure Case 1     when execution, segmentation fault
    time_t end;
    time(&end);

    struct tm * start;   // defining a pointer

    start->tm_hour = 0;
    start->tm_min  = 0;
    start->tm_sec  = 0;
    start->tm_year = 114;
    start->tm_mon  = 6;
    start->tm_mday = 29;

    double second = difftime(end, mktime(start) ); // where problem come from!

    // Success Case 2, with expected result
    time_t end;
    time(&end);       

    struct tm start;   // defining a non-pointer

    start.tm_hour = 0;
    start.tm_min  = 0;
    start.tm_sec  = 0;
    start.tm_year = 114;
    start.tm_mon  = 6;
    start.tm_mday = 29;

    double second = difftime(end, mktime( &start) );
Was it helpful?

Solution

The original case 1 doesn't allocate memory, and both cases do not clear ALL the fields in the tm structure, which may be required to get the correct result (and certainly is a "good practice").

To solve Case 1 in C, the best solution is to use calloc:

struct tm *start = calloc(1, sizeof(struct tm)); 

start->tm_year = 114;
start->tm_mon  = 6;
start->tm_mday = 29;

and then when you no longer need the start value, use

free(start);

(Note that since the structure is filled with zeros, you no longer need to manually set hour, min, sec)

In C++, you'd use new instead:

tm *start = new tm(); 
...
// After it is finished. 
delete start

The empty parenthesis in tm() makes it "fill with zero values" after allocating the actual memory.

The "Case 2" variant is preferred, since it allocates the start variable on the stack.

Case 1 are somewhat bad, since allocating memory for small data structures (small typically means anything smaller than around 1KB, but it depends on the actual runtime environment, a watch with 64KB of RAM may have stricter requirements than a desktop machine with 16GB of RAM, and a mobile phone would be somewhere in between those, somewhat depending on what kind of phone it is). There are at least two reasons to avoid "small" memory allocations:

  1. It takes more memory, since all known allocators use SOME extra memory to keep track of the actual "lump" of memory allocated.
  2. It takes extra time because new or calloc are much more complex than the allocation on the stack (in typical machines, allocating space on the stack takes 1-2 instructions above and beyond the same function with no variables at all, where a call to new or {c,m}alloc can be half a dozen just for the call and the same again for delete or free, and several dozen to a few thousand instructions inside those library functions - how long the code is depends largely on how it is implemented, and whether the runtime has some "memory available" or a call into the OS is required to "get some more memory" as well). And of course, you need to keep track of the allocation and not "leak" it. [There are C++ solutions to do that too, but I've written enough in this answer already to make it hard to follow]

For case 2 you can use:

struct tm start = {}; 

(And again, you don't need to set zero-values for hour, min and sec)

In C++ it is correct to omit struct, since struct tm { ... }; declaration in the relevant header file makes the name tm represent the structure anyway - this applies for all struct and class names - only exception is if the same name is used in a different way, e.g. there's a function or variable called tm in the same context - in which case the compiler will give some error saying "don't understand what you mean by tm here" [exact wording varies depending on which compiler is used].

Since the original question specifies BOTH C and C++, I've tried to explain

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top