如何继续使用 malloc?

how to keep using malloc?

我有一个存储整数序列的文件。整数总数是未知的,所以如果我从文件中读取整数,我会继续使用 malloc() 来申请新内存。 我不知道我是否可以继续请求内存并将它们添加到数组的末尾。 Xcode 一直警告我 malloc() 行中的 'EXC_BAD_EXCESS'。 如果我一直从文件中读取整数,我该怎么做?

int main()
{
    //1.read from file
    int *a = NULL;
    int size=0;
    //char ch;
    FILE *in;

    //open file
    if ( (in=fopen("/Users/NUO/Desktop/in.text","r")) == NULL){
        printf("cannot open input file\n");
        exit(0);    //if file open fail, stop the program
    }

    while( ! feof(in) ){
        a = (int *)malloc(sizeof(int));
        fscanf(in,"%d", &a[size] );;
        printf("a[i]=%d\n",a[size]);
        size++;
    }
fclose(in);
return 0;
}
  1. 不使用 malloc,而是使用 realloc
  2. 不要在 while 循环中使用 feof(in)See why.
int number;
while( fscanf(in, "%d", &number) == 1 ){
    a = realloc(a, sizeof(int)*(size+1));
    if ( a == NULL )
    {
       // Problem.
       exit(0);
    }
    a[size] = number;
    printf("a[i]=%d\n", a[size]);
    size++;
}

像那样反复调用 malloc() 并不像您认为的那样。每次调用 malloc(sizeof(int)) 时,它都会分配一个单独的新内存块,该内存块只够容纳一个整数。写入 a[size] 最终会为第一个值之后的每个值注销该数组的末尾。

这里你要的是realloc()函数,例如

a = realloc(a, sizeof(int) * (size + 1));
if (a == NULL) { ... handle error ... }

修改您的代码,使 size 实际上是数组的 大小 ,而不是它的最后一个索引,这将有助于简化此代码,但这既不是这里也不是那里。

您还没有分配一个整数数组,您在这里分配了一个整数。因此,您需要分配默认数组大小,然后在即将超过 运行 时调整大小。这将在每次填满时将其大小调整 2。以这种方式调整大小可能不符合您的最佳利益,但您也可以为每个附加字段重新分配每个字段。

size_t size = 0;
size_t current_size = 2;

a = (int *)malloc(sizeof(int) * current_size);
    if(!a)
        handle_error();


while( ! feof(in) ){
    if(size >= current_size) {
        current_size *= 2;
        a = (int *)realloc(a, sizeof(int) * current_size);
        if(!a)
            handle_error();
    }
    fscanf(in,"%d", &a[size] );;
    printf("a[i]=%d\n",a[size]);
    size++;
}

您的 malloc() 正在覆盖您之前的存储空间,space 只够存储一个整数!

a = (int *)malloc(sizeof(int));
 ^^^ assignment overwrites what you have stored!

相反,realloc() 数组:

a = realloc(a, sizeof(int)*(size+1));

通常的方法是首先分配一定数量的 space(大到足以覆盖大多数情况),然后根据需要使用 realloc 函数将其加倍。

一个例子:

#define INITIAL_ALLOCATED 32 // or enough to cover most cases
...
size_t allocated = INITIAL_ALLOCATED;
size_t size = 0;
...
int *a = malloc( sizeof *a * allocated );
if ( !a )
  // panic

int val;

while ( fscanf( in, "%d", &val ) == 1 )
{
  if ( size == allocated )
  {
    int *tmp = realloc( a, sizeof *a * allocated * 2 ); // double the size of the buffer
    if ( tmp )
    {
      a = tmp;
      allocated *= 2;
    }
    else
    {
      // realloc failed - you can treat this as a fatal error, or you
      // can give the user a choice to continue with the data that's 
      // been read so far.  
    }
    a[size++] = val;
  }
}

我们首先将 32 个元素分配给 a。然后我们从文件中读取一个值。如果我们不在数组的末尾(size 不等于 allocated),我们将该值添加到数组的末尾。如果我们在数组的末尾,则使用 realloc 将其大小加倍。如果 realloc 调用成功,我们更新 allocated 变量以跟踪新大小并将值添加到数组。我们继续前进,直到到达输入文件的末尾。

每次达到限制时将数组的大小加倍可减少 realloc 调用的总数,如果您正在加载 lot,这可以节省性能值。

请注意,我将 realloc 的结果分配给了另一个变量 tmprealloc 将 return NULL 如果它出于任何原因无法扩展数组。如果我们将 NULL 值分配给 a,我们将失去对之前分配的内存的引用,从而导致内存泄漏。

另请注意,我们检查 fscanf 的结果而不是调用 feof,因为 feof 不会 return true 直到我们'我们已经尝试读取文件末尾。