I haven't written one bit of C code in well over a decade, being mostly in C#, Rust and Elixir. That being said I have a work reason to work in some C code (much to my dismay) and I'm trying to get back in the groove of actually having to care about memory management.
To do this I'm working through project Euler problems, and for problem #12 I have the following code:
Utils.h:
#ifndef C_SCRATCHPAD_UTILS_H
#define C_SCRATCHPAD_UTILS_H
#define BOOL char
#define TRUE 1
#define FALSE 0
typedef struct {
long *values;
int size;
int capacity;
} long_list;
long_list *get_primes_to_index(int index);
long_list *new_long_list();
void add_to_long_list(long_list *list, long value);
#endif //C_SCRATCHPAD_UTILS_H
Utils.c
#include <stdlib.h>
#include <string.h>
#include "utils.h"
long_list *get_primes_to_index(int index)
{
long_list *primes = new_long_list();
add_to_long_list(primes, 2);
long current_number = 3;
while (primes->size < index + 1)
{
BOOL divisor_found = FALSE;
for (int iterator = 0; iterator < primes->size; iterator++)
{
if (current_number % primes->values[iterator] == 0)
{
divisor_found = TRUE;
break;
}
}
if (divisor_found == FALSE)
{
add_to_long_list(primes, current_number);
}
current_number++;
}
return primes;
}
long_list *new_long_list()
{
long_list *list = malloc(sizeof(long_list));
list->values = malloc(sizeof(long));
list->size = 0;
list->capacity = 1;
return list;
}
void add_to_long_list(long_list *list, long value)
{
if (list->size + 1 > list->capacity)
{
long *temp = list->values;
list->values = malloc(list->capacity * 2 * sizeof(long));
memcpy(list->values, temp, list->capacity * sizeof(long));
list->capacity = list->capacity * 2;
free(temp);
}
list->values[list->size] = value;
list->size++;
}
euler.c
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "euler.h"
#include "utils.h"
typedef struct {
long *factors;
int factor_count;
long triangle_value;
} data;
data *get_factors_of_xth_triangle_number(int triangle_number, long_list *primes)
{
long_list *numbers = new_long_list();
long total = 0;
for (int x = 1; x <= triangle_number; x++)
{
total += x;
add_to_long_list(numbers, x);
}
// Find the factors
long_list *factors = new_long_list();
long sqrt_of_total = (long)sqrt(total);
for (int index = -1;index < primes->size; index++)
{
long prime = index >= 0 ? primes->values[index] : 1;
if (prime > sqrt_of_total)
{
break;
}
if (total % prime == 0)
{
int multiplier = 1;
while(1)
{
long test_number = prime * multiplier;
if ((prime == 1 && multiplier > 1) || test_number > sqrt_of_total)
{
break;
}
BOOL already_has_value = FALSE;
for (int x = 0; x < factors->size; x++)
{
if (test_number == factors->values[x])
{
already_has_value = TRUE;
break;
}
}
if (already_has_value == FALSE && test_number < total && total % test_number == 0)
{
add_to_long_list(factors, test_number);
if (total / test_number != test_number)
{
add_to_long_list(factors, total / test_number);
}
}
multiplier++;
}
}
}
data *results = malloc(sizeof(data));
results->factor_count = factors->size;
results->triangle_value = total;
results->factors = factors->values;
free(numbers);
free(factors);
return results;
}
void run_euler_problem()
{
printf("Problem #12\n");
long_list *primes = get_primes_to_index(500);
int number = 1;
while (1)
{
data *results = get_factors_of_xth_triangle_number(number, primes);
int factor_count = results->factor_count;
long total = results->triangle_value;
free(results->factors);
free(results);
if (factor_count > 500)
{
printf("Result: %ld\n", total);
break;
}
number++;
}
free(primes->values);
free(primes);
}
I'm less concerned with algorithmic efficiency as much as I am that I'm allocating things correctly, freeing things correctly, and generally not missing any C-specific gotchas that I'm not aware of.
bool
since 1999. Please use it. \$\endgroup\$