我正在编写一个程序,该程序从输入文件中读取有关分子的信息(电荷,多重性,原子类型及其坐标),但是由于某种原因,二维矢量数组被零填充,并找到一个不存在的原子进行协调也是零。我不知道如何正确调试它,所以我无法跟踪问题。
#include <iostream>
#include <cstdlib>
#include <string>
#include <fstream>
#include <cassert>
#include <vector>
int main(int argc, char* argv[])
{
if (argc > 1)
{
std::cout << "The input file is: " << argv[1] << std::endl;
} else
{
std::cout << "No arguments" << std::endl;
return 1;
}
const char *filename = argv[1];
std::ifstream inputfile(filename);
assert(inputfile.good());
int charge, multiplicity;
inputfile >> charge >> multiplicity;
std::cout << charge << " " << multiplicity << std::endl;
int natom;
std::vector<std::string> atomSymbol;
std::vector< std::vector<double> > position;
for (int i = 0; !inputfile.eof(); i++) {
std::string bufferAtomicSymbol;
double bufferPositionX;
double bufferPositionY;
double bufferPositionZ;
std::vector<double> bufferPosition(3);
inputfile >> bufferAtomicSymbol >> bufferPositionX >> bufferPositionY >> bufferPositionZ;
atomSymbol.push_back(bufferAtomicSymbol);
bufferPosition.push_back(bufferPositionX);
bufferPosition.push_back(bufferPositionY);
bufferPosition.push_back(bufferPositionZ);
position.push_back(bufferPosition);
}
inputfile.close();
natom = position.size();
std::cout << "There are " << natom << " atoms" << std::endl;
for (int i = 0; i < natom; i++)
std::cout << atomSymbol[i] << " " << position[i][0] << " " << position[i][1] << " " << position[i][2] << std::endl;
return 0;
}
输入文件示例:
0 1
C 1.11988 -0.11356 -0.04893
C -0.22149 0.53742 0.15390
N -1.36703 -0.23693 -0.04570
O -0.39583 1.70537 0.48392
H 1.93813 0.59458 0.13709
H 1.23188 -0.48457 -1.07645
H 1.25795 -0.96373 0.63239
H -2.27205 0.14808 0.07622
H -1.29145 -1.18667 -0.31244
程序输出:
The input file is: acetamide.xyz
0 1
There are 10 atoms
C 0 0 0
C 0 0 0
N 0 0 0
O 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
H 0 0 0
0 0 0
答案 0 :(得分:1)
您有两个主要问题困扰着您尝试从数据文件中成功读取数据,一个是特定问题,另一个是更笼统的问题,但这两个问题都同样致命。
通过阅读Why !.eof() inside a loop condition is always wrong.可以解决阅读中的技术问题。您面临的同样重要的更普遍的普遍问题是,您试图将胶带和捆扎线捆扎在一起的vectors
,strings
和doubles
的清单庞大。当您使用多余的或不合适的容器使数据处理过于复杂时,试图使它们协同工作就像将牙膏放回试管中一样-不会起作用。...
花一点时间,整理一下每个数据块需要存储的内容,然后创建一个保存该数据的数据结构。可以使用一些临时变量来方便地读取数据,但是数据的最终存储应该简单明了,并且要尽可能地简单。
在您的情况下,您将原子符号存储为string
和位置的三个double
值。您的基本数据结构应该能够将所有三个对象捕获为一个对象。尽管有两种选择,但是用于在不同类型的数据之间进行协调的普通struct
可以正常工作。然后,您只需创建 struct向量作为最终存储解决方案,以允许访问数据。
按照要求的简单性,您可以使用包含struct
和三个string
值的double
。例如:
struct atom {
std::string sym;
double x, y, z;
};
这就是捕获符号和位置坐标所需的全部。您只需声明一个 atom向量作为最终存储解决方案,例如
std::vector<atom> atoms; /* your final storage container */
整个代码中正在运行的主题将引发未定义行为,但该主题无法验证每个输入。如果您只是从流中读取而没有 validation (读取是否成功),那么您只是在玩Russian-Roulette。如果读取失败,并且您只是盲目地使用未初始化的变量继续前进,则假定已正确填充数据,结束了游戏。
因此请验证每次读取。例如,阅读charge
和multiplicity
,您可以执行以下操作:
if (!(fs >> charge >> multiplicity)) { /* validate EVERY input */
std::cerr << "error: invalid format: charge, multiplicity\n";
return 1;
}
(注意:,我已经缩短了您的变量名,例如inputfile
现在是fs
,键入不适合)
要从文件的每个后续行中读取每个原子,可以执行以下操作:
/* read each remaining line until you run out */
while (fs >> atmSymbol >> bposX >> bposY >> bposZ) {
/* add the values read to your temporary struct */
atom tmp = { atmSymbol, bposX, bposY, bposZ };
atoms.push_back(tmp); /* push tmp struct onto storage vector */
}
关键是验证每次读取的成功或失败,以便您知道您正在处理代码中的有效数据。
在一个简短的示例中将其余部分放在一起以读取数据文件,您可以执行以下操作:
#include <iostream>
#include <iomanip>
#include <fstream>
#include <array>
#include <string>
#include <vector>
struct atom {
std::string sym;
double x, y, z;
};
int main (int argc, char *argv[]) {
if (argc < 2) { /* validate at least one argument given for filename */
std::cout << "error: insuffient input.\n"
"usage: " << argv[0] << " <fn>\n";
return 1;
}
std::cout << "The input file is: " << argv[1] << '\n';
std::ifstream fs (argv[1]); /* file stream, just use argv[1] */
int charge, multiplicity, natom; /* temporary variables for filling */
double bposX, bposY, bposZ;
std::string atmSymbol;
std::vector<atom> atoms; /* your final storage container */
if (!(fs >> charge >> multiplicity)) { /* validate EVERY input */
std::cerr << "error: invalid format: charge, multiplicity\n";
return 1;
}
/* read each remaining line until you run out */
while (fs >> atmSymbol >> bposX >> bposY >> bposZ) {
/* add the values read to your temporary struct */
atom tmp = { atmSymbol, bposX, bposY, bposZ };
atoms.push_back(tmp); /* push tmp struct onto storage vector */
}
fs.close(); /* close stream -- you are done reading */
natom = atoms.size(); /* get an output size */
std::cout << "\nThere are " << natom << " atoms.\n\n";
for (auto& a : atoms) { /* loop over each atom in vector */
std::cout << a.sym /* output atomic symbol */
<< " " << std::setw(8) << a.x /* each coordinate, and */
<< " " << std::setw(8) << a.y
<< " " << std::setw(8) << a.z << '\n';/* tidy up with \n */
}
}
使用/输出示例
$ ./bin/atoms_read dat/atoms.txt
The input file is: dat/atoms.txt
There are 9 atoms.
C 1.11988 -0.11356 -0.04893
C -0.22149 0.53742 0.1539
N -1.36703 -0.23693 -0.0457
O -0.39583 1.70537 0.48392
H 1.93813 0.59458 0.13709
H 1.23188 -0.48457 -1.07645
H 1.25795 -0.96373 0.63239
H -2.27205 0.14808 0.07622
H -1.29145 -1.18667 -0.31244
仔细检查一下,如果还有其他问题,请告诉我。
根据请求处理文件中的空行进行更新
如果要在数据文件中读取其他由空行分隔的原子块,您要做的就是稍微重新排列读取范围,以使用getline
一次读取文件中的一行。然后,从该行创建一个stringstream
并从字符串流中读取,就像我们最初从文件中读取的一样。如果您可以有效地从字符串流中读取原子符号和位置坐标,那么您有一条有效的线。
使用getline
进行快速编辑并删除不再需要的临时变量(我们现在可以直接读取到临时结构中),您可以这样做:
std::ifstream fs (argv[1]); /* file stream, just use argv[1] */
int charge, multiplicity, natom; /* temporary variables for filling */
std::string line;
std::vector<atom> atoms; /* your final storage container */
if (!(fs >> charge >> multiplicity)) { /* validate EVERY input */
std::cerr << "error: invalid format: charge, multiplicity\n";
return 1;
}
/* read each remaining line until you run out with getline */
while (getline (fs, line)) {
std::stringstream ss (line); /* create stringstream from line */
atom tmp; /* declare temporary struct */
/* read from stringstream into temporary struct */
if (ss >> tmp.sym >> tmp.x >> tmp.y >> tmp.z)
atoms.push_back(tmp); /* push_back atmp struct on success */
}
fs.close(); /* close stream -- you are done reading */
现在,从第二行开始,代码将把与您的行格式匹配的所有原子数据读入atoms
向量中,而与文件中的空白行或其他不合格行无关。