Function to add two binary numbers in C I tried to write a function bin_add() in C to add two positive binary numbers represented as zero terminated strings:

#include &lt;errno.h&gt;
#include &lt;stdbool.h&gt;
#include &lt;stddef.h&gt;
#include &lt;string.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

#define MAX(x, y) ((x) &gt; (y) ? (x) : (y))

size_t gpp(char const *s)
{
    char *n = strchr(s, '.');
    return n  ? (size_t)(n - s + 1) : 0;
}

char* bin_add(char const *a, char const *b)
{
    char const *inp[] = { a, b };
    size_t ll[] = { strlen(a), strlen(b) };
    size_t pp[] = { gpp(a), gpp(b) };
    size_t OO[2], off[2];

    for (size_t i = 0; i &lt; 2; ++i) {
        OO[i] = pp[i] ? pp[i] - 1 : ll[i];
        pp[i] = pp[i] ? ll[i] - pp[i] : 0;}

    for (size_t i = 0; i &lt; 2; ++i)
        off[i] = OO[i] &lt; OO[!i] ? OO[!i] - OO[i] : 0;

    size_t ML = MAX(OO[0], OO[1]) + MAX(pp[0], pp[1]) + (!!pp[0] || !!pp[1]);
    char *Ol = calloc(ML + 2, 1);
    if(!Ol) return Ol;

    char ops[2];
    int xc = 0;
    size_t lO = ML;
    unsigned cc[2] = { 0 };
    for (size_t i = ML; i; --i) {
        bool pt = false;
        for (size_t l = 0; l &lt; 2; ++l) {
            ops[l] = i &lt;= ll[l] + off[l] &amp;&amp; i - off[l] - 1
                       &lt;  ll[l] ? inp[l][i - off[l] - 1] : '0';
            if (ops[l] == '.') {
                if (cc[l]) {
                    free(Ol);
                    return NULL;
                }
                pt = true;
                ++cc[l];
            }
            ops[l] -= '0';
        }
        if (pt) {
            Ol[i] = '.';
            continue;
        }
        if ((Ol[i] = ops[0] + ops[1] + xc) &gt; 1) {
            Ol[i] = 0;
            xc = 1;
        }
        else xc = 0;
        lO = (Ol[i] += '0') == '1' ? i : lO;
    }
    if((Ol[0] = '0' + xc) == '1') return Ol;
        for (size_t i = 0; i &lt;= ML - lO + 1; ++i)
            Ol[i] = Ol[lO + i];

    return Ol;
}

int main(void)
{
    char a[81], b[81];

    while (scanf(" %80[0.1] %80[0.1]", a, b) &amp; 1 &lt;&lt; 1) {
        char *c = bin_add(a, b);
        if (!c &amp;&amp; errno == ENOMEM) {
            fputs("Not enough memory :(\n\n", stderr);
            return EXIT_FAILURE;
        }
        else if (!c) {
            fputs("Input error :(\n\n", stderr);
            goto clear;
        }

        char* O[] = { a, b, c };
        size_t lO[3], Ol = 0;
        for (size_t i = 0; i &lt; 3; ++i) {
            lO[i] = gpp(O[i]);
            lO[i] = lO[i] ? lO[i] : strlen(i[O]) + 1;
            Ol = lO[i] &gt; Ol ? lO[i] : Ol;
        }

        putchar('\n');
        for (size_t i = 0; i &lt; 3; ++i) {
            for (size_t l = 0; l &lt; Ol - lO[i]; ++l, putchar(' '));
        puts(O[i]);
        }
        putchar('\n');

        free(c);
        clear :{ int c; while ((c = getchar()) != '\n' &amp;&amp; c != EOF); }
    }
}


The main() is just included to provide input to the function and pretty-print its results. Every C99 compliant compiler should be able to compile above code.

Do you see any flaws in my code and anything that could be improved?
Do you see any flaws in my code and anything that could be improved?


Segregate code

Splitting into bin_add.c, bin_add.h, main.c would help delineate what is the code, its user interface and test code.

No compilation errors

As posted now, I did not notice any warnings either- good.

Some comments would help

gpp() would benefit with at least a line comment about its goal, expected input, output, etc.  Same for bin_add() - which should alert that the return pointer needs to be free'd.  This becomes even more important when the user only has access to the declaration in a .h file.

Commenting some of the block of code would help too.

When to shift

When there is not a final carry, code shifts Ol[].  As a final carry with this FP-like code is more rare, I'd shift when there is a carry.

Collapsing

With floating point strings, I expect code to drop trailing zero digits to the right of the '.'.  

Leading zero digits are possible based on input.  Perhaps eat those too with an early while (*a == '0') a++; and with b. - depends on coding goals though. 

Inconsistent bracket style

//                                v ?? 
pp[i] = pp[i] ? ll[i] - pp[i] : 0;}


Hopefully code is auto-formatted.

Inconsistent indentation

if((Ol[0] = '0' + xc) == '1') return Ol;
//  v   Why indented here?
    for (size_t i = 0; i &lt;= ML - lO + 1; ++i)
        Ol[i] = Ol[lO + i];


This implies code is not auto formatted.  Save time, and use auto-formatting. 

Terse digit like object names lose clarity

The short object names OO, lO, O, Ol, ll look too much like 00, 10, 0, 01, 11.  Consider more clear alternatives.

Other examples:
int xc as the carry bit looks more clear as int carry.
size_t ML more meaningful as MaxLength.

Input error detection

I'd suggest a separate bool bin_valid(const char *s) and let bin_add() assume  valid strings a,b.  This would help simplify - a NULL return would only indicate out-of-memory.

Good use of cast to ward off warnings

return n  ? (size_t)(n - s + 1) : 0;
//          ^------^


Misc.

ops[2], cc[2] could be local to for (size_t i = ML; i; --i) {

Good use of const.

Good use of size_t.

Personal preference: Consider char *Ol = calloc(ML + 2, sizeof *Ol);



Main

Do not assume EOF is -1

Simply test if the scanf() result is 2.

// while (scanf(" %80[0.1] %80[0.1]", a, b) &amp; 1 &lt;&lt; 1) {
while (scanf(" %80[0.1] %80[0.1]", a, b) == 2) {


ENOMEM

ENOMEM is not part of the standard C.

Test cases

Some specific example test cases would be useful.


  maybe even C90/C89


Not quite.

Lots of error: 'for' loop initial declarations are only allowed in C99 or C11 mode problems

warning: control reaches end of non-void function [-Wreturn-type]

error: redefinition of 'i'