String "Contains" char function
The final memcpy may overflow output_buffer. I recommend to change the signature to

int str_contains(const char * str, char c, int *indices, size_t indices_size);


The caller shall compare the return value with the size of buffer it passed and act accordingly.
Dynamic memory is uncalled for. You may safely collect indices directly into the passed buffer.
There is no need for strlen.
When appropriate, use pointers.


All that said,

int str_contains(const char * str, char c, size_t * indices, size_t indices_size)
{
    size_t occurrences = 0;
    for (char * cursor = str; *cursor; cursor++) {
        if (*cursor == c) {
            if (occurrences &lt; indices_size) {
                indices[occurrences] = cursor - str;
            }
            occurrences++;
        }
    }
    return occurrences;
}