Search code examples
cmemory-leaks

I can't understand why my Program is leaking memory


This is homework of one of my teachers on university.

The program is a "calculator" (just for +, - and *) for bigNumbers

I can't understand why the code is leaking memory; can someone help me?

I used a lot of AI to help but still no clue.

(not native English, sorry)

(EDITED code and question to make it clear)

INPUT EXAMPLE:

12

2

"-"

This approach has 2 issues; it still leaks 4 bytes, and every time I enter input in the terminal, it requires me to press Enter again to prompt for the next input.

Here's what Valgrind says:


==36491== 
==36491== HEAP SUMMARY:
==36491==     in use at exit: 4 bytes in 1 blocks
==36491==   total heap usage: 8 allocs, 7 frees, 2,096 bytes allocated
==36491== 
==36491== 4 bytes in 1 blocks are definitely lost in loss record 1 of 1
==36491==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==36491==    by 0x1093A1: scanBigNumber (a.c:60)
==36491==    by 0x109FC8: main (a.c:421)
==36491== 
==36491== LEAK SUMMARY:
==36491==    definitely lost: 4 bytes in 1 blocks
==36491==    indirectly lost: 0 bytes in 0 blocks
==36491==      possibly lost: 0 bytes in 0 blocks
==36491==    still reachable: 0 bytes in 0 blocks
==36491==         suppressed: 0 bytes in 0 blocks
==36491== 
==36491== For lists of detected and suppressed errors, rerun with: -s
==36491== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

CODE:


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


void limparBuffer()
{
    int c;
    while ((c = getchar()) != '\n' && c != EOF)
        ;

    // Adiciona verificação para tratar o caractere '\n' deixado pelo scanf
    if (c == '\n')
    {
        while ((c = getchar()) != EOF && c != '\n')
            ;
    }
}
typedef struct
{
    int *digitos;
    int ndigitos;
    char sinal;
} BigNumber;

BigNumber scanBigNumber()
{
    BigNumber inp;
    char buffer[1000];
    int l = 0;
    char aux;

    printf("Enter Number: ");
    scanf(" %c", &aux);

    if (aux == '-')
    {
        inp.sinal = aux;
    }
    else
    {
        inp.sinal = '+';
        buffer[l++] = aux - '0'; // Ajuste para lidar com o primeiro dígito
    }

    while (1)
    {
        scanf("%c", &aux);

        if (aux == '\n')
        {
            break;
        }
        buffer[l++] = aux - '0';
    }

    inp.digitos = malloc(l * sizeof(int));
    inp.ndigitos = l;

    for (int i = 0; i < inp.ndigitos; i++)
    {
        inp.digitos[i] = buffer[i];
    }

    return inp;
}

void addZeros(BigNumber *inp, int size)
{
    if (size <= inp->ndigitos)
    {
        return;
    }

    int *newDigits = calloc(size, sizeof(int));

    // Copia os dígitos existentes para a nova área alocada
    for (int i = 0; i < inp->ndigitos; i++)
    {
        newDigits[i + (size - inp->ndigitos)] = inp->digitos[i];
    }

    free(inp->digitos); // Libera a memória antiga

    inp->digitos = newDigits;
    inp->ndigitos = size;
}

int getGreaterArraySize(BigNumber *inp1, BigNumber *inp2)
{
    if (inp1->ndigitos > inp2->ndigitos)
        return inp1->ndigitos;
    if (inp1->ndigitos < inp2->ndigitos)
        return inp2->ndigitos;
    else
        return inp1->ndigitos;
}

void printArray(int *v, int n)
{
    int k = -1;

    for (int i = 0; i < n; i++)
    {
        if (v[i] != 0)
        {
            k = i;
            break;
        }
    }

    if (k == -1)
    {
        printf("0");
        return;
    }

    for (int i = k; i < n; i++)
    {
        printf("%d", v[i]);
    }
}

void inverterArray(int *arr, int tamanho)
{
    int inicio = 0;
    int fim = tamanho - 1;

    while (inicio < fim)
    {
        // Trocar os elementos no início e no final
        int temp = arr[inicio];
        arr[inicio] = arr[fim];
        arr[fim] = temp;

        // Avançar o ponteiro do início e retroceder o ponteiro do final
        inicio++;
        fim--;
    }
}

