【问题标题】:How to sum big numbers如何对大数求和
【发布时间】:2015-11-15 16:17:37
【问题描述】:

我正在尝试编写一个程序,该程序将汇总非常大的数字。不幸的是,我被卡住了——即使我注释掉 malloc 和 realloc (编译器似乎失败了),它也不会返回任何结果。有任何想法吗?我的代码:

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

int i,j,x;
char *actual = NULL;
char *sum = NULL;

void init () {
    sum = malloc(500);
    actual = malloc(500);
}

void calculate (char *argv[]) {
    int rest = 0;
    actual = *argv;
    actual = realloc(actual, strlen(*argv));
    if (strlen(actual) > strlen(sum)) {
    sum = realloc(sum, strlen(actual) + 1);
    } else sum = realloc(sum, strlen(sum) + 1);
    long b;
    for (b = 1; b < strlen(actual); b++) {
        rest = rest + atoi(&sum[strlen(sum) - b]) + atoi(&actual[strlen(actual) - b]);
        if (rest > 9) {
            sum[strlen(sum) - b] = rest - 10;
            rest = 1;   // carrying over 1
        } else {
            sum[strlen(sum) - b] = rest;
            rest = 0;
        }
    }
}

void writeResult () {
    printf("VYPIS - sum:");
    printf("strlen souctu je: %lu\n",strlen(sum));
    long c;
    for (c = 0; c <= strlen(sum); c++) {
        printf("%c",sum[c]);
    }
    printf("\n");
}

void emtpy () {
    free(actual);
    free(sum);
}

int main(int argc, char * argv[]) {
    init();
    for (i = 1; i < argc; i++) {
        calculate(&argv[i]);
    }
    writeResult();
    emtpy();
    return 0;
}

【问题讨论】:

  • 始终检查可能遇到错误的函数的结果!
  • 遍历每个对 strlen() 的调用,并确保传递了一个有效的以 NULL 结尾的字符串。
  • 附带说明:atoi 需要一个以 null 结尾的字符串,但不是:atoi(&amp;sum[strlen(sum) - b])。要转换单个数字,您只需执行x - '0'
  • '实际 = *argv;'覆盖在 Init() 中分配的指针。
  • 你的bug太多了。修复已经注意到的那些,将所有那些 strlen() 调用读入中间临时变量,调试重建并使用你的调试器。

标签: c bignum


【解决方案1】:

尝试realloc argv 是未定义的行为。一般来说,您不应该 realloc 没有 malloc 的内容或从明确将内存所有权转移给您的函数接收到的内容。

另请注意,atoi 需要一个以 null 结尾的 C 字符串,因此将长字符串的一部分传递给它是不正确的。如果您想获得char 数字的数值,请减去'0',如下所示:

int digit = actual[strlen(actual) - b] -'0';

要将单个十进制数字转换为char,请在后面添加'0'

res[b] = digit + '0';

【讨论】:

  • 我怀疑 OP 认为 'actual = *argv;'复制 char 数组,(我们知道它不会)。
【解决方案2】:

你的代码太复杂了,有几个问题:

  • 您不能使用atoi 将字符转换为值,可以通过这种方式非常简单地完成:int value = c - '0'
  • 您不应修改argv 数组中的字符串。特别是你不能重新分配它们。这会调用未定义的行为。
  • 始终为最终'\0' 分配或重新分配比您要存储在结果数组中的字符串长度多1 个字节,并记住设置这个最终字节。
  • 您应该像手动一样从右到左计算加法,跟踪从一个数字到下一个数字的进位,可能会添加一个额外的前导数字。

这是一个针对您的问题的简化版本,展示了如何处理以 10 为底的大数:

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

static char *bigsum(char *res, const char *arg) {
    size_t pos1, pos2, pos3, len3;
    unsigned int carry;

    pos1 = strlen(res);
    pos2 = strlen(arg);
    len3 = pos3 = (pos1 < pos2) ? pos2 + 1 : pos1 + 1;
    /* reallocate the result array to one more than the larger operand */
    res = realloc(res, len3 + 1);
    /* set the terminating '\0' at the end of result */
    res[pos3] = '\0';
    for (carry = 0; pos3 > 0; carry /= 10) {
        if (pos1 > 0) carry += res[--pos1] - '0';
        if (pos2 > 0) carry += arg[--pos2] - '0';
        res[--pos3] = '0' + carry % 10;
    }
    while (res[0] == '0' && len3 > 1) {
        /* normalize the result: remove redundant initial zeroes */
        memmove(res, res + 1, len3--);
    }
    return res;
}

int main(int argc, const char **argv) {
    /* initialize the result to "0" as an allocated string */
    char *result = strcpy(malloc(2), "0");
    int i;

    for (i = 1; i < argc; i++) {
        result = bigsum(result, argv[i]);
    }
    printf("%s\n", result);
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-01
    • 2020-04-10
    • 1970-01-01
    • 1970-01-01
    • 2022-11-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多