【问题标题】:(C) Using Arrays with Dynamic memory allocation(C) 使用动态内存分配的数组
【发布时间】:2016-09-01 01:04:56
【问题描述】:

我想创建一个包含 10 个元素的简单整数数组。 我正在使用动态内存在内存中分配空间,每当我超过该数量时,它将调用 realloc 使其大小翻倍。 每当我输入“q”时,它都会退出循环并打印数组。

我知道我的程序充满了错误,所以请指导我找出错误所在。

/* Simple example of dynamic memory allocation */

/* When array reaches 10 elements, it calls
   realloc to double the memory space available */

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

#define SIZE_ARRAY 10
int main()
{
    int *a;
    int length=0,i=0,ch;


    a= calloc(SIZE_ARRAY, sizeof(int));
    if(a == NULL)
    {
        printf("Not enough space. Allocation failed.\n");
        exit(0);
    }

    printf("Fill up your array: ");

    while(1)
    {

        scanf("%d",&ch);
        if(ch == 'q')                  //possible mistake here
            break;

        a[length]=ch;
        length++;

        if(length % 10 == 0)   //when length is 10, 20, 30 ..
            {
                printf("Calling realloc to double size.\n");

                a=realloc(a, 2*SIZE_ARRAY*sizeof(int));
            }


    }

    printf("You array is: \n");
    for(;i<length;i++)
        printf("%d ",a[i]);

   return 0;
}

每当我输入“q”时,程序就会崩溃。我是初学者,所以我知道我犯了一个愚蠢的错误。任何帮助将不胜感激。

【问题讨论】:

  • 您有多个错误。 a=realloc(a, 2*SIZE_ARRAY*sizeof(int));。那里的大小是常量。这显然不是您想要的,因为每个realloc 的大小都应该增加。接下来,scanf("%d",&amp;ch); if(ch == 'q') 并没有按照你的想法去做。 ch 被解析为整数。所以scanf 总是会在你输入一个非数字值比如'q' 时失败(总是检查scanf 的返回值)。
  • 顺便说一句,建议您学习使用调试器,以便您自己更有效地发现这些问题。
  • 感谢凯勒姆的建议。在您的第一点中,SIZE_ARRAY 宏是常量,但是如果我将常量乘以 2,那么它不会给我两倍的值吗? ....如果我想按字符“q”退出循环,你建议我应该怎么做?我的思绪被阻塞了,似乎无法弄清楚。
  • 2*ARRAY_SIZE 是一个常数值吧?这就是大小为 80、80、80、80 等的 realloc。你能看出问题所在吗?大小需要为 80、160、320 等。对于退出,一种选择是检查 scanf 的返回值。如果输入是有效数字,它将返回 1(已解析的项目数),否则将返回 0(未解析项目)。
  • 哦,我现在明白你的意思了。我会努力解决的。再次感谢您的帮助。

标签: c arrays memory dynamic


【解决方案1】:

您不应该将每个realloc() 的内存加倍,因为它可以变得非常大,非常快。您通常只按小块扩展内存。 realloc() 也有一个讨厌的习惯,如果旧的内存不能足够长,就会使用另一部分内存。如果失败,您将丢失旧内存中的所有数据。这可以通过使用临时指针指向新内存并在成功分配后交换它们来避免。这带来了额外指针(主要是 4 或 8 个字节)和交换(最多只需要几个 CPU 周期)的成本。小心 x86 的xchg 它在多个处理器的情况下使用锁,这是相当贵!)

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

// would normally be some small power of two, like
// e.g.: 64 or 256
#define REALLOC_GROW 10
int main()
{
  // a needs to be NULL to avoid a first malloc()
  int *a = NULL, *cp;
  // to avoid complications allocated is int instead of size_t
  int allocated = 0, length = 0, i, ch, r;

  printf("Fill up your array: ");
  while (1) {
    // Will also do the first allocation when allocated == length
    if (allocated <= length) {
      // realloc() might choose another chunk of memory, so
      // it is safer to work on copy here, such that nothing is lost
      cp = realloc(a, (allocated + REALLOC_GROW) * sizeof(int));
      if (cp == NULL) {
        fprintf(stderr, "Malloc failed\n");
        // but we can still use the old data
        for (i = 0; i < length; i++) {
          printf("%d ", a[i]);
        }
        // that we still have the old data means that we need to
        // free that memory, too
        free(a);
        exit(EXIT_FAILURE);
      }
      a = cp;
      // don't forget to keep the amount of memory we've just allocated
      allocated += REALLOC_GROW;
    }
    // out, if user typed in anything but an integer
    if ((r = scanf("%d", &ch)) != 1) {
      break;
    }
    a[length] = ch;
    length++;
  }

  printf("Your array is: \n");
  // keep informations together, set i=0 in the loop
  for (i = 0; i < length; i++) {
    printf("%d ", a[i]);
  }
  fputc('\n', stdout);
  // clean up
  free(a);

  exit(EXIT_SUCCESS);
}

如果您使用allocated 的起始值、REALLOC_GROW 的值并在realloc() 中使用乘法而不是加法并将if(allocated &lt;= length) 替换为if(1),则可以触发no-memory 错误,看看它是否仍然打印您之前输入的内容。现在直接使用 a 更改 realloc-on-copy 并查看它是否打印数据。情况可能仍然如此,但不再保证。

【讨论】:

  • 非常感谢。就两个问题。 “// a 需要为 NULL 以避免第一个 malloc()”是什么意思。并且也在“free(a)”中。在程序的最后是否有必要这样做?据我了解,一旦程序终止,它将释放所有内存,对吗?那么有什么理由包含它吗?
  • @tadm123 如果您使用p == NULL 调用realloc(p,size),它的作用类似于p = malloc(size),但必须初始化p。这样,您只有一个故障点 (realloc) 而不是两个(第一个 malloc() 和以下 realloc()s)。你不需要在程序结束时free()内存。但它是 a) 良好的风格和 b) 如果您使用内存检查程序,例如:Valgrind,不释放算作泄漏,可能会淹没真正的泄漏。首先让它成为一种习惯,当它重要时你甚至不必考虑它。
  • 我明白了。再次感谢。
猜你喜欢
  • 2023-03-17
  • 2021-04-02
  • 1970-01-01
  • 2021-07-17
  • 2013-05-24
  • 2014-07-19
  • 2022-01-15
相关资源
最近更新 更多