Fix the compiler warnings
I get the following two warnings (after adding the necessary include of <stdint.h>
):
7504.c: In function ‘next_pascal_row’:
7504.c:9:44: warning: conversion to ‘long unsigned int’ from ‘int64_t’ {aka ‘long int’} may change the sign of the result [-Wsign-conversion]
retval = (int64_t*)malloc(sizeof(int64_t)*(previous_size+1));
^
7504.c: In function ‘print_row’:
7504.c:24:16: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘int64_t’ {aka ‘long int’} [-Wformat=]
printf("%lld ",row[i]);
~~~^ ~~~~~~
%ld
The first is best fixed by using an unsigned type such as size_t
for previous_size
.
To fix the second, we can use one of the format macros in <inttypes.h>
:
printf("%"PRId64" ",row[i]);
Choose your element type
Entries will never be negative, so we can use an unsigned type, such as uint_least64_t
. Even better, we can use a typedef so that it's clear where we're using this for the values in our triangle.
Always check your allocations succeed
When you use malloc()
and family, you must check whether the returned pointer is null before using it. Also, there's no need to cast the return value (and doing so can sometimes mask errors you'll want to know about).
Don't allocate on every iteration
If you know in advance how many iterations you'll perform (as you do here), you can allocate two buffers big enough to hold all the values (i.e. one more than the iteration count), and swap between them at each iteration.
This change reduces allocations noticeably, from
total heap usage: 33 allocs, 33 frees, 5,248 bytes allocated
to
total heap usage: 3 allocs, 3 frees, 1,536 bytes allocated
Use const
when reading
In next_pascal_row
, we only read from previous_row
, so we can pass it as a pointer to const
numbers. Similarly, we can pass pointer-to-const into print_row()
.
Avoid testing for first and last in the loop
We're in control of the loop, so if we go from the second to the penultimate element, we can fill in the first and last values outwith the loop.
Modified code
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
typedef uintmax_t number;
void next_pascal_row(number *current,
const number *previous, size_t previous_size)
{
current[0] = 1;
for (size_t i = 1; i < previous_size; ++i) {
current[i] = previous[i-1] + previous[i];
}
current[previous_size] = 1;
}
void print_row(const number *row, size_t size)
{
for (size_t i = 0; i < size; ++i) {
printf("%"PRId64" ", row[i]);
}
puts("");
}
int main()
{
/* Estimate how many iterations we can have - conservatively
assume that we double the middle value each round. */
static const size_t iterations = sizeof (number) * CHAR_BIT;
number *current_row = malloc(sizeof *current_row * iterations);
number *previous_row = malloc(sizeof *previous_row * iterations);
if (!current_row || !previous_row) {
/* malloc failed */
return 1;
}
for (size_t i = 0; i < iterations; ++i) {
next_pascal_row(current_row, previous_row, i);
print_row(current_row, i+1);
/* now swap rows */
number *next_row = previous_row;
previous_row = current_row;
current_row = next_row;
}
free(current_row);
free(previous_row);
}