Here's my attempt at a sudoku puzzle solver in C. Please note this is not a copy & paste and implement in C solution but a solution I build from the ground up..

Also: This is a brute force solution but that shouldn't be a concern(stack overflow) because a sudoku puzzle only has 81 squares so the function call depth shouldn't exceed 81 by much.

The sudoku puzzle to solve is stored in an array(Sudoku_Str) in main.c. The values of the sudoku puzzle are placed into the array(Sudoku_Str) row by row. i.e. Enter the values of the first row and then the second row and so on.
Code:
#define SUDOKU_SIZE 81

unsigned int Sudoku_Str[SUDOKU_SIZE] = {
    0, 0, 0, 0, 0, 8, 0, 0, 0, 2,
    0, 0, 0, 5, 9, 0, 0, 0, 1, 0,
    0, 0, 0, 0, 2, 5, 0, 0, 0, 8,
    0, 0, 1, 4, 6, 0, 3, 0, 0, 0,
    0, 0, 1, 0, 0, 9, 0, 4, 0, 8,
    3, 0, 0, 0, 0, 0, 0, 5, 0, 0,
    0, 8, 4, 0, 0, 0, 0, 0, 4, 9,
    0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0};
Here's the code:
dyn_array.h
Code:
#ifndef DYN_ARRAY__HH
#define DYN_ARRAY__HH

#define ARR_LENGTH_MULTI 2

typedef unsigned int *ARRAY;
typedef struct dyn_array *DYN_ARRAY_PTR;
typedef void (*APPEND)(DYN_ARRAY_PTR, unsigned int);
typedef void (*DISPLAY)(DYN_ARRAY_PTR);
typedef void (*FREE)(DYN_ARRAY_PTR);

typedef struct dyn_array
{
    size_t pos;
    size_t length;
    ARRAY arr;
    APPEND append;
    DISPLAY display;
    FREE free;
} DYN_ARRAY;

DYN_ARRAY_PTR createNewDynamicArray(size_t);

#endif
dyn_array.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include "dyn_array.h"

void check_allocation(void *ptr)
{
    if (!ptr)
    {
        fputs("Allocation failed!\n", stderr);
        exit(EXIT_FAILURE);
    }
}

static void append(DYN_ARRAY_PTR da, unsigned int value)
{
    if (da->pos < da->length)
    {
        da->arr[da->pos++] = value;
        return;
    }
    size_t new_length = da->length * ARR_LENGTH_MULTI;
    da->arr = realloc(da->arr, new_length);
    check_allocation(da->arr);
    da->arr[da->pos++] = value;
    da->length = new_length;
}

static void display(DYN_ARRAY_PTR da)
{
    if (da)
    {
        fprintf(stdout, "Pos: %ld, Len: %ld\n", da->pos, da->length);
        fputs("[ ", stdout);
        if (da->arr)
        {
            size_t i = 0;
            for (; i < da->length; i++)
            {
                fprintf(stdout, "%d ", da->arr[i]);
            }
        }
        fputs("]\n", stdout);
    }
}

static void free_array(DYN_ARRAY_PTR da)
{
    free(da->arr);
    free(da);
}

DYN_ARRAY_PTR createNewDynamicArray(size_t length)
{
    DYN_ARRAY_PTR ans = malloc(sizeof(*ans));
    check_allocation(ans);
    ans->arr = calloc(sizeof(*ans->arr), length);
    check_allocation(ans);
    ans->pos = 0;
    ans->length = length;
    ans->append = append;
    ans->display = display;
    ans->free = free_array;
    return ans;
}
main.c
Code:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "dyn_array.h"

#define SUDOKU_SIZE 81
#define SUDOKU_ROW 9
#define SUDOKU_BOX 3
#define BOX_EDGES 4
#define NUM_EDGES 20

const unsigned int Sudoku_Valid_Characters[SUDOKU_ROW] = {
    1, 2, 3, 4, 5, 6, 7, 8, 9};

// Sudoku puzzle to solve
unsigned int Sudoku_Str[SUDOKU_SIZE] = {
    0, 0, 0, 0, 0, 8, 0, 0, 0, 2,
    0, 0, 0, 5, 9, 0, 0, 0, 1, 0,
    0, 0, 0, 0, 2, 5, 0, 0, 0, 8,
    0, 0, 1, 4, 6, 0, 3, 0, 0, 0,
    0, 0, 1, 0, 0, 9, 0, 4, 0, 8,
    3, 0, 0, 0, 0, 0, 0, 5, 0, 0,
    0, 8, 4, 0, 0, 0, 0, 0, 4, 9,
    0, 0, 0, 2, 3, 0, 0, 0, 0, 0, 0};
// Sudoku puzzle to solve

typedef struct rrp
{
    unsigned int r;
    unsigned int rp;
} RRP;

RRP build_rrp(const unsigned int p)
{
    RRP ans = {(p % SUDOKU_ROW), (p / SUDOKU_ROW)};
    return ans;
}

DYN_ARRAY_PTR build_row(const unsigned int p)
{
    DYN_ARRAY_PTR ans = createNewDynamicArray(SUDOKU_ROW - 1);
    RRP rrp = build_rrp(p);
    size_t e = 0;
    for (; e < SUDOKU_ROW; e++)
    {
        if (e != rrp.r)
        {
            ans->append(ans, (e + (rrp.rp * SUDOKU_ROW)));
        }
    }
    return ans;
}

