From eda098773eb04c06351dc6f52d732897b3944e0c Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 10:30:14 -0400 Subject: C code for challenge 1 --- challenge-326/walt-mankowski/c/ch-1.c | 37 +++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 challenge-326/walt-mankowski/c/ch-1.c diff --git a/challenge-326/walt-mankowski/c/ch-1.c b/challenge-326/walt-mankowski/c/ch-1.c new file mode 100644 index 0000000000..f325530a39 --- /dev/null +++ b/challenge-326/walt-mankowski/c/ch-1.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include + +void usage() { + printf("Usage: ch-1 YYYY-MM-DD\n"); + exit(1); +} + +int main(int argc, char *argv[]) { + struct tm tm; + if (argc != 2) + usage(); + + /* Make a copy of argv[1] so we can call strtok() on it */ + char *yyyymmdd = malloc(strlen(argv[1]) + 1); + strcpy(yyyymmdd, argv[1]); + + /* parse the date */ + int year = atoi(strtok(yyyymmdd, "-")); + int month = atoi(strtok(NULL, "-")); + int mday = atoi(strtok(NULL, "-")); + + /* construct a struct tm with the year, month, and day */ + memset(&tm, 0, sizeof(tm)); + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_mday = mday; + + /* get the epoch time for midnight on that date */ + time_t t = mktime(&tm); + + /* get the yday for that date */ + struct tm *new_tm = gmtime(&t); + printf("%d\n", new_tm->tm_yday + 1); +} -- cgit From 70e682443c763acf9851ceb27ed199e1ba6cf10d Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 10:30:33 -0400 Subject: C code for challenge 2 --- challenge-326/walt-mankowski/c/ch-2.c | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 challenge-326/walt-mankowski/c/ch-2.c diff --git a/challenge-326/walt-mankowski/c/ch-2.c b/challenge-326/walt-mankowski/c/ch-2.c new file mode 100644 index 0000000000..a73873c380 --- /dev/null +++ b/challenge-326/walt-mankowski/c/ch-2.c @@ -0,0 +1,30 @@ +#include +#include + +int main (int argc, char *argv[]) { + if (argc % 2 != 1) { + fputs("There should be an even number of parameters\n", stderr); + exit(1); + } + + /* compute how big the output array should be */ + size_t output_size = 0; + for (int i = 1; i < argc; i += 2) + output_size += atoi(argv[i]); + int *output = malloc(output_size * sizeof(int)); + + /* add things to the output array */ + int k = 0; + for (int i = 1; i < argc; i += 2) { + int cnt = atoi(argv[i]); + int val = atoi(argv[i+1]); + for (int j = 0; j < cnt; j++) + output[k++] = val; + } + + /* print out the array */ + printf("("); + for (int i = 0; i < output_size-1; i++) + printf("%d, ", output[i]); + printf("%d)\n", output[output_size-1]); +} -- cgit From 51148c8ad32d4fec91227db07697a9ab1c52e1cd Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 10:31:18 -0400 Subject: Makefile for C code for challenge 326 --- challenge-326/walt-mankowski/c/Makefile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 challenge-326/walt-mankowski/c/Makefile diff --git a/challenge-326/walt-mankowski/c/Makefile b/challenge-326/walt-mankowski/c/Makefile new file mode 100644 index 0000000000..d1cec8a239 --- /dev/null +++ b/challenge-326/walt-mankowski/c/Makefile @@ -0,0 +1,18 @@ +C = /usr/bin/cc +CFLAGS = -Wall -O3 + +all: ch-1 ch-2 + +%.o: %.cpp + $(CPP) $(CPPFLAGS) -c $< + +ch-1: ch-1.o + $(C) -o $@ ch-1.o + +ch-2: ch-2.o + $(C) -o $@ ch-2.o + +clean: + rm -f *~ + rm -f *.o + rm -f ch-1 ch-2 -- cgit From 32aec247e56e9df31e849d885df2c5cf075663bc Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 10:38:18 -0400 Subject: changed output array type to unsigned int --- challenge-326/walt-mankowski/c/ch-2.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/challenge-326/walt-mankowski/c/ch-2.c b/challenge-326/walt-mankowski/c/ch-2.c index a73873c380..415aff1ec3 100644 --- a/challenge-326/walt-mankowski/c/ch-2.c +++ b/challenge-326/walt-mankowski/c/ch-2.c @@ -11,7 +11,7 @@ int main (int argc, char *argv[]) { size_t output_size = 0; for (int i = 1; i < argc; i += 2) output_size += atoi(argv[i]); - int *output = malloc(output_size * sizeof(int)); + unsigned int *output = malloc(output_size * sizeof(unsigned int)); /* add things to the output array */ int k = 0; @@ -25,6 +25,6 @@ int main (int argc, char *argv[]) { /* print out the array */ printf("("); for (int i = 0; i < output_size-1; i++) - printf("%d, ", output[i]); - printf("%d)\n", output[output_size-1]); + printf("%u, ", output[i]); + printf("%u)\n", output[output_size-1]); } -- cgit From c9918ff51ba59e4778ec4b2c9580610faaf009ba Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 10:55:21 -0400 Subject: moved computation of output length to a function --- challenge-326/walt-mankowski/c/ch-2.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/challenge-326/walt-mankowski/c/ch-2.c b/challenge-326/walt-mankowski/c/ch-2.c index 415aff1ec3..7b116cac04 100644 --- a/challenge-326/walt-mankowski/c/ch-2.c +++ b/challenge-326/walt-mankowski/c/ch-2.c @@ -1,6 +1,14 @@ #include #include +size_t compute_output_len(int argc, char *argv[]) { + size_t output_len = 0; + for (int i = 1; i < argc; i += 2) + output_len += atoi(argv[i]); + + return output_len; +} + int main (int argc, char *argv[]) { if (argc % 2 != 1) { fputs("There should be an even number of parameters\n", stderr); @@ -8,10 +16,8 @@ int main (int argc, char *argv[]) { } /* compute how big the output array should be */ - size_t output_size = 0; - for (int i = 1; i < argc; i += 2) - output_size += atoi(argv[i]); - unsigned int *output = malloc(output_size * sizeof(unsigned int)); + size_t output_len = compute_output_len(argc, argv); + unsigned int *output = malloc(output_len * sizeof(unsigned int)); /* add things to the output array */ int k = 0; @@ -24,7 +30,7 @@ int main (int argc, char *argv[]) { /* print out the array */ printf("("); - for (int i = 0; i < output_size-1; i++) + for (int i = 0; i < output_len-1; i++) printf("%u, ", output[i]); - printf("%u)\n", output[output_size-1]); + printf("%u)\n", output[output_len-1]); } -- cgit From 5fbb02f1f92d9a96664e085c3598998bc50d065f Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 11:01:56 -0400 Subject: parse the date directly into the struct tm --- challenge-326/walt-mankowski/c/ch-1.c | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/challenge-326/walt-mankowski/c/ch-1.c b/challenge-326/walt-mankowski/c/ch-1.c index f325530a39..0d27be33d7 100644 --- a/challenge-326/walt-mankowski/c/ch-1.c +++ b/challenge-326/walt-mankowski/c/ch-1.c @@ -17,21 +17,16 @@ int main(int argc, char *argv[]) { char *yyyymmdd = malloc(strlen(argv[1]) + 1); strcpy(yyyymmdd, argv[1]); - /* parse the date */ - int year = atoi(strtok(yyyymmdd, "-")); - int month = atoi(strtok(NULL, "-")); - int mday = atoi(strtok(NULL, "-")); - - /* construct a struct tm with the year, month, and day */ + /* parse the date and construct a struct tm with the year, month, and day */ memset(&tm, 0, sizeof(tm)); - tm.tm_year = year - 1900; - tm.tm_mon = month - 1; - tm.tm_mday = mday; + tm.tm_year = atoi(strtok(yyyymmdd, "-")) - 1900; + tm.tm_mon = atoi(strtok(NULL, "-")) - 1; + tm.tm_mday = atoi(strtok(NULL, "-")); /* get the epoch time for midnight on that date */ time_t t = mktime(&tm); - /* get the yday for that date */ + /* get the yday for that time */ struct tm *new_tm = gmtime(&t); printf("%d\n", new_tm->tm_yday + 1); } -- cgit From f9bbd9730cd5aa4388730a256763098417924b2e Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 11:03:32 -0400 Subject: replaced gmtime with gmtime_r --- challenge-326/walt-mankowski/c/ch-1.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/challenge-326/walt-mankowski/c/ch-1.c b/challenge-326/walt-mankowski/c/ch-1.c index 0d27be33d7..be8ed584cd 100644 --- a/challenge-326/walt-mankowski/c/ch-1.c +++ b/challenge-326/walt-mankowski/c/ch-1.c @@ -27,6 +27,6 @@ int main(int argc, char *argv[]) { time_t t = mktime(&tm); /* get the yday for that time */ - struct tm *new_tm = gmtime(&t); - printf("%d\n", new_tm->tm_yday + 1); + gmtime_r(&t, &tm); + printf("%d\n", tm.tm_yday + 1); } -- cgit From 4fd03856504621243cd9866bf5b4bb7202ac18ee Mon Sep 17 00:00:00 2001 From: Walt Mankowski Date: Sun, 22 Jun 2025 11:32:34 -0400 Subject: updated with descriptions of my C implementations --- challenge-326/walt-mankowski/README.md | 95 ++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) diff --git a/challenge-326/walt-mankowski/README.md b/challenge-326/walt-mankowski/README.md index 06eb8c7b5c..15d5acf2e1 100644 --- a/challenge-326/walt-mankowski/README.md +++ b/challenge-326/walt-mankowski/README.md @@ -11,6 +11,9 @@ arguments, and I don't do any error checking. Of course I wouldn't do that in the real world, but here I just wanted to focus on the algorithms and language features. +Update: Several days later I added C versions of my solutions to the +challenges. See my notes at the bottom. + ## Task #1: Day of the Year For this task we're given a date in YYYY-MM-DD format and we're asked @@ -76,3 +79,95 @@ while Python uses the `*` operator and `+=`: output += [val] * cnt ``` +## Bonus C Implementations + +It's Sunday morning and thunderstorming outside, so I decided to do C +versions of the challenges this week. + +### Day of the Week in C + +There are two steps to solving this challenge: parsing the date into +year, month, and day, and then computing the day of the year for that +date. C doesn't have a handy `split()` function, so instead I used +`strtok(3)`. `strtok()` works by modifying its input string, changing +instances of the token to NULL. We can't modify `argv` so first I make +a copy of it: + +```c + /* Make a copy of argv[1] so we can call strtok() on it */ + char *yyyymmdd = malloc(strlen(argv[1]) + 1); + strcpy(yyyymmdd, argv[1]); +``` + +Then I used `strtok()` to find the tokens between instances of `'c'` +and store them in a `struct tm`. This structure requires year 0 to be +1900 and numbers the months starting at 0, so we need to account for +that. + +```c + /* parse the date and construct a struct tm with the year, month, and day */ + memset(&tm, 0, sizeof(tm)); + tm.tm_year = atoi(strtok(yyyymmdd, "-")) - 1900; + tm.tm_mon = atoi(strtok(NULL, "-")) - 1; + tm.tm_mday = atoi(strtok(NULL, "-")); +``` + +Finally we use `mktime(3)` to convert the `struct tm` to an epoch +time and use `gmtime_r(3)` to convert it back into a `struct tm`. But +that struct has all the other information about that date populated, +and so we can just print `tm.tm_yday`. Except it's not quite that +easy, since it considers January 1 to be day 0 instead of day 1. So we +need to add 1 to it when we output it. + +```c + /* get the epoch time for midnight on that date */ + time_t t = mktime(&tm); + + /* get the yday for that time */ + gmtime_r(&t, &tm); + printf("%d\n", tm.tm_yday + 1); +``` + +### Decompressed List in C + +C doesn't have dynamically sized arrays like Perl and Python, so the +first thing we need to do is make a pass through `argv` to compute how +big the output array will be: + +```c +size_t compute_output_len(int argc, char *argv[]) { + size_t output_len = 0; + for (int i = 1; i < argc; i += 2) + output_len += atoi(argv[i]); + + return output_len; +} +``` + +We use that to `malloc` an array of `unsigned int`s: + +```c + /* compute how big the output array should be */ + size_t output_len = compute_output_len(argc, argv); + unsigned int *output = malloc(output_len * sizeof(unsigned int)); +``` + +After that, building the array and printing it out are pretty much the +same as they are in the other languages, just a bit more verbose: + +```c + /* add things to the output array */ + int k = 0; + for (int i = 1; i < argc; i += 2) { + int cnt = atoi(argv[i]); + int val = atoi(argv[i+1]); + for (int j = 0; j < cnt; j++) + output[k++] = val; + } + + /* print out the array */ + printf("("); + for (int i = 0; i < output_len-1; i++) + printf("%u, ", output[i]); + printf("%u)\n", output[output_len-1]); +``` -- cgit