【问题标题】:Realloc gives invalid pointer error when resizing array调整数组大小时,Realloc 给出无效指针错误
【发布时间】:2016-10-29 10:18:05
【问题描述】:

我正在尝试制作一个随输入增加的数组的简单示例。输入是一系列数字,这个系列的结尾是零。我的想法是每次读取一个新数字时增加我的数组,但由于某种原因,这似乎不起作用,因为我收到错误:

Realloc(): invalid pointer 

这是我当前的代码:

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

int *resizeIntArray(int *series, int newSize) {
    int *newSeries = realloc(series, newSize * sizeof(int));
    if (newSeries == NULL) {
        printf("Error: Memory allocation failed");
        exit(-1);
    }
    return newSeries;
}

int main(int argc, char *argv[]) {
    int number;
    scanf("%d", &number);

    int *numbers;
    int size = 0;
    while (number != 0) {
       numbers = resizeIntArray(numbers, size + 1);
       printf("%d ", number);
       scanf("%d", &number);
       size++;
    }
}

【问题讨论】:

  • 你的编译器应该已经警告过这一点。您使用的是哪个编译器,您是否确保设置了合理的选项?
  • 如果文件不包含0 值,您应该测试scanf() 的返回值以避免文件末尾的无限循环。

标签: c arrays memory


【解决方案1】:

你将一个未初始化的变量传递给你的函数,然后传递给realloc,它需要一个指向先前分配的内存的指针,或者NULL

所以初始化那个变量:

int *numbers = NULL;

【讨论】:

  • @jurhas 是realloc 接受NULL 指针,在这种情况下它的行为类似于malloc
  • 请注意,realloc() 可能会在传递新大小 0 并返回 NULL 或指向不允许写入任何内容的已分配对象的指针时释放内存块。最后,与普遍的看法相反,free 也接受NULL 作为参数并且什么都不做。
【解决方案2】:

您的代码中有多个问题:

  • 您没有将numbers 初始化为NULL,因此realloc() 在第一次调用时会调用未定义的行为。这导致了您观察到的问题。
  • 您没有检查scanf() 的返回值,如果输入流不包含0 数字,则会导致潜在的无限循环和未定义的行为。
  • 您没有将数字存储在重新分配的数组中...
  • 您没有释放数组(次要)。
  • main() 的末尾不返回 0(次要)。

这里有一个更简单、更安全的版本:

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

int *resizeIntArray(int *series, int newSize) {
    int *newSeries = realloc(series, newSize * sizeof(int));
    if (newSeries == NULL) {
        printf("Error: Memory allocation failed");
        exit(-1);
    }
    return newSeries;
}

int main(int argc, char *argv[]) {
    int number;
    int *numbers = NULL;
    int i, size = 0;

    /* reading the numbers */
    while (scanf("%d", &number) == 1 && number != 0) {
       numbers = resizeIntArray(numbers, size + 1);
       numbers[size++] = number;
    }
    /* printing the numbers */
    for (i = 0; i < size; i++) {
       printf("%d ", numbers[i]);
    }
    printf("\n");

    free(numbers);
    return 0;
}

