c++ - 从二维整数数组中的文件读取
问题描述
我是 C++ 编码的新手,我需要从这种结构的文件中读取:
8
1 0 0 0 1
1 1 1 0 0
1 1 0 0 0
1 1 1 1 0
5
我需要将数字读入 2 个不同的 int 变量(8 和 5),其余的读入 2d int 数组。
到目前为止我所拥有的:
#include<fstream>
#include<iostream>
#include<conio.h>
using namespace std;
ifstream fin("f.in");
ofstream gout("g.out");
int a[30][30], n, x;
int main()
{
fin>>n;
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
{
fin>>a[i][j];
}
fin>>x; c[1]=x; s[x]=1;
//other function call .....
for(i=1; i<=n; i++)
gout<<c[i]<<" ";
return 0;
}
代码正在构建和编译,但是它不会从文件中读取。
解决方案
如果您仍然卡住,那么让我们一步一步来。
首先不要硬编码文件名。(并且不要使用magic-number,例如任何数字卡在你的代码中,而不是为它正确定义一个常量)。ifstream fin("f.in");
如果您有另一个文件"f.int2"
要阅读怎么办?这就是函数参数的用途。因为main()
你已经argc
告诉你给出了多少个参数,并且argv
,一个指向每个参数的指针数组(后跟一个终止NULL
指针)。使用它们。例如:
int main (int argc, char **argv) {
...
if (argc < 2) { /* validate 1-argument available for filename */
std::cerr << "error: insufficnent input\nusage: " << argv[0]
<< " filename\n";
return 1;
}
std::ifstream fin (argv[1]); /* open filename given by 1st argument */
(注意:第一个参数值 ,argv[0]
始终是正在运行的可执行文件名称,因此您必须检查总共两个参数以确保其中有内容argv[1]
)
接下来验证文件是否已打开以供读取,例如
if (!fin.good()) { /* validate file open for reading */
std::cerr << "error: file open failed '" << argv[1] << "'.\n";
return 1;
}
现在让我们来阅读您的输入文件,我将命名2dintarr+stuff.txt
并将其放在dat
子目录中,例如
示例输入文件
$ cat dat/2dintarr+stuff.txt
8
1 0 0 0 1
1 1 1 0 0
1 1 0 0 0
1 1 1 1 0
5
的"+stuff"
存在8
与5
您要存储的二维值数组无关。8
和很容易处理,只需将5
整行读入 a string
,从该行创建 a stringstream
,然后循环并从字符串流中读取整数,直到用完要读取的数字。如果您在用完数字之前只读取一个值,那么您可以简单地将这些值存储在不是您的数组的某个位置(例如在一个名为 的向量中notarr
)。如果该行中有多个值,则将所有值存储在一个向量中,并将该向量作为一行添加到向量向量中。
听起来很复杂,但事实并非如此。C++ 提供了容器,允许您像使用数组一样向它们添加和删除值,但更好的是,容器会自动为您管理内存,根据需要分配更多内存,并在没有更多引用时释放内存容器。其中一个容器是vector
您可以简单地认为是一维数组的容器。C++ 允许容器包含其他容器。所以当你需要一个二维数组时,你想要的是一个向量的向量。
在您的情况下,您需要 astring
保存您读取的每一行数据,您需要arr
数组的向量向量,然后是另一个单个向量来保存"+stuff"
不属于您的数组的部分 - 称为notarr
. 声明如下:
#include <string>
#include <vector>
...
std::string line; /* string for reading each line */
std::vector<std::vector <int>> arr; /* vector<vector<int>> (2D arr) */
std::vector<int> notarr; /* vector to hold single values */
现在剩下的就是读取每一行,然后从该行创建一个字符串流,这样您就可以从该行循环读取整数,直到用完要读取的数字。(您不能只fin >> number;
在循环中使用,因为读取 iostream 将跳过前导空白,'\n'
即空白,因此尝试>>
在文件流本身上使用 - 您永远无法判断行中有多少值,>>
只会跳过'\n'
as whitespace .
如何解决?使用stringstream
. 基本上,字符串流相当于可以用作流的缓冲区。因此,您从文件中读取一行数据,从中创建一个字符串流,然后循环while (ss >> value)
当它到达字符串流(即缓冲区)的末尾时将停止,因为没有其他可读取的内容允许您确定有多少值包含在原始行中。(您将一遍又一遍地使用此技术)
例子:
while (getline (fin, line)) { /* read each remaining data line */
int i;
std::vector<int> tmp; /* vector<int> for each line */
std::stringstream ss (line); /* stringstream to read from */
while (ss >> i) /* read int from stringstream */
tmp.push_back(i); /* add to tmp vector */
if (tmp.size() == 1) /* if single value in line */
notarr.push_back(i); /* add value to notarr */
else if (tmp.size() > 1) /* if multiple values in line */
arr.push_back(tmp); /* add tmp vector to arr */
}
在上面,您只需将每一行读入line
,创建 stringsteam ss
,然后使用临时向量tmp
,将每个值加载到临时向量中。tmp
完成后,您只需检查向量中有多少元素。如果一个,它是8
or 5
,将它添加到 vector notarr
,如果它超过一个,tmp
包含你的二维数组的一行,所以添加它 do arr
。而已。
总而言之,您可以执行以下操作:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <limits>
int main (int argc, char **argv) {
std::string line; /* string for reading each line */
std::vector<std::vector <int>> arr; /* vector<vector<int>> (2D arr) */
std::vector<int> notarr; /* vector to hold single values */
if (argc < 2) { /* validate 1-argument available for filename */
std::cerr << "error: insufficnent input\nusage: " << argv[0]
<< " filename\n";
return 1;
}
std::ifstream fin (argv[1]); /* open filename given by 1st argument */
if (!fin.good()) { /* validate file open for reading */
std::cerr << "error: file open failed '" << argv[1] << "'.\n";
return 1;
}
while (getline (fin, line)) { /* read each remaining data line */
int i;
std::vector<int> tmp; /* vector<int> for each line */
std::stringstream ss (line); /* stringstream to read from */
while (ss >> i) /* read int from stringstream */
tmp.push_back(i); /* add to tmp vector */
if (tmp.size() == 1) /* if single value in line */
notarr.push_back(i); /* add value to notarr */
else if (tmp.size() > 1) /* if multiple values in line */
arr.push_back(tmp); /* add tmp vector to arr */
}
std::cout << "2D array of values:\n\n";
for (auto& i : arr) { /* loop over rows */
for (auto& j : i) /* loop over each value in column */
std::cout << " " << j; /* output value */
std::cout << '\n'; /* tidy up with newline */
}
std::cout << "\nSingle-values:\n\n";
for (auto& i: notarr) /* output values not part of array */
std::cout << " " << i;
std::cout << '\n'; /* tidy up with newline */
}
(注意: vector 容器提供了.push_back()
和.size()
成员函数,让您可以向向量添加一个值,并告诉您其中包含许多元素。)
示例使用/输出
$ ./bin/rd2dintarr+stuff dat/2dintarr+stuff.txt
2D array of values:
1 0 0 0 1
1 1 1 0 0
1 1 0 0 0
1 1 1 1 0
Single-values:
8 5
如果您还有其他问题,请仔细查看并告诉我。
推荐阅读
- scala - 从 UDF 中的 Dataframe 创建一列 ArrayType[StructType]
- hololens - HoloLens2:我想在用户正在看的表面网格上绘制一个目标
- python - 类如何从基类继承
- mysql - 如何简化我的代码以阻止它使服务器崩溃?
- matlab - 如何在图像上旋转多行
- javascript - 我可以使用父函数的参数来命名它的子函数吗?
- r - 更改 ggplot 中变量名称的字体大小
- algorithm - 如何从给定的递归函数中找到递归关系
- python - 无法使用 PyMySQL 与远程 MySQL 服务器建立 TLS TCP 连接,其他工具可以工作
- javascript - 根据 HTML 中的选项标签,以不同的语言显示星期几