考虑以下代码。此函数从文件中读取一些整数和字符串。
const int vardo_ilgis = 10;
void skaityti(int &n, int &m, int &tiriama, avys A[])
{
ifstream fd("test.txt");
fd >> n >> m >> tiriama;
fd.ignore(80, '\n');
char vard[vardo_ilgis]; // <---
for(int i = 1; i <= n; i++)
{
cout << i << ' ';
fd.get(vard, vardo_ilgis+1); // <---
cout << i << endl;
A[i].vardas = vard;
getline(fd, A[i].DNR);
}
fd.close();
}
并输入:
4 6
4
Baltukas TAGCTT
Bailioji ATGCAA
Doli AGGCTC
Smarkuolis AATGAA
在这种情况下,变量'vard'的长度为vardo_ilgis = 10,但在函数fd.get中,读取输入为vardo_ilgis + 1 = 11(大于存储数据的可变长度)。我不是在问如何解决问题,因为显然不要读取比存储在变量上更多的内容。 但是,我真的想了解这种行为的原因:循环计数变量减少了fd.get。为什么以及如何发生这种情况呢?这是这段代码的输出:
1 0
1 0
1 0
1 0
1 1
2 2
3 3
4 4
答案 0 :(得分:0)
你为什么用+1
?
fd.get(vard, vardo_ilgis+1);
超越该缓冲区会破坏一些内存。在一个简单的未经优化的构建中,损坏的内存可能是循环索引。
循环计数变量减少了fd.get。为什么以及如何发生这种情况呢?
一旦你知道为什么你造成了未定义的行为,许多人说你不应该调查这个未定义行为的细节。我不同意。通过了解详细信息,您可以提高诊断其他情况的能力,在这些情况下您不知道可能调用了哪些未定义的行为。
所有局部变量都存储在一起,因此覆盖一个会倾向于破坏另一个。
您将变量描述为“减少”,而实际上它已设置为零。在归零之前它是1的事实并没有影响它的归零。未定义的行为恰好等同于i&=~255;
,其中256以下的值等于i=0;
。您可以将其视为i--;
希望很明显为什么i
在输入用完后停止归零。
答案 1 :(得分:0)
fd.get(vard, vardo_ilgis+1);
使缓冲区写入越界。
在您的情况下,您编写的区域(以及您不应该写的区域)可能与存储i
的内存区域相同。
但是,最重要的是你最终得到了如此着名的不确定行为。这意味着什么都可能发生,并且没有必要试图理解为什么或如何(平台,编译器甚至特定于上下文的情况会发生什么,我认为任何人都无法预测或解释它。)