This exercise illustrates the frustrations that may occur if we (ab)use global variables and pointers. We will play with simple programs that use the standard C library time.h. Recently, a student in 'Imperative Programming' told me that he had used a lot of time on these functions, and he could not figure out why he got wrong results...
A very short explanation of the time functions in C: Time can be represented as 'unix time' (the the number of seconds elapsed since January 1, 1970) with use of the type time_t (just an unsigned integer). Time can also be encoded as a struct, of type struct tm (or in C++ just tm) with fields for seconds, minutes, hours, day, month, year (and more). The function time returns the current time, as a value of type time_t. The function localtime encodes (a pointer to) a unix time. The function asctime returns a textual presentation of (a pointer to) a tm struct. There are a few additional functions, which you may explore yourself.
The following C++ program works as expected:
#include <iostream> #include <ctime> #include <string> using namespace std; int main(){ time_t t1 = time(NULL), // Time now t2 = t1 - 7 * 24 * 60 * 60; // Same time last week. tm *tm1 = localtime(&t1); // Transforms t1 to tm struct char *tmstr1 = asctime(tm1); // Make an ASCII text string of the time cout << "Time now: "<< tmstr1 << endl; // Print it tm *tm2 = localtime(&t2); // Transforms t2 to tm struct char *tmstr2 = asctime(tm2); // Make an ASCII text string of the time cout << "Time a week ago: " << tmstr2 << endl; // Print it }
Try it out - and play with some variations if you want to explore the possiblities with time.h functions. It is a C++ program, so compile it with your C++ compiler.
The following program - where we have reordered some of the commands - does not work as expected:
#include <iostream> #include <ctime> #include <string> using namespace std; int main(){ time_t t1 = time(NULL), // Time now. t2 = t1 - 7 * 24 * 60 * 60; // Same time last week. tm *tm1 = localtime(&t1); // Transforms t1 to tm struct char *tmstr1 = asctime(tm1); // Make an ASCII text string of the time tm *tm2 = localtime(&t2); // Transforms t2 to tm struct char *tmstr2 = asctime(tm2); // Make an ASCII text string of the time cout << "Time now: "<< tmstr1 << endl; // Print time now cout << "Time a week ago: " << tmstr2 << endl; // Print time a week ago. Upps - what happened? }
Make sure you understand the problem(s). How does localtime deliver its result (a tm struct)? An similarly, how does asctime deliver its result (a C-style text string)? Consult the documentation of the time.h library.
Be sure to understand the problems in terms of global data, memory allocation, and pointers.
Why do you think the designers of time.h came up with the signatures of these functions, and the conventions for the use of the functions?
How would you design the functions in order to eliminate the frustrations?