我正在为一个大文件编写一个解析器,我负责从输入文件中读取的一个函数有一个名为peek
的char缓冲区。基本上,当main
重复调用此函数时,peek
最终会被一些奇数值覆盖。这是main
调用的函数。 bufferAsInt
:
void bufferAsInt(ifstream &inf, int &i)
{
char peek[3];
inf.read(peek, 3);
i = atoi(peek);
//I'm not using the >> operator to read an int because the int is just
//3 chars long in the input file and two consecutive integer values can
//be written like this: 123456 for 123 and 456.
}
我发现当我将这些值写入输出文件时,当读取只有两位数的int值时,第三个数字(或其他一些数字)将留在char缓冲区peek
中并且该值将被错误地写入输出文件(这只发生在从输入文件中读取非常大量的数据之后。)因此,经过数万次迭代,当读取像15
这样的数字时,将写入我的输出文件的值可能类似于156
。
为了解决这个问题,我将bufferAsInt
的实现更改为:
void bufferAsInt(ifstream &inf, int &i)
{
char *peek = new char[3];
inf.read(peek, 3);
i = atoi(peek);
delete [] peek;
}
(当然我猜的是问题是什么)。我想知道的是,如果我的问题得到解决的事实是在堆上声明这个char缓冲区或者如果问题实际上是我的程序已经用完的某种奇怪后果堆栈记忆。
我的计算机上有6GB的RAM,在运行时,没有其他程序可以使用足够的内存来解决这个问题。
答案 0 :(得分:2)
你是一个人。
atoi
期望以null结尾的字符串。因此,三位数字需要char[4]
才能正确存储。此外,read
不会在结尾处放置空值。
试试这个:
void bufferAsInt(ifstream &inf, int &i)
{
char peek[4];
inf.read(peek, 3);
peek[3] = 0;
i = atoi(peek);
}
答案 1 :(得分:2)
atoi()
期望一个C'NUL终止字符串'作为输入,即ASCII字符后跟一个ASCII零字节。这是函数知道停止转换的唯一方法。
在您的第一个代码清单中,您将三个字节读入三字节缓冲区,但您无法控制内存中的后续字节。我相信这是C ++中未定义的行为,所以任何事情都可能发生。但是,通常情况下,如果后续字节恰好是零或非数字,则字符串将正确转换;如果碰巧是一个数字,你会得到一个不同的数字。
正确的解决方法是使用您的第一个示例,但是:
char peek[4]; // 4 char buffer instead of 3
inf.read(peek, 3);
peek[3] = '\0'; // ensure the 4th char is zero
i = atoi(peek);
答案 2 :(得分:0)
最有可能唯一改变的是new
,使用您的编译器和选项,将数组归零。
保证你可以写
char *peek = new char[3]();
但是动态分配没有任何意义,所以请这样做:
char peek[3] = {};
注意:如果文件包含3位数字,那么您应该使用四个位数组,以便有空间终止零。