// =================================================================
// OPERAÇÕES
// =================================================================

BigNumber soma(BigNumber *inp1, BigNumber *inp2)
{
    int n2 = 0;
    int n = getGreaterArraySize(inp1, inp2);
    BigNumber temp;
    temp.digitos = calloc(n, sizeof(int));
    temp.ndigitos = n;
    if (inp1->ndigitos > inp2->ndigitos)
        addZeros(inp2, n);
    if (inp1->ndigitos < inp2->ndigitos)
        addZeros(inp1, n);
    int carry = 0;
    for (int i = n - 1; i >= 0; i--)
    {
        int sum = 0;
        if (i < inp1->ndigitos)
            sum += inp1->digitos[i];
        if (i < inp2->ndigitos)
            sum += inp2->digitos[i];
        sum += carry;
        temp.digitos[i] = sum % 10;
        carry = sum / 10;
        n2++;
    }

    if (carry > 0)
    {
        addZeros(&temp, n + 1);
        temp.digitos[0] = carry;
    }
    return temp;
}

BigNumber subtract(BigNumber *inp1, BigNumber *inp2)
{
    int n = getGreaterArraySize(inp1, inp2);
    BigNumber temp;
    temp.digitos = calloc(n, sizeof(int));
    temp.ndigitos = n;
    int borrow = 0;

    if (inp1->ndigitos > inp2->ndigitos)
        addZeros(inp2, n);
    else if (inp1->ndigitos < inp2->ndigitos)
        addZeros(inp1, n);

    for (int i = n - 1; i >= 0; i--)
    {
        int dif = inp1->digitos[i] - inp2->digitos[i] - borrow;
        if (dif < 0)
        {
            dif += 10; // Change to base decimal
            borrow = 1;
        }
        else
            borrow = 0;
        temp.digitos[i] = dif;
    }

    // Libera a memória dos digitos de inp1 e inp2
    free(inp1->digitos);
    free(inp2->digitos);

    // Ajusta ndigitos de temp para remover zeros à esquerda
    while (temp.ndigitos > 1 && temp.digitos[0] == 0)
    {
        temp.ndigitos--;
        memmove(temp.digitos, temp.digitos + 1, temp.ndigitos * sizeof(int));
    }

    return temp;
}

BigNumber multiply(BigNumber *num1, BigNumber *num2)
{

    int i, j, carry;
    BigNumber temp;
    temp.digitos = calloc(num1->ndigitos + num2->ndigitos, sizeof(int));
    temp.ndigitos = num1->ndigitos + num2->ndigitos;

    for (i = 0; i < num1->ndigitos; i++)
    {
        carry = 0;
        int digit1 = num1->digitos[num1->ndigitos - 1 - i];

        for (j = 0; j < num2->ndigitos; j++)
        {
            int digit2 = num2->digitos[num2->ndigitos - 1 - j];

            int sum = digit1 * digit2 + temp.digitos[i + j] + carry;
            carry = sum / 10;
            temp.digitos[i + j] = sum % 10;
        }

        if (carry > 0)
        {
            temp.digitos[i + num2->ndigitos] += carry;
        }
    }

    inverterArray(temp.digitos, temp.ndigitos);

    // int pos = num1->ndigitos + num2->ndigitos - 1;
    // while (pos >= 0 && temp.digitos[pos] == 0)
    // {
    //     pos--;
    // }

    // // Print the result
    // printf("\n\n\n\n\nResult of multiplication: ");
    // for (; pos >= 0; pos--)
    // {
    //     printf("%d", temp.digitos[pos]);
    // }
    // printf("\n");

    return temp;
}

// =================================================================
// =================================================================
// =================================================================

int comparaModulo(BigNumber inp1, BigNumber inp2)
{
    if (inp1.ndigitos > inp2.ndigitos)
        return 1;

    else if (inp1.ndigitos < inp2.ndigitos)
        return 2;

    else if (inp1.ndigitos == inp2.ndigitos)
        for (int i = 0; i < inp1.ndigitos; i++)
        {
            if (inp1.digitos[i] > inp2.digitos[i])
                return 1;
            else if (inp1.digitos[i] < inp2.digitos[i])
                return 2;
            else if (inp1.digitos[i] == inp2.digitos[i])
                continue;
        }

    return 1;
}

