使用 "fgetc" 读取文件时出错(溢出)
Error when reading a file with "fgetc" (Overflow)
我正在使用此代码读取文件:
char* fs_read_line(FILE* file)
{
if (file == NULL) {
return "CFILEIO: Error while reading the file: Invalid File";
}
long threshold = ftell(file);
fseek(file, 0, SEEK_END);
uint8_t* buffer = calloc(ftell(file)-threshold, sizeof(uint8_t));
if(buffer == NULL)
return;
int8_t _;
fseek(file, threshold, SEEK_SET);
uint32_t ct = 0;
while ((_ = (char)(fgetc(file))) != '\n'
&& _ != '[=11=]' && _ != '\r' && _ != EOF) {
buffer[ct++] = _;
}
buffer = realloc(buffer, sizeof *buffer * (ct + 1));
buffer[ct] = '[=11=]';
return buffer;
}
如果文件太大,我会收到(堆)溢出错误,可能是因为我最初分配文件时包含的字符总数。
我尝试这样做的另一种方法是 realloc
每次迭代后的缓冲区,但这有点不是我想要的方法。
有什么方法可以根据当前迭代动态更改数组的大小而不总是 uisng realloc
吗?或者有没有办法通过使用 ftell
和 fseek
?
来确定当前行的长度
如果您的文件无法放入内存,那么它也无法放入内存。您正在提前分配内存缓冲区,但您犯了两个错误,这可能会导致您分配的内存超出您的需要。
- 您从文件中的任意位置开始,但分配内存就像从文件开头开始一样。分配
ftell(file) - threshold
字节。
- 你分配的内存太多了。
sizeof(uint8_t *)
应该改为 sizeof(uint8_t)
。您分配的内存比应有的多 4 或 8 倍。
除此之外,在您写完之后重新分配缓冲区有什么意义?内存溢出已经发生。您应该在写入之前分配(在 while 循环内)。不过,我根本看不到重新分配的意义,因为您分配的内存已经足够多了。
代码不return指向字符串的指针。
returned buffer
中没有 空字符,因此调用代码无法知道已分配内存的长度。这肯定会导致调用代码出错。
当re-allocating时,加1。
// buffer = realloc(buffer, ct * sizeof(uint8_t*));
// v--- no star
buffer = realloc(buffer, ct * sizeof(uint8_t ) + 1);
buffer[ct] = '[=10=]';
// or better
size_t ct = 0;
...
buffer = realloc(buffer, sizeof *buffer * (ct + 1));
buffer[ct] = '[=10=]';
Is there any way to dynamically change the size of the array allocated memory depending on the the current iteration without always using realloc
?
数组大小无法更改。要动态更改已分配内存的大小需要 realloc()
。注意:所需的内存量可以在内存分配调用之前确定。
or is there an way to determine how long the current line is by using ftell
and fseek
?
像这段代码一样,您找到了当前行长度的上限。 ftell
和 fseek
没有找到行尾。
代码可以 "seek" 到行尾 fscanf(file, "%*[^\n]");
或 1 之后的 fgetc(file)
.
以下代码:
- 干净地编译
- 执行所需的操作
- 正确处理错误情况
- 正确声明变量类型
- 正确地 return 是
char*
而不是 uint8_t*
- 留下悬而未决的问题:为什么 return 是所需缓冲区长度的 2 倍
- 传入参数为NULL时显示的错误信息不正确。建议更改以指示传入的文件指针为 NULL
- OP 发布的代码无法检查每次调用
fseek()
的 returned 值,也无法检查每次调用 ftell()
的 return 值应该这样做以确保操作成功。我没有在我的答案中添加错误检查,以免代码混乱,但是,应该执行它。
现在,代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
char* fs_read_line(FILE* file);
char* fs_read_line(FILE* file)
{
if ( !file )
{
return "CFILEIO: Error while reading the file: Invalid File";
}
// implied else, valid parameter
long threshold = ftell(file);
fseek(file, 0, SEEK_END);
char* buffer = calloc( (size_t)(ftell(file) - threshold) *2 +1, sizeof(char));
if(buffer == NULL)
return NULL;
// implied else, calloc successful
int ch;
fseek(file, threshold, SEEK_SET);
size_t ct;
while ( (ch = fgetc(file)) != '\n'
&& ch != '[=10=]'
&& ch != '\r'
&& ch != EOF)
{
buffer[ct++] = (char)ch;
}
return buffer;
} // end function: fs_read_line
我正在使用此代码读取文件:
char* fs_read_line(FILE* file)
{
if (file == NULL) {
return "CFILEIO: Error while reading the file: Invalid File";
}
long threshold = ftell(file);
fseek(file, 0, SEEK_END);
uint8_t* buffer = calloc(ftell(file)-threshold, sizeof(uint8_t));
if(buffer == NULL)
return;
int8_t _;
fseek(file, threshold, SEEK_SET);
uint32_t ct = 0;
while ((_ = (char)(fgetc(file))) != '\n'
&& _ != '[=11=]' && _ != '\r' && _ != EOF) {
buffer[ct++] = _;
}
buffer = realloc(buffer, sizeof *buffer * (ct + 1));
buffer[ct] = '[=11=]';
return buffer;
}
如果文件太大,我会收到(堆)溢出错误,可能是因为我最初分配文件时包含的字符总数。
我尝试这样做的另一种方法是 realloc
每次迭代后的缓冲区,但这有点不是我想要的方法。
有什么方法可以根据当前迭代动态更改数组的大小而不总是 uisng realloc
吗?或者有没有办法通过使用 ftell
和 fseek
?
如果您的文件无法放入内存,那么它也无法放入内存。您正在提前分配内存缓冲区,但您犯了两个错误,这可能会导致您分配的内存超出您的需要。
- 您从文件中的任意位置开始,但分配内存就像从文件开头开始一样。分配
ftell(file) - threshold
字节。 - 你分配的内存太多了。
sizeof(uint8_t *)
应该改为sizeof(uint8_t)
。您分配的内存比应有的多 4 或 8 倍。
除此之外,在您写完之后重新分配缓冲区有什么意义?内存溢出已经发生。您应该在写入之前分配(在 while 循环内)。不过,我根本看不到重新分配的意义,因为您分配的内存已经足够多了。
代码不return指向字符串的指针。
returned buffer
中没有 空字符,因此调用代码无法知道已分配内存的长度。这肯定会导致调用代码出错。
当re-allocating时,加1。
// buffer = realloc(buffer, ct * sizeof(uint8_t*));
// v--- no star
buffer = realloc(buffer, ct * sizeof(uint8_t ) + 1);
buffer[ct] = '[=10=]';
// or better
size_t ct = 0;
...
buffer = realloc(buffer, sizeof *buffer * (ct + 1));
buffer[ct] = '[=10=]';
Is there any way to dynamically change the size of the
arrayallocated memory depending on the the current iteration without always usingrealloc
?
数组大小无法更改。要动态更改已分配内存的大小需要 realloc()
。注意:所需的内存量可以在内存分配调用之前确定。
or is there an way to determine how long the current line is by using
ftell
andfseek
?
像这段代码一样,您找到了当前行长度的上限。 ftell
和 fseek
没有找到行尾。
代码可以 "seek" 到行尾 fscanf(file, "%*[^\n]");
或 1 之后的 fgetc(file)
.
以下代码:
- 干净地编译
- 执行所需的操作
- 正确处理错误情况
- 正确声明变量类型
- 正确地 return 是
char*
而不是uint8_t*
- 留下悬而未决的问题:为什么 return 是所需缓冲区长度的 2 倍
- 传入参数为NULL时显示的错误信息不正确。建议更改以指示传入的文件指针为 NULL
- OP 发布的代码无法检查每次调用
fseek()
的 returned 值,也无法检查每次调用ftell()
的 return 值应该这样做以确保操作成功。我没有在我的答案中添加错误检查,以免代码混乱,但是,应该执行它。
现在,代码:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
char* fs_read_line(FILE* file);
char* fs_read_line(FILE* file)
{
if ( !file )
{
return "CFILEIO: Error while reading the file: Invalid File";
}
// implied else, valid parameter
long threshold = ftell(file);
fseek(file, 0, SEEK_END);
char* buffer = calloc( (size_t)(ftell(file) - threshold) *2 +1, sizeof(char));
if(buffer == NULL)
return NULL;
// implied else, calloc successful
int ch;
fseek(file, threshold, SEEK_SET);
size_t ct;
while ( (ch = fgetc(file)) != '\n'
&& ch != '[=10=]'
&& ch != '\r'
&& ch != EOF)
{
buffer[ct++] = (char)ch;
}
return buffer;
} // end function: fs_read_line