大整数程序。 X乘法后停止

时间:2012-06-02 20:35:40

标签: c memory integer multiplication

我在C中制作一个大的整数乘数而没有任何其他来源,如GMP。它可以将10,000个数字的整数乘以另一个。我遇到的问题是经过一定数量的乘法(对我来说,经过大约3次大乘法或25次小乘和3次大)我的程序冻结了。它使用大约1.8 GB的RAM然后停止。我不太确定是什么导致这种情况,我知道不同的数字具有相同的结果。 谢谢你的帮助。

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

    #define MAX 10001

    struct integer {
    int* digits;
    int size;
    };

    struct integer* add(struct integer* one, struct integer *two);
    void print(struct integer* number);
    void print_op(struct integer* op1, struct integer* op2,struct integer* tempwer,char op);
    struct integer* convert_integer(char* word);
    void free_struct(struct integer* thisint);
    struct integer* multiply(struct integer *p, struct integer *q);


    int main() {

    FILE* ifp = fopen("bigint.txt", "r");

    int loop, numcases;
    fscanf(ifp, "%d", &numcases);

    // Go through each case.
    for (loop=1; loop<=numcases; loop++) {

        // Read in both operands.
        char op1[MAX];
        char op2[MAX];
        fscanf(ifp, "%s%s", op1, op2);

        // Convert and compute.
        struct integer* first = convert_integer(op1);
        struct integer* second = convert_integer(op2);
        struct integer* ans = multiply(first, second);


        printf("Problem #%d: ", loop);
        print_op(first, second, ans, '*');
        printf("\n");

        // After we output, we don't need these any more.
        free_struct(first);
        free_struct(second);
        free_struct(ans);


    }

    return 0;
}

// Pre-conditions: Both one and two are not NULL pointers that point to
//                 linked lists structures that store non-negative digits
//                 at each node.
// Post-conditions: A pointer to a linked list will be returned. The
//                  linked list will store the value of the sum of the
//                  two integers represented by the linked lists passed
//                  into the function.
struct integer* add(struct integer* one, struct integer *two) {

    struct integer *ans;
    int digit1 = 0, digit2 = 0, carry = 0, result, i;


    ans = (struct integer *)malloc(sizeof(struct integer));

    //allocate space for the larger of the 2 arrays
    if(one->size>two->size)
        ans->size=one->size;
    else
        ans->size=two->size;

    ans->digits=(int*)(malloc(sizeof(int)*ans->size));

    for(i=0;i<ans->size;i++){
        // Determine digit to add from first operand.
        if (i<one -> size)
            digit1 = one -> digits[i];
        else
            digit1 = 0;

        // Determine digit to add from second operand.
        if (i<two -> size)
            digit2 = two -> digits[i];
        else
            digit2 = 0;

        // Compute correct addition digit and carry.
        result = (digit1 + digit2 + carry)%10;
        carry = (digit1 + digit2 + carry)/10;

        // Store result in the appropriate linked list.
        ans -> digits[i] = result;

    }//for

    // Take care of the most significant digit if there is a carry.
    if (carry != 0) {

        //copy off the whole array into a new one
        //of size+1 and free the old one in case of carry
        ans->size+=1;
        ans->digits = (int *)realloc(ans->digits, sizeof(int)*ans->size);
        ans->digits[ans->size-1] = carry;
    }

    // Return the ptr. to the added result.
    return ans;
}

// Precondition: number points to a not NULL linked list that contains
//               only single digits stored at each node.
// Postcondition: The integer represented by the linked list pointed to by
//                number will be printed out.
void print(struct integer* number) {

    int i;
    if (number != NULL) {

        // Loop through in backwards order, since number is stored reversed.
        for(i=number->size-1;i>=0;i--){
            printf("%d",number->digits[i]);
        }
    }

}

// Precondition: op1 and op2 point to valid linked lists storing integers,
//               operator is a valid integer operator, and tempwer is the
//               value of applying the first operation to the second.
// Postcondition: The arithmetic operation desired (op1 operator op2) will
//                be printed to the screen in a reasonable manner.
void print_op(struct integer* op1, struct integer* op2,struct integer* tempwer,char op) {

    print(op1);
    printf(" %c ", op);
    print(op2);
    printf(" = ");
    print(tempwer);


}

//Preconditions: the first parameter is a pointer to a
//  pointer variable that points to
//  struct integer. The function skips leading
//  blanks and assumes that no leading zeros are
//  entered at the input.
//Postconditions: The function will read the digits of the
//  large integer character by character,
//  convert them into integers and place them in
//  nodes of a linked list. The pointer to the
//  head of the list is returned as the value of
//  the input parameter.
struct integer* convert_integer(char* word) {

    int i;

    struct integer *ans=(struct integer *)(malloc(sizeof(struct integer)));
    ans->size=0;
    if(word==NULL) ans->digits=NULL;

    else {

        // Allocate space for each of the digits.
        ans->size = strlen(word);
        ans->digits=(int *)(malloc(sizeof(int)*ans->size));

        // Store them in reverse order.
        for(i=0;i< ans->size;i++)
            ans->digits[ans->size-i-1]=word[i] - '0';

    }//if word not NULL