DYN_ARRAY_PTR build_col(const unsigned int p)
{
    DYN_ARRAY_PTR ans = createNewDynamicArray(SUDOKU_ROW - 1);
    RRP rrp = build_rrp(p);
    size_t e = 0;
    for (; e < SUDOKU_ROW; e++)
    {
        if (e != rrp.rp)
        {
            ans->append(ans, (rrp.r + (e * SUDOKU_ROW)));
        }
    }
    return ans;
}

typedef struct box_offset
{
    int x;
    int y;
} BOX_OFFSET;

BOX_OFFSET build_box_offset(const unsigned int p)
{
    BOX_OFFSET ans;
    if (p == 0)
    {
        ans.x = 1;
        ans.y = 2;
        return ans;
    }
    else if (p == 1)
    {
        ans.x = -1;
        ans.y = 1;
        return ans;
    }
    ans.x = -2;
    ans.y = -1;
    return ans;
}

DYN_ARRAY_PTR build_box(const unsigned int p)
{
    DYN_ARRAY_PTR ans = createNewDynamicArray(BOX_EDGES);
    BOX_OFFSET r = build_box_offset((p / SUDOKU_ROW) % SUDOKU_BOX);
    BOX_OFFSET c = build_box_offset(p % SUDOKU_BOX);
    ans->append(ans, (c.x + p + (r.x * SUDOKU_ROW)));
    ans->append(ans, (c.x + p + (r.y * SUDOKU_ROW)));
    ans->append(ans, (c.y + p + (r.x * SUDOKU_ROW)));
    ans->append(ans, (c.y + p + (r.y * SUDOKU_ROW)));
    return ans;
}

DYN_ARRAY_PTR build_edges(const unsigned int p)
{
    DYN_ARRAY_PTR ans = createNewDynamicArray(NUM_EDGES);
    size_t i = 0;
    DYN_ARRAY_PTR row = build_row(p);
    DYN_ARRAY_PTR col = build_col(p);
    DYN_ARRAY_PTR box = build_box(p);
    for (; i < row->pos; i++)
    {
        ans->append(ans, row->arr[i]);
    }
    for (i = 0; i < col->pos; i++)
    {
        ans->append(ans, col->arr[i]);
    }
    for (i = 0; i < box->pos; i++)
    {
        ans->append(ans, box->arr[i]);
    }
    row->free(row);
    col->free(col);
    box->free(box);
    return ans;
}

DYN_ARRAY_PTR build_starting_values(const DYN_ARRAY_PTR edges)
{
    DYN_ARRAY_PTR ans = createNewDynamicArray(SUDOKU_ROW);
    bool found = false;
    size_t i = 0, j = 0;
    for (; i < SUDOKU_ROW; i++)
    {
        for (j = 0; j < edges->pos; j++)
        {
            if (Sudoku_Str[edges->arr[j]] == Sudoku_Valid_Characters[i])
            {
                found = true;
                break;
            }
        }
        if (!found)
        {
            ans->append(ans, Sudoku_Valid_Characters[i]);
        }
        found = false;
    }
    return ans;
}

typedef struct sudoku_data
{
    size_t position;
    unsigned int value;
    bool fixed;
    DYN_ARRAY_PTR edges;
    DYN_ARRAY_PTR starting_values;
} SUDOKU_DATA;
typedef struct sudoku_data *SUDOKU_DATA_PTR;

SUDOKU_DATA_PTR build_sudoku_data()
{
    SUDOKU_DATA_PTR ans = calloc(sizeof(*ans), SUDOKU_SIZE);
    size_t i = 0;
    for (; i < SUDOKU_SIZE; i++)
    {
        bool fixed = Sudoku_Str[i] != 0;
        if (fixed)
        {
            SUDOKU_DATA da = {i, Sudoku_Str[i], fixed, NULL, NULL};
            ans[i] = da;
        }
        else
        {
            DYN_ARRAY_PTR edges = build_edges(i);
            SUDOKU_DATA da = {i, Sudoku_Str[i], fixed, edges, build_starting_values(edges)};
            ans[i] = da;
        }
    }
    return ans;
}

void solve_it(const SUDOKU_DATA_PTR s, size_t p, bool free_data)
{
    if (p < SUDOKU_SIZE)
    {
        if (s[p].fixed)
        {
            solve_it(s, p + 1, free_data);
        }
        else
        {
            bool found = false;
            size_t i = 0, j = 0;
            for (i = 0; i < s[p].starting_values->pos; i++)
            {
                for (j = 0; j < s[p].edges->pos; j++)
                {
                    if (Sudoku_Str[s[p].edges->arr[j]] == s[p].starting_values->arr[i])
                    {
                        found = true;
                        break;
                    }
                }
                if (!found)
                {
                    Sudoku_Str[p] = s[p].starting_values->arr[i];
                    solve_it(s, p + 1, free_data);
                    Sudoku_Str[p] = 0;
                }
                found = false;
            }
        }
    }
    else
    {
        size_t i = 0;
        for (; i < SUDOKU_SIZE; i++)
        {
            fprintf(stdout, "%d ", Sudoku_Str[i]);
        }
        if (free_data)
        {
            for (i = 0; i < SUDOKU_SIZE; i++)
            {
                if (s[i].edges)
                    s[i].edges->free(s[i].edges);
                if (s[i].starting_values)
                    s[i].starting_values->free(s[i].starting_values);
            }
            free(s);
        }
        exit(EXIT_SUCCESS);
    }
}

int main(int argc, char **argv)
{
    solve_it(build_sudoku_data(), 0, true);
    return 0;
}
The program compiles and runs without any problems and I even used valgrind to check that I could free all allocated memory.

Any comments? Please post them.