- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在从标准输入读取具有以下形式的文本文件:
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
,使用它们会让你变得更容易并且更不容易出错。在这里,虽然您可以读取第一个值 N
,但当您使用 std::vector
进行存储时则不需要它。 STL 容器自动处理所需的存储,因此您真正关心的是从文件中读取实际数据值,然后使用 .push_back()
成员函数将值添加到 vector 中。
不要在代码中硬编码文件名。这就是 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()
。
打开文件后,以最简单的形式,您可以简单地使用重载的 >>
流运算符从文件中读取值。您必须验证每次读取,以确保杂散的非数字字符确实会导致匹配失败,并在输入流上设置失败的流状态。例如,要检查 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
失败而退出,在第二种情况下,我们只是不输入包含其余代码的 block (即现在向右移动了一层缩进...)
读取其余值并填充 vector 只需以相同方式读取临时值tmp
,然后在确认读取正确后,只需将该值添加到您的 vector 中即可。使用 .push_back()
成员函数的 vector ,例如
while (f >> tmp) /* read remaining int values into vector v */
v.push_back(tmp);
(注意:读取数值时,所有空格都会被忽略。这意味着文件中是否剩余 1 行或 1000 行整数值 - 全部将被读入您的 vector 。所有 '\n'
都会被忽略,因为 '\n'
是空白。这就是您使用的地方getline()
和 std::stringstream
(如果您只需要读取单行中的值)
读取第一个 N
仅适用于与 vector 的 .size()
进行比较,您现在可以使用它来确认您已读取 N
值到你的 vector 中,例如
if (v.size() != (size_t)N) { /* valdate .size() == N */
std::cerr << "error: number read does not equal N.\n";
return 1;
}
您可以对 vector v
中的值执行任何您喜欢的操作。在这里,它们只是使用基于范围的for循环进行输出,并将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
这个故事的寓意——不要使用 scanf
。对于新 C/C++ 程序员来说,它充满了陷阱,而且它的不当使用会在本网站上产生如此多的问题,建议使用 scanf 就等于编程不当> 解决方案。检查一下,如果您还有其他问题,请告诉我。
关于c - 如何将未知数量的整数扫描到数组中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58961026/
我是一名优秀的程序员,十分优秀!