我有一个存储整数序列的文件。总整数的数量是未知的,所以如果我从文件中读取一个整数,我会继续使用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 filen");
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]=%dn",a[size]);
size++;
}
fclose(in);
return 0;
}
像那样反复调用malloc()
并不能达到你认为的效果。每次调用malloc(sizeof(int))
时,它都会分配一个单独的、新的内存块,该内存块只够一个整数使用。写入a[size]
的结果是,对于超过第一个值的每个值,都会写入该数组的末尾。
这里需要的是realloc()
功能,例如
a = realloc(a, sizeof(int) * (size + 1));
if (a == NULL) { ... handle error ... }
重新编写代码,使size
实际上是数组的大小,而不是它的最后一个索引,这将有助于简化此代码,但这既不存在也不存在。
- 不要使用
malloc
,而是使用realloc
- 不要在
while
循环中使用feof(in)
。看看原因
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]=%dn", a[size]);
size++;
}
您的malloc()
正在用一个整数所需的空间覆盖您以前的存储!
a = (int *)malloc(sizeof(int));
^^^ assignment overwrites what you have stored!
相反,realloc()
阵列:
a = realloc(a, sizeof(int)*(size+1));
您还没有分配整数数组,您在这里分配了一个整数。因此,您需要分配一个默认的数组大小,然后在即将过度运行时调整大小。这将在每次装满时将其大小调整为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]=%dn",a[size]);
size++;
}
通常的方法是首先分配一些空间(足够大,可以覆盖大多数情况),然后根据需要使用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
调用的总数,如果您正在加载批值,则可以节省性能。
注意,我将realloc
的结果分配给了不同的变量tmp
。如果realloc
由于任何原因无法扩展数组,则它将返回NULL
。如果我们将NULL
值分配给a
,我们将丢失对之前分配的内存的引用,从而导致内存泄漏。
还要注意,我们检查fscanf
的结果,而不是调用feof
,因为feof
在我们已经尝试读取文件末尾之后才会返回true
。