Search code examples
cbignum

How to sum big numbers


I am trying to put together a program, which would sum extremely big numbers. Unfortunately I am stuck - it doesn't return any result, even if I comment out malloc & realloc (where the compiler seems to be failing). Any ideas? My code:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int i,j,x;
char *actual = NULL;
char *sum = NULL;

void init () {
    sum = malloc(500);
    actual = malloc(500);
}

void calculate (char *argv[]) {
    int rest = 0;
    actual = *argv;
    actual = realloc(actual, strlen(*argv));
    if (strlen(actual) > strlen(sum)) {
    sum = realloc(sum, strlen(actual) + 1);
    } else sum = realloc(sum, strlen(sum) + 1);
    long b;
    for (b = 1; b < strlen(actual); b++) {
        rest = rest + atoi(&sum[strlen(sum) - b]) + atoi(&actual[strlen(actual) - b]);
        if (rest > 9) {
            sum[strlen(sum) - b] = rest - 10;
            rest = 1;   // carrying over 1
        } else {
            sum[strlen(sum) - b] = rest;
            rest = 0;
        }
    }
}

void writeResult () {
    printf("VYPIS - sum:");
    printf("strlen souctu je: %lu\n",strlen(sum));
    long c;
    for (c = 0; c <= strlen(sum); c++) {
        printf("%c",sum[c]);
    }
    printf("\n");
}

void emtpy () {
    free(actual);
    free(sum);
}

int main(int argc, char * argv[]) {
    init();
    for (i = 1; i < argc; i++) {
        calculate(&argv[i]);
    }
    writeResult();
    emtpy();
    return 0;
}

Solution

  • Your code is too complicated and it has several problems:

    • You cannot use atoi to convert characters into values, it can be done very simply this way: int value = c - '0'.
    • You should not modify the strings from the argv array. Especially you cannot reallocate them. This invokes undefined behaviour.
    • Always allocate or reallocate 1 more byte than the length of the string you mean to store in the resulting array for the final '\0' and remember to set this final byte.
    • You should compute the addition from right to left, as you do by hand, keeping track of the carry from one digit to the next, potentially adding an extra leading digit.

    Here is a much simplified version for your problem that shows how to deal with large numbers in base 10:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static char *bigsum(char *res, const char *arg) {
        size_t pos1, pos2, pos3, len3;
        unsigned int carry;
    
        pos1 = strlen(res);
        pos2 = strlen(arg);
        len3 = pos3 = (pos1 < pos2) ? pos2 + 1 : pos1 + 1;
        /* reallocate the result array to one more than the larger operand */
        res = realloc(res, len3 + 1);
        /* set the terminating '\0' at the end of result */
        res[pos3] = '\0';
        for (carry = 0; pos3 > 0; carry /= 10) {
            if (pos1 > 0) carry += res[--pos1] - '0';
            if (pos2 > 0) carry += arg[--pos2] - '0';
            res[--pos3] = '0' + carry % 10;
        }
        while (res[0] == '0' && len3 > 1) {
            /* normalize the result: remove redundant initial zeroes */
            memmove(res, res + 1, len3--);
        }
        return res;
    }
    
    int main(int argc, const char **argv) {
        /* initialize the result to "0" as an allocated string */
        char *result = strcpy(malloc(2), "0");
        int i;
    
        for (i = 1; i < argc; i++) {
            result = bigsum(result, argv[i]);
        }
        printf("%s\n", result);
        return 0;
    }