BigNumber operationHandler(BigNumber inp1, BigNumber inp2, char signal)
{
    // =================================================================
    // SOMA
    // =================================================================

    BigNumber inpRes;
    int maiorNum = comparaModulo(inp1, inp2);
    if (signal == '+')
    {
        // 8 + 4
        if (inp1.sinal == '+' && inp2.sinal == '+')
        {
            inpRes = soma(&inp1, &inp2);
            inpRes.sinal = '+';
        }
        else if (inp1.sinal == '+' && inp2.sinal == '-')
        {
            if (maiorNum == 1)
            // 8+ (-4)
            {
                inpRes = subtract(&inp1, &inp2);
                inpRes.sinal = '+';
            }
            else if (maiorNum == 2)
            // 4+ (-8)
            {
                inpRes = subtract(&inp2, &inp1);
                inpRes.sinal = '-';
            }
        }
        else if (inp1.sinal == '-' && inp2.sinal == '+')
        {
            if (maiorNum == 1)
            // - 8 + 4
            {
                inpRes = subtract(&inp1, &inp2);
                inpRes.sinal = '-';
            }
            else if (maiorNum == 2)
            // -4 + 8
            {
                inpRes = subtract(&inp2, &inp1);
                inpRes.sinal = '+';
            }
        }
        else if (inp1.sinal == '-' && inp2.sinal == '-')
        {
            //-8 + (-4)
            inpRes = soma(&inp1, &inp2);
            inpRes.sinal = '-';
        }
    }

    // =================================================================
    // SUBTRAÇÃO
    // =================================================================

    else if (signal == '-')
    {
        if (inp1.sinal == '+' && inp2.sinal == '+')
        {
            if (maiorNum == 1)
            {
                inpRes = subtract(&inp1, &inp2);
                inpRes.sinal = '+';
            }
            else if (maiorNum == 2)
            {
                inpRes = subtract(&inp2, &inp1);
                inpRes.sinal = '-';
            }
        }

        else if (inp1.sinal == '+' && inp2.sinal == '-')
        {
            inpRes = soma(&inp1, &inp2);
            inpRes.sinal = '+';
        }

        else if (inp1.sinal == '-' && inp2.sinal == '+')
        {
            inpRes = soma(&inp2, &inp1);
            inpRes.sinal = '-';
        }

        else if (inp1.sinal == '-' && inp2.sinal == '-')
        {
            if (maiorNum == 1)
            {
                inpRes = subtract(&inp1, &inp2);
                inpRes.sinal = '-';
            }
            else if (maiorNum == 2)
            {
                inpRes = subtract(&inp2, &inp1);
                inpRes.sinal = '+';
            }
        }
    }

    // =================================================================
    // MULTIPLICAÇÃO
    // =================================================================

    else if (signal == '*')
    {
        inpRes = multiply(&inp1, &inp2);
        if ((inp1.sinal == '+' && inp2.sinal == '-') || (inp1.sinal == '-' && inp2.sinal == '+'))
            inpRes.sinal = '-';
        else
            inpRes.sinal = '+';
    }

    return inpRes;
}

int main()
{
    // Vetor para armazenar os resultados
    BigNumber *resultados = NULL;
    int numResultados = 0;

    while (1)
    {
        // Leitura da primeira entrada
        BigNumber inp1 = scanBigNumber();
        getchar();

        // Verifica se o usuário deseja encerrar o programa
        if (inp1.digitos[0] == 1 && inp1.ndigitos == 1 && inp1.sinal == '-')
            break;

        // Leitura da segunda entrada
        BigNumber inp2 = scanBigNumber();
        getchar();

        // Leitura do sinal
        char operacao;
        scanf(" %c", &operacao);
        getchar();

        // Executa a operação e obtém o resultado
        BigNumber resultado = operationHandler(inp1, inp2, operacao);

        // Armazena o resultado no vetor dinâmico
        numResultados++;
        resultados = realloc(resultados, numResultados * sizeof(BigNumber));
        resultados[numResultados - 1] = resultado;
    }

    // Imprime os resultados
    for (int i = 0; i < numResultados; i++)
    {
        printArray(resultados[i].digitos, resultados[i].ndigitos);
        printf("\n");
    }

    // Libera a memória alocada para os resultados
    for (int i = 0; i < numResultados; i++)
    {
        free(resultados[i].digitos);
    }

    // Libera a memória alocada para os resultados
    free(resultados);

    return 0;
}