    return ans;
}

//Preconditions: p and q are pointers to struct integers.
//Postconditions: A new struct integer is created that
//                stores the product of the integers
//                pointed to by p and q and a pointer to it
//                is returned.
struct integer* multiply(struct integer *p, struct integer *q){

    struct integer *temp;
    struct integer *ans;

    int digit1 = 0, digit2 = 0, carry = 0, index=0, front=0, result, i, j, pos, preSize;

    temp = (struct integer *)calloc(sizeof(struct integer),1);
    ans = (struct integer *)calloc(sizeof(struct integer),1);


    //allocate space for the larger of the 2 arrays
    //Which ever array is larger will be the starting size of the tempwer array.
    if(q->size>p->size)
        temp->size = q->size;

    else
        temp->size = p->size;


    temp->digits=(int*)(calloc(sizeof(int)*temp->size,1));


    //use a double for loop, one for the top number and one for bottom.
    for(i=0; i<q->size; i++){

        //Make the starting size the size of the biggest number.
        if(q->size>p->size)
            temp->size = q->size;

        else
            temp->size = p->size;


        temp->digits=(int*)(calloc(sizeof(int)*temp->size,1));

        if (i < q->size)
            digit1 = q->digits[i];
        else
            digit1 = 0;




        //Bottom part of the multiplication.
        for(j=0; j<p->size; j++){

            // Determine digit to add from first operand.
            if (j < p->size)
                digit2 = p->digits[j];
            else
                digit2 = 0;

            // Compute correct multiplication digit and carry.
            //gives last digit
            result = (digit1 * digit2 + carry)%10;
            //drops last digit
            carry = (digit1 * digit2 + carry)/10;

            // Store result in the appropriate linked list.
            temp -> digits[j] = result;

        }

        //Add a zero to the end of the next number (like multiplying by hand).
        if(i>0){

            temp->size += i;
            temp->digits = (int *)(realloc(temp->digits, sizeof(int)*temp->size));


            for(j=temp->size; j>0; j--){

                if((j-1-i)<0)
                    break;
                //Shift everthing over by 1.
                else
                    temp->digits[j-1]=temp->digits[j-1-i];

            }
            //Make the new number zero.
            for(j=1; j<=i; j++)
                temp -> digits[j-1] = 0;

        }//if


        //If there is a carry insert it in front of the number.
        if (carry != 0) {

            temp->size += 1;
            temp->digits = (int *)(realloc(temp->digits, sizeof(int)*temp->size));
            temp->digits[temp->size-1]=0;

            //Find the front of the number.
            for(j=temp->size; j>0; j--){

                if(temp->digits[j-1] != 0){

                    front = j;
                    break;
                }
            }

            //Insert it.
            if(result == 0)
                temp->digits[front+1] = carry;
            else
                temp->digits[front] = carry;

            carry = 0;

        }//if




    //Delete any leading zeros.
    if(temp->size != 1){

        for(j=temp->size; j>0; j--){

            //Finds where the zeros end.
            if(temp->digits[j-1] != 0){
                pos =j;
                break;
            }

            //Counts the zeros.
            if(temp->digits[j-1] == 0)
                index++;

            }

        //If they are all zeros then make the temp number 0 of size 1.
        if(index==temp->size) {
            pos=1;
            temp->size = temp->size-(temp->size-pos);
            temp->digits = (int *)realloc(temp->digits, sizeof(int)*temp->size);
        }
        //If not then reallocate with the extra zeros removed.
        else{
            temp->size = temp->size-(temp->size-pos);
            temp->digits = (int *)realloc(temp->digits, sizeof(int)*temp->size);
        }

        index=0;

    }//if


        //If this is the first time saving the answer the allocate memory for it.
        if(i==0){
            ans->size = temp->size;
            ans->digits=(int*)(calloc(sizeof(int)*temp->size,1));
        }

        //Add the temp number to the total (ans).
        ans = add(temp, ans);

        //Clear temp.
        for(j=0; j<temp->size; j++)
            temp->digits[j]=0;


    }//for on top


    free_struct(temp);

    return ans;

}


    // Frees the memory for the struct pointed to by thisint.
    void free_struct(struct integer* thisint) {
    free(thisint->digits);
    free(thisint);
}

1 个答案:

答案 0 :(得分:0)

在你的乘法方法的这一部分:

    temp->digits=(int*)(calloc(sizeof(int)*temp->size,1));// <-- allocate some

    //use a double for loop, one for the top number and one for bottom.
    for(i=0; i<q->size; i++){

        //Make the starting size the size of the biggest number.
        if(q->size>p->size)
            temp->size = q->size;
        else
            temp->size = p->size;

        temp->digits=(int*)(calloc(sizeof(int)*temp->size,1)); // <--allocate again

看起来你正在分配内存,而不是匹配除了最后一个在函数结束时被释放的空闲内容。我使用c已经很多年了,所以希望我没有错过任何明显的东西。