我正在从标准输入中读取具有以下格式的文本文件:
5
4 7 9 2 1
其中第一行是我每次要创建的数组的大小,第二行是元素
到目前为止,我有这个
int main()
{
int N;
int i;
FILE *fp;
const char *mode="r";
fp=fopen("input.txt", "r");
if((fp=fopen("input.txt", "r"))==NULL) {
printf("Error opening file %s\n");
return -1;
}
fscanf(fp, "%d", &N);
int a[N];
int n;
while (fscanf(fp, "%d %n", &a[i], &n) == 1){
i++;
fp += n;
}
fclose(fp);
return 0;
}
它读取文件,但没有存储正确的值
除非您不能使用STL中的容器,例如std::vector
,否则使用它们将使容器变得更容易且更不易出错。在这里,虽然您可以读取第一个值std::vector
,但在使用N
进行存储时则不需要它。 STL容器自动处理所需的存储,因此您真正关心的就是从文件中读取实际数据值,然后使用std::vector
成员函数将值添加到向量中。
.push_back()
的参数所针对的(或者您可以将文件名作为输入)。例如,您可以这样做:int main (int argc, char **argv)
无需对您的文件名进行硬编码,只需将其作为参数传递给,以确保杂散的非数字字符确实导致匹配失败,并在输入流上设置失败的流状态。例如,检查int main (int argc, char **argv) { int N, tmp; /* int N and temporary int to use filling vector */ std::vector<int> v; /* vector of int */ if (argc < 2) { /* valdate 1 argument given for filename */ std::cerr << "usage: " << argv[0] << " filename\n"; return 1; } std::ifstream f (argv[1]); /* open file */ if (!f.good()) { /* validate file open */ std::cerr << "error: file open failed.\n"; return 1; }
。以最简单的形式打开文件,您只需使用重载的
main()
流运算符即可从文件中读取值。您每次读取必须validate
>>
的读取是否良好(在这里还不错),您可以这样做:N
由于除非读取良好,否则打算退出,因此使用了if (!(f >> N)) { /* read/validate N */ std::cerr << "error: invalid integer input - N.\n"; return 1; }
形式。 (这也减少了构建到代码中的缩进级别)。您可以完成:
!(f >> N)
验证是相同的,但是在第一种情况下,我们在读取if (f >> N) { /* read/validate N */ /* rest of your code goes here on good read */ }
失败时退出,在第二种情况下,我们只是不进入包含其余代码的代码块(此代码现在又移动了一层)向右缩进...)读取其余的值并填充向量只是以相同的方式读取临时值
N
的问题,然后在确认良好的读取之后,您只需使用tmp
将值添加到向量中成员函数,例如
.push_back()
(的数字值将被忽略。这意味着您是否在文件中剩余1行或1000行整数值-所有这些都将被读取到向量中。因为note:读取所有whitespace
while (f >> tmp) /* read remaining int values into vector v */
v.push_back(tmp);
是whitespace,所以所有的'\n'
都将被忽略。如果只需要读取一行中的值,可以在这里使用'\n'
和getline()
。读取第一个std::stringstream
仅适合与向量的N
进行比较,您现在可以使用它来确认已将.size()
值读取到向量中,例如N
您可以对向量进行循环并重新设置if (v.size() != (size_t)N) { /* valdate .size() == N */ std::cerr << "error: number read does not equal N.\n"; return 1; }
中的值执行任何您喜欢的操作。在这里,它们只是使用基于范围
v
作为计数器的输出,也可以输出索引:tmp
将其完全放在一起,您可以做:
tmp = 0; for (auto& n : v) /* loop over all values in v outputting */ std::cout << "v[" << tmp++ << "] : " << n << '\n';
示例使用/输出
将数据保存在文件#include <iostream> #include <fstream> #include <vector> int main (int argc, char **argv) { int N, tmp; /* int N and temporary int to use filling vector */ std::vector<int> v; /* vector of int */ if (argc < 2) { /* valdate 1 argument given for filename */ std::cerr << "usage: " << argv[0] << " filename\n"; return 1; } std::ifstream f (argv[1]); /* open file */ if (!f.good()) { /* validate file open */ std::cerr << "error: file open failed.\n"; return 1; } if (!(f >> N)) { /* read/validate N */ std::cerr << "error: invalid integer input - N.\n"; return 1; } while (f >> tmp) /* read remaining int values into vector v */ v.push_back(tmp); if (v.size() != (size_t)N) { /* valdate .size() == N */ std::cerr << "error: number read does not equal N.\n"; return 1; } tmp = 0; for (auto& n : v) /* loop over all values in v outputting */ std::cout << "v[" << tmp++ << "] : " << n << '\n'; }
中,您将按如下所示使用该程序来生成以下输出:
dat/nint.txt
故事的寓意-请勿使用
$ ./bin/readnint dat/nint.txt
v[0] : 4
v[1] : 7
v[2] : 9
v[3] : 2
v[4] : 1
。对于新的C / C ++程序员来说,这真是个陷阱,如果使用不当,会在此站点上产生很多问题,这等于要提出scanf
解决方案。仔细检查一下,如果还有其他问题,请告诉我。