【问题标题】:Taking ints with scanf into a memory allocation during a while loop and realloc'ing在 while 循环和重新分配期间将带有 scanf 的整数放入内存分配中
【发布时间】:2019-05-16 22:14:22
【问题描述】:

我声明一个 int 指针并为其分配内存。然后我将整数输入其中,直到用户输入 Ctrl+d。除非我尝试输入 7 或更多,否则循环工作正常,此时它给我一个看起来像“realloc(): invalid next size”的错误,并给我一个回溯/内存映射。它与我的realloc 行有关,但我不确定是什么。有谁能赐教吗?

int  n= 0, *x, i;
double mean = 0.0, median = 0.0, stdDev = 0.0;

x =  malloc(sizeof(int));
for(i = 0; scanf("%d", &x[i]) != -1; i++) {
        n++;
        x = realloc(x, n+1 * sizeof(int));
        mean = findMean(x, n);
        median = findMedian(x, n);
        stdDev = findStandardDeviation(x, n, mean);
}

【问题讨论】:

  • 如果用户输入非数字文本,for(i = 0; scanf("%d", &x[i]) != -1; i++) { ... } 是一个无限循环。建议改为for(i = 0; scanf("%d", &x[i]) == 1; i++) { ... }

标签: c malloc scanf realloc


【解决方案1】:

问题在于运算顺序:n + 1 * sizeof(int) 的意思是“乘以 sizeof(int) 的 1 倍,然后加上 n”。您可以使用括号来强制执行顺序:(n + 1) * sizeof(int)

内存分配可能很昂贵!请求合理的内存块,然后每隔一段时间将其增加 2 倍。在内存分配系统调用中,操作系统可能会为您提供比您要求的更大的块,以便后续的 realloc 调用更便宜并使用您的程序已经可用的内存。

最好检查您的mallocrealloc 调用是否成功。如果分配请求失败,这些函数将返回 NULL。

另外,当你完成分配的内存时,不要忘记free 以避免内存泄漏。

编写您自己的类似“vector/ArrayList/list”的接口可能是一个有趣的练习,该接口可以扩展和收缩到大小并可能具有slice(start_index, end_index)remove(index) 等操作。

这是一个完整的例子:

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

int main() {
    int nums_len = 0;
    int nums_capacity = 5;
    int *nums = malloc(nums_capacity * sizeof(int));

    while (scanf("%d", &nums[nums_len]) != -1) {
        if (++nums_len >= nums_capacity) {
            printf("increasing capacity from %d to %d\n", 
                   nums_capacity, nums_capacity * 2);

            nums_capacity *= 2;
            nums = realloc(nums, nums_capacity * sizeof(int));

            if (!nums) {
                fprintf(stderr, "%s: %d: realloc failed\n", 
                        __func__, __LINE__);
                exit(1);
            }
        }

        printf("got: %d\n", nums[nums_len-1]);
    }

    printf("Here are all of the %d numbers you gave me:\n", nums_len);

    for (int i = 0; i < nums_len; i++) {
        printf("%d ", nums[i]);
    }

    puts("");
    free(nums);
    return 0;
}

示例运行:

5
got: 5
6
got: 6
7
got: 7
8
got: 8
1
increasing capacity from 5 to 10
got: 1
3
got: 3

5
got: 5
6
got: 6
7
got: 7
1
increasing capacity from 10 to 20
got: 1
2
got: 2
3
got: 3
4
got: 4
5
got: 5
6
got: 6
67
got: 67
8
got: 8
1
got: 1
2
got: 2
3
increasing capacity from 20 to 40
got: 3
4
got: 4
1
got: 1
2
got: 2
Here are all of the 23 numbers you gave me:
5 6 7 8 1 3 5 6 7 1 2 3 4 5 6 67 8 1 2 3 4 1 2

【讨论】:

  • 谢谢你。您将如何不每次都重新分配?只是带有 i%5==0 或类似内容的 if 语句?在每个 realloc() 之后我也 free() 吗?
  • Realloc 并不总是那么昂贵。首先,每个 malloc/realloc 都不是系统调用,它们以非常大的块向操作系统请求内存。然后他们将它们以较小的部分提供给程序,而无需进行任何系统调用。而realloc 通常只是大小更新而不移动内容。如果正在“重新分配”的内存是最后分配的内存,则尤其如此。
  • @user3242445 不——只有一个免费的指针。我添加了一个周期性重新分配的示例。这有助于澄清吗?
  • @ggorlen 是的,这有帮助!但现在无论我的输入如何,我都只是进入 0,大声笑.. 哦,亲爱的
  • 我建议您回滚您的编辑,然后单独发布您更新的代码(如果有的话)。否则,答案将无效,未来的访问者将无法从问题中收集到太多信息。更新代码中的问题是变量命名不佳——您同时使用in 来处理数组上的索引和长度逻辑。最好像我一样使用更明确的名称,这样可以消除变量含义的混淆。
【解决方案2】:

n+1 * sizeof(int)(n+1) * sizeof(int)不一样

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-06-28
    • 2016-02-19
    • 2017-09-15
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多