-3

久しぶりに C で動的メモリ割り当てをいじっていて、メモリ リークの問題に遭遇しました...どこに問題があるのか​​わかりません。誰でも助けてもらえますか?

EDIT2:プログラムは非常に大きな数でも問題なく動作し、非常に高速です:)プログラム構造を変更し、char文字列だけでなく構造体を使用することにしました。メモリ リークがあってはなりません (valgrind でテスト済み)。

現在のコード:

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

typedef struct binary{
    char * number;
    size_t length;
}Tbinary;

//exterminate leading zeros
size_t exterminate(char * bin, size_t length){
char * pch = NULL;
long position = 0;

pch = strchr(bin, '1');
if(pch==NULL){
    bin[1] = '\0';
    length = 2;
}
else{
    position = pch-bin;
    strcpy(bin, pch);
}

return (length-position);
}

int binaryAdd(Tbinary first, Tbinary second){
int a=0, b=0, sum=0, carry=0;
size_t index = first.length;
first.number[first.length] = '\0';

while((first.length != 0) || (carry != 0)){
    if(first.length>1) a= first.number[first.length-2]-'0';
    else a = 0;
    if(second.length>1) b= second.number[second.length-2]-'0';
    else b = 0;
    sum = (a+b+carry)%2;
    first.number[first.length-1] = (sum)+'0';
    carry = (a+b+carry)/2;
    if(first.length >0)first.length--;
    if(second.length >0)second.length--;
}

exterminate(first.number,index);

printf("Sum: %s\n", first.number);
return EXIT_SUCCESS;
}

int get_number(Tbinary *bin_addr){
char * tmp, * bin;
char ch=1;
int size = 1, index = 0;
bin = bin_addr->number;

while(ch){
    ch = getc(stdin);

    if((ch == '\n') || (ch == ' ')) ch = '\0';

    if((ch-'0' != 0) && (ch-'0' != 1) && (ch != '\0')) return EXIT_FAILURE;

    if (size-1 <=index){
        size += 5;
        tmp = (char *)realloc(bin, size*sizeof(char));
        if(tmp == NULL){
            return EXIT_FAILURE;
        }
        bin = tmp;
        bin_addr->number = bin;
    }
    bin[index++] = ch;
}

bin_addr->length = index;
bin_addr->length = exterminate(bin_addr->number, bin_addr->length);

return EXIT_SUCCESS;
} 

int main (void)
{
Tbinary bin1 = {bin1.number = NULL, bin1.length = 0};
Tbinary bin2 = {bin2.number = NULL, bin2.length = 0};

//allocate space for first number
bin1.number = (char *)malloc(sizeof(char));
if(bin1.number == NULL)
    return EXIT_FAILURE;

//allocate space for second number
bin2.number = (char *)malloc(sizeof(char));
if(bin2.number == NULL){
    free(bin1.number);
    return EXIT_FAILURE;
}

printf("Enter two binary numbers:\n");

//number1 load
if(get_number(&bin1) != EXIT_SUCCESS){
    free(bin1.number);
    free(bin2.number);
    printf("Invalid input.\n");
    return EXIT_FAILURE;
}

//number2 load
if(get_number(&bin2) != EXIT_SUCCESS){
    free(bin1.number);
    free(bin2.number);
    printf("Invalid input.\n");
    return EXIT_FAILURE;
}

//add the two numbers
if(bin1.length >= bin2.length){
    if(binaryAdd(bin1, bin2) != EXIT_SUCCESS){
        free(bin1.number);
        free(bin2.number);
        printf("Invalid input.\n");
        return EXIT_FAILURE;
    }
}
else{
    if(binaryAdd(bin2, bin1) != EXIT_SUCCESS){
        free(bin1.number);
        free(bin2.number);
        printf("Invalid input.\n");
        return EXIT_FAILURE;
    }
}

free(bin1.number);
free(bin2.number);
return EXIT_SUCCESS;
}
4

2 に答える 2

1

binaryAdd()では、realloc()がnullを返す場合だけでなく、すべての場合にrealloc()の後に合計を解放する必要があります。get_number()でも同じです。a = (int)strlen(first);strlen()の戻り値をintにキャストする理由についてはどうでしょうか。また、割り当て関数のリターンをキャストしないでください。

于 2012-11-12T23:40:08.317 に答える
0

sizeand のindex関係に 1 つずつずれているエラーがあります。

    if (size <=index){
        size += 5;
        tmp = (char *)realloc(sum, size*sizeof(char));
        if(tmp == NULL){
            free(sum);  // free memory to avoid leak
            return EXIT_FAILURE;
        }
        sum = tmp;
    }
    for(int i=index; i>0; i--){
        sum[i] = sum[i-1];
    }
    sum[0] = num%2+'0';
    carry = num/2;
    index++;
}
sum[index] = '\0';

最後の反復に入ったときにindex == size-1、割り当てられたメモリの外側に書き込んでいる場合。無害な場合もあれば、重要なデータを上書きしてもすぐにクラッシュしない場合もあれば、すぐにクラッシュする場合もあります (通常、境界外アクセスがページ境界を越える場合)。テストを に変更しsize - 1 <= indexます。

ではget_number、必要に応じてreallocのローカル コピーをchar*入力バッファに変更するだけなので、場所が変更された場合、 のポインタはmain無効なメモリを指します。そのはず

int get_number(char **bin_addr){
    char * tmp, bin = *bin_addr;
    char ch=1;
    size_t size = 1, index = 0;

    while(ch){
        ch = getc(stdin);

        if((ch == '\n') || (ch == ' ')){
            ch = '\0';
        }

        if((ch-'0' != 0) && (ch-'0' != 1) && (ch != '\0')){
            return EXIT_FAILURE;
        }

        if (size-1 <=index){
            size += 5;
            tmp = (char *)realloc(bin, size*sizeof(char));
            if(tmp == NULL){
                return EXIT_FAILURE;
            }
            bin = tmp;
            *bin_addr = bin;  // let the pointer always point to the real block
        }
        bin[index++] = ch;
    }
    return EXIT_SUCCESS;
}

で呼び出さget_number(&bin1);mainます。

于 2012-11-13T00:41:52.707 に答える