Solution

    1. valgrind is unappy with the input "1\n" "10\n" "+\n". scanBigNumber() allocates inp1.digitos say with address a1 then operationHandler() is called with the two numbers by value. soma() in turn calls addZeros() which free(a1) and allocate a new array inp1.digitos with address a2. So far so good. Upon return to main() we double free(a1) (very bad) and leak a2. The fix is to call operationHandler() with the address of the two numbers.

      comparaModulo() was also changed to take the address of the numbers but this merely for consistency.

      Another design choice is for main() to transfer ownership of the two numbers (by address or value) when calling operationHandler(). operationHandler() is now responsible for freeing a2 and upon return, main() should consider the two values invalid (and not read or free the array). This is somewhat unusual so you would want to document that.

    2. valgrind is unhappy with an invalid operator. For example with the the input "1\n" "1\n" "x\n". The question does not indicate what should happen in that case. I suggest modifying the operationHandler() interface to support returning an error or not call it at all:

          if(strchr("+-*", sinal)) {
              res = realloc(res, sizeof *res * (n + 1));
              res[n] = operationHandler(inp1, inp2, sinal);
              n++;
          }
      
    3. inp1.digitos[0] == 1 && inp1.sinal == '-' && inp1.ndigitos == 1 "looks" unsafe. You want to check inp1.ndigitos before accessing the corresponding array. If you guarantee that scanBigNumber() always return a number with at least 1 digit (you probably want to) then it's ok but I would still swap the order.

    4. In main() after the first iteration of the loop the input buffer will contain the trailing \n from reading the operator so the BigNumber inp1 = scanBigNumber() will always read the empty string. You need to flush that with limparBuffer() but it should handle EOF as well:

      int limparBuffer() {
         for(;;) {
             int c = getchar();
             if(c == EOF || c == '\n')
                return c;
         }
      }
      
      // ...
          scanf(" %c", &sinal);
          if(limparBuffer() == EOF) {
              free(inp1.digitos);
              free(inp2.digitos);
              break;
          }
      
    5. (Not fixed) soma(), subtract(), and multiply() don't set temp.sinal to either + or -.

    6. s = realloc(s, ...) will leak memory if realloc() fails. Use temporary variable before overwriting s:

      char *tmp = realloc(s, l);
      if(!tmp) {
        // handle error
      }
      s = tmp;
      
    7. Check the return value of malloc(), realloc() and calloc().

    8. In main() you haveint p = 0; while(!p) {} but you never change p. Eliminate the variable p and just use an infinite loop for(;;) {} instead.

    9. In main() you do:

      BigNumber *res = NULL;  // Inicializa o ponteiro para evitar problemas com free() posterior
      res = malloc(sizeof(BigNumber));
      

      Why assign NULL to this variable when you immediately overwrite it? You allocate an array with 1 element before the loop, then in the first iteration of the following loop you allocate l=1 (i.e. no-op). Just leave it as and realloc() will do the right thing:

      BigNumber *res = NULL;
      
    10. Use integer constants '0' instead of 48.

    11. (Not fixed) addZeros() creates a new array newDigitos but you could just resize inp->ndigitos with realloc() then memmove() the digits diff positions then zero the first diff digits to 0 as you do (or with memset()).

    12. (Not completely fixed) Prefer using variables to sizeof instead of types. So temp.digitos = calloc(n, sizeof *temp.digitos) instead of temp.digitos = calloc(n, sizeof(int)). It leads to less duplication and in particular would make the next suggestion a 1 line change.

    13. (Not fixed) int *digitos is used to store digits as binary (0 through 9). Consider using a uint8_t (1 byte) instead of an int (4? bytes).

    14. (Not fixed) char signal is used to store either + or - (i.e. 1 bit of information). Consider reworking it to bool negative. calloc() will by default create a positive value (see above), and you communicate that nothing funky is going on here. You may or many not care about +0 vs -0.

    15. (Not fixed) operationHandler() have a lot of duplicated code. The + and - operators are handled very similarly. Within each operation each of operator cases are also very similar. I suggest you combine soma() and subtract() and figure out how they that handle those cases internally. You can use usual math tricks like sum(a, b) == sum(b, a), sum(a, -b) == diff(a, b) etc. With code that might be wrapper a wrapper function or recursive calls with switched arguments.

    16. (Not fixed) scanBigNumber(): you read the input into aux then copy that into a resizing char * array finally to map that into int * array. I suggest you read into aux then convert it into a inp.digitos[l] = aux - '0'; entry as you go (i.e. skip the array s). Initialize inp.digitos = NULL then realloc() as you process each number (l=0, l=1 etc). Just remember the value of malloc(0) is undefined so it may be NULL so you probably still want to ensure that there is at least one digit with value 0.

    17. (Not fixed) scanBigNumber(): validate aux. What should the return value be for "", +1, abc?

    18. (Not fixed) Check the return value of all I/O operations like scanf(). Otherwise you may be operating on uninitialized variables.

    19. (Not fixed) scanBigNumber(): Consider reading a line then process the string. fgets() requires a preallocated string with a maximum string length while getline() will allocate the string for you. You can also use scanf() but you remember to use a maximum field width to indicate the maximum string length you want to support. Reading a line allows you extract what you understand and ignore the rest (or be strict). This means you always make progress opposed trying to read a number and the input buffer has a letter. Separate I/O from parsing makes the complicated part, parsing, simpler. You may need to consider the entire string before you can process it, say, you want to support scientific notation "1e-2". You don't know till you read the "e" that this is not just a regular number. Maybe you want to support constants, say, "pi" but you only know at end of string. There are libraries (like readline) that allow user to edit a line so you don't lose all the input if you had a typo on the first digit.

    Here is the resulting code:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    typedef struct {
        int *digitos;
        int ndigitos;
        char sinal;
    } BigNumber;
    
    BigNumber scanBigNumber() {
        BigNumber inp;
        int l = 1;
        char *s = malloc(l);
        if(!s) {
            fprintf(stderr, "malloc failed\n");
            exit(1);
        }
        char aux;
    
        printf("Enter Number: ");
        scanf("%c", &aux);
        if (aux == '-') {
            inp.sinal = aux;
            scanf("%c", &aux);
        } else
            inp.sinal = '+';
    
        while (aux != '\n') {
            l++;
            char *tmp = realloc(s, l);
            if(!tmp) {
                fprintf(stderr, "malloc failed\n");
                exit(1);
            }
            s = tmp;
            s[l - 2] = aux;
            scanf("%c", &aux);
        }
    
        inp.digitos = malloc(sizeof *inp.digitos * (l - 1));
        if(!inp.digitos) {
            fprintf(stderr, "malloc failed\n");
            exit(1);
        }
        inp.ndigitos = l - 1;
        for (int i = 0; i < inp.ndigitos; i++)
            inp.digitos[i] = s[i] - '0';
    
        free(s);
        return inp;
    }
    
    void addZeros(BigNumber *inp, int size) {
        if (size <= inp->ndigitos) return;
        int *newDigitos = malloc(sizeof *newDigitos * size);
        if(!newDigitos) {
            fprintf(stderr, "malloc failed\n");
            exit(1);
        }
        int diff = size - inp->ndigitos;
        for (int i = 0; i < diff; i++)
            newDigitos[i] = 0;
        for (int i = 0; i < inp->ndigitos; i++)
            newDigitos[i + diff] = inp->digitos[i];
        free(inp->digitos);
        inp->digitos = newDigitos;
        inp->ndigitos = size;
    }
    
    int getGreaterArraySize(BigNumber *inp1, BigNumber *inp2) {
        if (inp1->ndigitos > inp2->ndigitos)
            return inp1->ndigitos;
        if (inp1->ndigitos < inp2->ndigitos)
            return inp2->ndigitos;
        return inp1->ndigitos;
    }
    
    void printArray(int *v, int n)
    {
        int isZero = 0, k = -1;
        for (int i = 0; i < n; i++)
            if (v[i] != 0)
            {
                isZero = 1;
                k = i;
                break;
            }
    
        if (k == -1)
        {
            printf("0");
            return;
        }
    
        if (!isZero)
            for (int i = 0; i < n; i++)
                printf("%d", v[i]);
        else
            for (int i = k; i < n; i++)
                printf("%d", v[i]);
    }
    
    void inverterArray(int *arr, int tamanho)
    {
        int inicio = 0;
        int fim = tamanho - 1;
    
        while (inicio < fim)
        {
            // Trocar os elementos no início e no final
            int temp = arr[inicio];
            arr[inicio] = arr[fim];
            arr[fim] = temp;
    
            // Avançar o ponteiro do início e retroceder o ponteiro do final
            inicio++;
            fim--;
        }
    }
    
    // =================================================================
    // OPERAÇÕES
    // =================================================================
    
    BigNumber soma(BigNumber *inp1, BigNumber *inp2)
    {
        int n = getGreaterArraySize(inp1, inp2);
        int n2 = 0;
        BigNumber temp;
        temp.digitos = calloc(n, sizeof(int));
        temp.ndigitos = n;
        if (inp1->ndigitos > inp2->ndigitos)
            addZeros(inp2, n);
        if (inp1->ndigitos < inp2->ndigitos)
            addZeros(inp1, n);
        int carry = 0;
        for (int i = n - 1; i >= 0; i--) {
            int sum = 0;
            if (i < inp1->ndigitos)
                sum += inp1->digitos[i];
            if (i < inp2->ndigitos)
                sum += inp2->digitos[i];
            sum += carry;
            temp.digitos[i] = sum % 10;
            carry = sum / 10;
            n2++;
        }
        if (carry > 0) {
            addZeros(&temp, n + 1);
            temp.digitos[0] = carry;
        }
        return temp;
    }
    
    BigNumber subtract(BigNumber *inp1, BigNumber *inp2) {
        int n = getGreaterArraySize(inp1, inp2);
        BigNumber temp;
        temp.digitos = calloc(n, sizeof *temp.digitos);
        temp.ndigitos = n;
        int borrow = 0;
    
        if (inp1->ndigitos > inp2->ndigitos)
            addZeros(inp2, n);
        else if (inp1->ndigitos < inp2->ndigitos)
            addZeros(inp1, n);
    
        for (int i = n - 1; i >= 0; i--) {
            int dif = inp1->digitos[i] - inp2->digitos[i] - borrow;
            if (dif < 0) {
                dif += 10; // Change to base decimal
                borrow = 1;
            } else
                borrow = 0;
            temp.digitos[i] = dif;
        }
    
        return temp;
    }
    
    BigNumber multiply(BigNumber *num1, BigNumber *num2)
    {
    
        int i, j, carry;
        BigNumber temp;
        temp.digitos = calloc(num1->ndigitos + num2->ndigitos, sizeof(int));
        temp.ndigitos = num1->ndigitos + num2->ndigitos;
    
        for (i = 0; i < num1->ndigitos; i++) {
            carry = 0;
            int digit1 = num1->digitos[num1->ndigitos - 1 - i];
    
            for (j = 0; j < num2->ndigitos; j++)
            {
                int digit2 = num2->digitos[num2->ndigitos - 1 - j];
    
                int sum = digit1 * digit2 + temp.digitos[i + j] + carry;
                carry = sum / 10;
                temp.digitos[i + j] = sum % 10;
            }
    
            if (carry > 0)
            {
                temp.digitos[i + num2->ndigitos] += carry;
            }
        }
    
        inverterArray(temp.digitos, temp.ndigitos);
        return temp;
    }
    
    int limparBuffer() {
        for(;;) {
            int c = getchar();
            if(c == EOF || c == '\n')
                return c;
        }
    }
    
    int comparaModulo(BigNumber *inp1, BigNumber *inp2) {
        if (inp1->ndigitos > inp2->ndigitos)
            return 1;
        if (inp1->ndigitos < inp2->ndigitos)
            return 2;
        for (int i = 0; i < inp1->ndigitos; i++) {
            if (inp1->digitos[i] > inp2->digitos[i])
                return 1;
            if (inp1->digitos[i] < inp2->digitos[i])
                return 2;
        }
        return 1;
    }
    
    BigNumber operationHandler(BigNumber *inp1, BigNumber *inp2, char signal) {
        // =================================================================
        // SOMA
        // =================================================================
        BigNumber inpRes;
        int maiorNum = comparaModulo(inp1, inp2);
        if (signal == '+') {
            // 8 + 4
            if (inp1->sinal == '+' && inp2->sinal == '+')
            {
                inpRes = soma(inp1, inp2);
                inpRes.sinal = '+';
            }
            else if (inp1->sinal == '+' && inp2->sinal == '-')
            {
                if (maiorNum == 1)
                    // 8+ (-4)
                {
                    inpRes = subtract(inp1, inp2);
                    inpRes.sinal = '+';
                }
                else if (maiorNum == 2)
                    // 4+ (-8)
                {
                    inpRes = subtract(inp2, inp1);
                    inpRes.sinal = '-';
                }
            }
            else if (inp1->sinal == '-' && inp2->sinal == '+')
            {
                if (maiorNum == 1)
                    // - 8 + 4
                {
                    inpRes = subtract(inp1, inp2);
                    inpRes.sinal = '-';
                }
                else if (maiorNum == 2)
                    // -4 + 8
                {
                    inpRes = subtract(inp2, inp1);
                    inpRes.sinal = '+';
                }
            }
            else if (inp1->sinal == '-' && inp2->sinal == '-')
            {
                //-8 + (-4)
                inpRes = soma(inp1, inp2);
                inpRes.sinal = '-';
            }
        }
    
        // =================================================================
        // SUBTRAÇÃO
        // =================================================================
    
        else if (signal == '-')
        {
            if (inp1->sinal == '+' && inp2->sinal == '+')
            {
                if (maiorNum == 1)
                {
                    inpRes = subtract(inp1, inp2);
                    inpRes.sinal = '+';
                }
                else if (maiorNum == 2)
                {
                    inpRes = subtract(inp2, inp1);
                    inpRes.sinal = '-';
                }
            }
    
            else if (inp1->sinal == '+' && inp2->sinal == '-')
            {
                inpRes = soma(inp1, inp2);
                inpRes.sinal = '+';
            }
    
            else if (inp1->sinal == '-' && inp2->sinal == '+')
            {
                inpRes = soma(inp2, inp1);
                inpRes.sinal = '-';
            }
    
            else if (inp1->sinal == '-' && inp2->sinal == '-')
            {
                if (maiorNum == 1)
                {
                    inpRes = subtract(inp1, inp2);
                    inpRes.sinal = '-';
                }
                else if (maiorNum == 2)
                {
                    inpRes = subtract(inp2, inp1);
                    inpRes.sinal = '+';
                }
            }
        }
    
        // =================================================================
        // MULTIPLICAÇÃO
        // =================================================================
    
        else if (signal == '*')
        {
            inpRes = multiply(inp1, inp2);
            if ((inp1->sinal == '+' && inp2->sinal == '-') || (inp1->sinal == '-' && inp2->sinal == '+'))
                inpRes.sinal = '-';
            else
                inpRes.sinal = '+';
        }
        return inpRes;
    }
    
    int main(void) {
        BigNumber *res = NULL;
        int n = 0;
        for(;;) {
            BigNumber inp1 = scanBigNumber();
            if (inp1.ndigitos == 1 && inp1.digitos[0] == 1 && inp1.sinal == '-') {
                free(inp1.digitos);
                break;
            }
            BigNumber inp2 = scanBigNumber();
    
            char sinal;
            scanf(" %c", &sinal);
            if(limparBuffer() == EOF) {
                free(inp1.digitos);
                free(inp2.digitos);
                break;
            }
            if(strchr("+-*", sinal)) {
                BigNumber *tmp = realloc(res, sizeof *res * (n + 1));
                if(!tmp) {
                    fprintf(stderr, "malloc failed\n");
                    exit(1);
                }
                res = tmp;
                res[n] = operationHandler(&inp1, &inp2, sinal);
                n++;
            }
            free(inp1.digitos);
            free(inp2.digitos);
        }
        for (int i = 0; i < n; i++) {
            printf("\nCaso de teste %d\n", i + 1);
            if (res[i].sinal == '-')
                printf("-");
            printArray(res[i].digitos, res[i].ndigitos);
            printf("\n");
            free(res[i].digitos);
        }
        free(res);
        return 0;
    }
    

    and a valgrind session:

    Enter Number: 1
    Enter Number: 10
    +
    Enter Number: -1
    
    Caso de teste 1
    11
    ==422278== 
    ==422278== HEAP SUMMARY:
    ==422278==     in use at exit: 0 bytes in 0 blocks
    ==422278==   total heap usage: 15 allocs, 15 frees, 2,108 bytes allocated
    ==422278== 
    ==422278== All heap blocks were freed -- no leaks are possible