【讨论】:

    【解决方案3】:

    您可以尝试这样的方法。这包括:

    • 内存检查,带有相应的错误消息。
    • 使用malloc()realloc() 分配和重新分配内存。
    • 在运行时需要时分配足够的空间。
    • 适当检查scanf() 的返回值。

    代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    
    #define EXIT 0
    
    void exit_if_null(void *ptr, const char *msg);
    
    int
    main(int argc, char const *argv[]) {
        int *numbers = NULL;
        int number, num_size = 1, count = 0, i;
    
        /* initial allocation of memory */
        numbers = malloc(num_size * sizeof(*numbers));
    
        /* small error checking, to be safe */
        exit_if_null(numbers, "Initial Allocation");
    
        /* Reading in numbers */
        printf("Enter numbers(0 to end): ");
        while (scanf("%d", &number) == 1 && number != EXIT) {
    
            /* valid number found, but is there space? */
            if (num_size == count) {
                num_size *= 2;
    
                /* resize run-time array */
                numbers = realloc(numbers, num_size * sizeof(*numbers));
                exit_if_null(numbers, "Reallocation");
            }
            numbers[count++] = number;
        }
    
        /* print out numbers */
        printf("Your numbers stored in array:\n");
        for (i = 0; i < count; i++) {
            printf("%d ", numbers[i]);
        }
    
        /* free allocated memory, very important */
        free(numbers);
    
        return 0;
    }
    
    /* helper function for error checking */
    void
    exit_if_null(void *ptr, const char *msg) {
        if (!ptr) {
            printf("Unexpected null pointer: %s\n", msg);
            exit(EXIT_FAILURE);
        }
    }
    

    【讨论】:

      【解决方案4】:

      首先,您应该先分配一些内存,然后再重新分配。因此您的代码将更改为:

      #include <stdio.h> 
      #include <stdlib.h>
      int *resizeIntArray(int *series, int newSize){
      int *newSeries = realloc(series,newSize*sizeof(int));
      if(newSeries == NULL){
       printf("Error: Memory allocation failed");
       exit(-1);
       }
      return newSeries;
      }
      int main(int argc, char* argv[]) {
         int number;
         scanf("%d",&number);
         int *numbers=malloc(sizeof(int));///CHANGED
         int size = 1;///CHANGED
         while(number != 0){
         numbers = resizeIntArray(numbers,size +1);
         printf("%d ",number);
         scanf("%d",&number);
         size++;
       } 
      }
      

      但是你正在做的白色是很没有效率的。 realloc() 函数隐藏了一个 free() 一个 malloc() 和最糟糕的一个:memcpy()。因此,如果您在每个新项目上都重新分配(),那么您将度过一段糟糕的时光...... O(n^2) 完全正确。 最好的方法是分配内存缓冲区:

        struct vector
        {   
            int *numbers;
            size_t size;
            size_t i;
         }
         #define DEFAULTBUF 100
         int main()
         {
                struct vector v;
                v.numbers=malloc(sizeof(int)*DEFAULTBUF);
                v.size=DEFAULTBUF;
                v.i=0;
                scanf("%d",&number);
                while(number != 0 && v.numbers){
                   if (v.i->=v.size)
                    {   v.size+=v.size
                       v.numbers=realloc(v.numbers,sizeof(int)*v.size);
                     ///i leave to you the error handling
                     }
                     v.i++;
                    printf("%d ",number);
                    scanf("%d",&number);
      
                   }  
      
         }
      

      正确使用 realloc() malloc() 和类似方法非常重要。并且调整大小的比例也在增加。对于数据结构,我曾经加倍。对于文本,我线性进行

      【讨论】:

      • 其实不保证O(n^2)。这将取决于malloc()和朋友的实际实现。我见过一些只使用大小均为 2 次方的块。在这种情况下重复调用 realloc() 与您的解决方案具有相同的效果和复杂性。此外,正确处理内存不足并正确处理分配的内存比过早关注优化更为重要。当然free不是强制性的,因为程序会立即退出,但从一开始就养成一个好习惯。
      • 它可以与小数组一起使用,但我不会基于这些考虑编写代码。当我为我的 btree 编写代码时,我对 3.000.000 个项目进行了基准测试。重新分配步骤是线性的,包含 4096 个节点。它需要25秒。只需更改行 bt->sz+=DEFAULTBLOCKSIZE;到 bt->sz+=bt->sz;时间下降到3秒。从那天起,我就对 realloc() 和朋友们非常小心。永远喜欢列表而不是向量,除非向量是静态或准静态的,否则会分配更多缓冲区等等......如果程序需要 3 或 3.1 Mb,没人会注意到,但 25 秒
      猜你喜欢
      • 2012-03-17
      • 2017-09-16
      • 1970-01-01
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 2017-08-24
      • 1970-01-01
      • 2020-01-12
      相关资源
      最近更新 更多