我不明白为什么我的程序会泄漏内存

问题描述 投票:0回答:1

这是我大学一位老师的作业。

我不明白为什么代码会泄漏内存;有人可以帮助我吗?

我使用了很多人工智能来帮助,但仍然没有任何线索。

(不是母语英语,抱歉)

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

typedef struct
{
    int *digitos;
    int ndigitos;
    char sinal;
} BigNumber;

BigNumber scanBigNumber()
{
    BigNumber inp;
    char *s = malloc(sizeof(char));
    int l = 1;
    char aux;

    printf("Enter Number: ");
    scanf("%c", &aux);
    if (aux == '-')
    {
        inp.sinal = aux;
        scanf("%c", &aux);
    }
    else
        inp.sinal = '+';

    while (aux != '\n')
    {
        l++;
        s = realloc(s, l * sizeof(char));
        s[l - 2] = aux;
        scanf("%c", &aux);
    }

    inp.digitos = malloc((l - 1) * sizeof(int));
    inp.ndigitos = l - 1;
    for (int i = 0; i < inp.ndigitos; i++)
        inp.digitos[i] = s[i] - 48;

    free(s);
    return inp;
}

void addZeros(BigNumber *inp, int size)
{
    if (size <= inp->ndigitos)
    {
        return;
    }
    int *newDigitos = malloc(size * sizeof(int));
    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;
    else
        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 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)); // Correct the size to 'n'
    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;
    }

    // // Remove leading zeros
    // int firstNonZero = 0;
    // while (firstNonZero < n && temp.digitos[firstNonZero] == 0)
    // {
    //     firstNonZero++;
    // }

    // // If all digits are zero, keep a single zero
    // if (firstNonZero == n)
    // {
    //     free(temp.digitos);
    //     temp.digitos = calloc(1, sizeof(int));
    //     temp.ndigitos = 1;
    // }
    // else
    // {
    //     // Adjust the size and digits if there were leading zeros
    //     int newSize = n - firstNonZero;
    //     int *newDigits = malloc(newSize * sizeof(int));
    //     for (int i = firstNonZero; i < n; i++)
    //     {
    //         newDigits[i - firstNonZero] = temp.digitos[i];
    //     }
    //     free(temp.digitos);
    //     temp.digitos = newDigits;
    //     temp.ndigitos = newSize;
    // }

    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;
}

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

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

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()
{
    // =================================================================
    // Teste de operações
    // =================================================================

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

    while (!p)
    {
        BigNumber inp1, inp2;
        char sinal;
        
        inp1 = scanBigNumber();
        if (inp1.digitos[0] == 1 && inp1.sinal == '-' && inp1.ndigitos == 1)
        {
            free(inp1.digitos);  // Libera memória antes de encerrar o loop
            break;
        }

        inp2 = scanBigNumber();
        scanf(" %c", &sinal);  // Adiciona um espaço antes do %c para consumir espaços em branco

        res = realloc(res, (n + 1) * sizeof(BigNumber));
        res[n] = operationHandler(inp1, inp2, sinal);

        free(inp1.digitos);
        free(inp2.digitos);

        // limparBuffer();
        n++;
    }

    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);  // Libera a memória para cada resultado
    }

    free(res);  // Libera o array de resultados

    return 0;
}

该程序是一个“计算器”(仅适用于

+
-
*
)并且正在泄漏内存,可能在“添加零”功能中(我不太明白Valgrind告诉我的内容) ).

c memory-leaks
1个回答
0
投票
  1. 我唯一能让 valgrind 抱怨的是无效的操作符。例如,输入

    "1\n" "1\n" "x"
    。该问题并未表明在这种情况下会发生什么。我建议修改
    operationHandler()
    接口以支持返回错误或根本不调用它:

         if(strchr("+-*", sinal)) {
             res = realloc(res, sizeof *res * (n + 1));
             res[n] = operationHandler(inp1, inp2, sinal);
             n++;
         }
    
  2. 在循环第一次迭代之后的

    main()
    中,输入缓冲区将包含读取运算符的试验
    \n
    ,因此
    BigNumber inp1 = scanBigNumber()
    将始终读取空字符串。您需要用
    limparBuffer()
    刷新它,但它也应该处理 EOF:

    int limparBuffer() {
        for(;;) {
            int c =  getchar();
            if(c == EOF || c == '\n')
               return c;
        }
    }
    
    // ...
    
         if(limparBuffer() == EOF) {
             free(inp1.digitos);
             free(inp2.digitos);
             break;
         }
    
  3. soma()
    subtract()
    multiply()
    不设置
    temp.sinal

© www.soinside.com 2019 - 2024. All rights reserved.