简体   繁体   English

C大数相乘

[英]C multiplying large numbers

The following C program multiplies large numbers as strings. 以下C程序将大量数字乘以字符串。 It work works well with positive numbers, but with large numbers too much memory is used. 对于正数,它可以很好地工作,但是对于大数,将使用过多的内存。 How can I improve it to use less memory? 如何改善以减少内存使用量?

My program: 我的程序:

char *strrev(char *str) {
        char *p1, *p2;

        if(!str || !*str)
            return str;

        for (p1 = str, p2 = str + strlen(str) - 1; p2 > p1; ++p1, --p2) {
            *p1 ^= *p2;
            *p2 ^= *p1;
            *p1 ^= *p2;
        }
        return str;
    }

    char* addNumbers(char* c1, char* c2) {

        char *m1;
        char *m2;


        if (strlen(c1) >= strlen(c2)) {
            m1 = malloc(sizeof(c1));
            m2 = malloc(sizeof(c2));
            strcpy(m1, c1);
            strcpy(m2, c2);
        } else {
            m1 = malloc(sizeof(c2));
            m2 = malloc(sizeof(c1));
            strcpy(m1, c2);
            strcpy(m2, c1);
        }

        strrev(m1);
        strrev(m2);

        int lm1 = strlen(m1);
        int lm2 = strlen(m2);

        //char *w = malloc(1000000);
        char its;
        int jd = 0;
        for (int l = 0; l < lm1; l++) {
            int w1 = strToInt(m1[l]);
            int w2;
            if (l < strlen(m2)) {
                w2 = strToInt(m2[l]);
            } else {
                w2 = 0;
            }
            int w3 = w1 + w2 + jd;
            if (w3 > 9) {
                jd = 1;
                w3 = w3 % 10;
            } else {
                jd = 0;
            }
            its = w3 + 48;
            m1[l] = its;
        }
        if (jd > 0) {
            char its2[12];
            sprintf(its2, "%d", jd);
            strcat(m1, its2);
        }

        return strrev(m1);
    }

    int main(int argc, char* argv[]) {
        char *c1;
        char *c2;
        if (strlen(argv[1]) > strlen(argv[2])) {
            c1 = malloc(sizeof(argv[1]));
            c2 = malloc(sizeof(argv[2]));
            strcpy(c1, argv[1]);
            strcpy(c2, argv[2]);
        } else {
            c1 = malloc(sizeof(argv[2]));
            c2 = malloc(sizeof(argv[1]));
            strcpy(c1, argv[2]);
            strcpy(c2, argv[1]);
        }
        char counter[sizeof(c2)];
        sprintf(counter, "%d", 0);
        char one[2];
        sprintf(one, "%d", 1);
        char *w = malloc(100);
        while (strcmp(counter, c2) != 0) {
            strcpy(counter, addNumbers(counter, one));
            strcpy(w, addNumbers(w, c1));
        }
        printf("%s\n%s\n", c1, c2);
        free(c1);
        free(c2);
        printf("Result: %s,%ld\n\n", w,sizeof(w));
        free(w);
    }

I know that better algorithms exist, but I am required to use addNumbers() function. 我知道存在更好的算法,但是我需要使用addNumbers()函数。

How can I improve it to save memory? 如何改进它以节省内存?
As written, your post includes several instances of calls to calloc() , each creating heap memory, but none of the memory created is being freed, resulting in memory leaks. 如所写,您的帖子包括对calloc()多个调用实例,每个实例都创建堆内存,但是创建的所有内存都没有被释放,从而导致内存泄漏。 At a very minimum then the answer to your question is to simply make a corresponding call to free() for each and every call to malloc() . 至少,对于您的问题的答案是,只需对每个malloc()调用一次相应的free()调用即可。

By the way, there are good discussions on when, where and how to use dynamically allocated memory here and here . 顺便说一下, 这里这里对何时,何地以及如何使用动态分配的内存进行了很好的讨论。

The following is a simplification of the addNumbers function, while preserving its original prototype. 以下是addNumbers函数的简化,同时保留了其原始原型。 As requested in the comments, it uses ANSI C with no additional libraries. 根据注释中的要求,它使用没有其他库的ANSIC。 It also features among other things integrated string reversing (Eliminating the strrev() function), uses only one instance of dynamically allocated memory, and leaks none. 除其他功能外,它还具有集成的字符串反转功能(消除了strrev()函数),仅使用动态分配的内存的一个实例,并且不会泄漏任何实例。

Note, the example uses hard coded inputs for illustration, but by uncommenting the scanf() functions, and adding command line inputs, it can easily be converted to match your needs. 注意,该示例使用硬编码的输入进行说明,但是通过取消注释scanf()函数并添加命令行输入,可以轻松地将其转换为符合您的需求。

char* addNumbers(char* s1, char* s2) ;

int main(int argc, char *argv[])
{
    char s1[101] = {"150353265326"};
    char s2[101] = {"22055653351"};

    // Expect: 3316139500221184007426

    //scanf(" %s",s1);
    //scanf(" %s",s2);
    char * result = addNumbers(s1, s2); 


    printf("%s\n", result);

    free(result);

    return 0;
}


char* addNumbers(char* s1, char* s2) 
{
    int i=0, j=0, tmp;

    int l1 = strlen(s1);
    int l2 = strlen(s2);
    int a[100]={0},b[100]={0};
    int ans[200] = {0};
    char *result = calloc(l1+l2+1, 1);

    for(i = l1-1,j=0;i>=0;i--,j++)
    {
        a[j] = s1[i]-'0';
    }
    for(i = l2-1,j=0;i>=0;i--,j++)
    {
        b[j] = s2[i]-'0';
    }
    for(i = 0;i < l2;i++)
    {
        for(j = 0;j < l1;j++)
        {
            ans[i+j] += b[i]*a[j];
        }
    }
    for(i = 0;i < l1+l2;i++)
    {
        tmp = ans[i]/10;
        ans[i] = ans[i]%10;
        ans[i+1] = ans[i+1] + tmp;
    }
    for(i = l1+l2; i>= 0;i--)
    {
        if(ans[i] > 0)
            break;
    }

    for(j=i;j >= 0;j--)
    {
        result[i-j] = (char)('0' + ans[j]);
    }
    return result;
}

Tested using command line inputs: 使用命令行输入进行了测试:

在此处输入图片说明

Note: This adaptation gives credit to this implementation. 注意:这种改编归功于该实现。

You are using up lots of memory by allocating it but not freeing it. 您正在通过分配而不是释放它来消耗大量内存。 Even if you do free it, you have lots of allocation, copying and deallocation. 即使您释放了它,您也有很多分配,复制和释放。

Rather than doing that, you would be better allocating space for the result, then accumulating in the same result until your product is finished. 与其这样做,不如为结果分配空间,然后再累积相同的结果,直到您的产品完成为止。

As your inputs can be const strings, you should aim for only one malloc in your main() function to allocate the space for the result, then the rest is modifying that in-place. 由于您的输入可以是const字符串,因此您应该只针对main()函数中的一个malloc来分配结果空间,然后其余部分就地进行修改。 If you need to reverse the input strings, then you will need a couple more allocations, but that's all. 如果您需要反转输入字符串,那么您将需要几个分配,仅此而已。 I would not do the addition in strings, but use an array of uint_8 and do the strToInt conversion once for each input at the start rather than many, many times in the loop. 我不会在字符串中进行加法运算,而是使用uint_8数组,并在开始时对每个输入执行一次strToInt转换,而不是在循环中进行多次。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM