Home | Blog | Yawp | Now | About

This is a collection of some of the things I've written about, recently. I am a perpetual tinker, and most of the things that I find the energy to write about are in that vein of things. This is Not a Writer's Log, but a Tinker's Notebook.

true
{{blog::edited}}

Pointers Are Hard

Published on 03/02/2023 |
#include <stdio.h>
#include <time.h>

int main() {
  char buf[80];

  time_t init = time(NULL);
  struct tm tmp = *localtime(&init);

  for (int i = 0; i < 4; i++) {
    struct tm startTime = tmp;
    startTime.tm_min += (i * 30);
    mktime(&startTime);

    struct tm breakTime = startTime;
    breakTime.tm_min += 25;
    mktime(&breakTime);

    strftime(buf, 80, "%H:%M", &startTime);
    printf("Start time: %s\n", buf);

    strftime(buf, 80, "%H:%M", &breakTime);
    printf("Break time: %s\n", buf);
    printf("--------------\n");
  }

  return 0;
}

I am somewhat prone to distraction and hyper-fixation on a given thing, especially when that thing scratches my brain in just the right way. In order to spend less time hunched over a keyboard and more time hunched over tile-work, I wrote a short program to list out start and stop times for a 2 hour Pomodoro.

The idea is pretty straightforward: work 25 minutes, break 5 minutes. Rinse and repeat. It's usually recommended that after 4 cycles or so, you take a long (30 minute) break. Since I'm trying to spend less time goofing off, I've decided to forego the extra junk people add on or alter for productivity reasons. Just 25 minutes of doing, and 5 minutes of not doing.

But that's not the important part. This is:

// My Use Case
time_t init = time(NULL);
struct tm tmp = *localtime(&init);

Google "C89 time.h example" and you'll get a lot of examples along these lines, with one minor difference.

// Example Use Case
time_t init = time(NULL);
struct tm *tmp = localtime(&init);

Spot the difference? The gist here is that I am not very literate in C, and often misunderstand the semantics of pointers and copying them around.

I had initially tried something like this:

char buf[80];
time_t now = time(NULL);
struct tm *startTime = localtime(&now);
struct tm *breakTime = startTime;
breakTime->tm_min += 25;
mktime(breakTime);

This doesn't work the way I had initially expected, because in my illiteracy, I had not realized that `startTime` and `breakTime` pointed to the sample place, as demonstrated by something like this:

strftime(buf, 80, "%H:%M", startTime);
printf("Start Time: %s, location: %x\n", buf, startTime);

strftime(buf, 80, "%H:%M", breakTime);
printf("Break Time: %s, location: %x\n", buf, breakTime);

So now we know we need to actually copy the information elsewhere to work on. Hence:

time_t init = time(NULL);
struct tm tmp = *localtime(&init);

struct tm startTime = tmp;
startTime.tm_min += (i * 30);
mktime(&startTime);

struct tm breakTime = startTime;
breakTime.tm_min += 25;
mktime(&breakTime);

And now it works as expected. the output from compiling and running `timer.c` is a nice little list of times to start and stop working for the next two hours. On its own it's not particularly useful unless you have the discipline to know when to stop and start. Since I'm easily distracted, the next logical step is to feed that list of times and a pair of start/stop scripts to `cron` to enforce the workflow...

Home | Blog | Yawp | Now | About