c++ - 如何在 C++ 中将文本文件读入二维数组?
问题描述
我真的很努力尝试将逗号分隔的整数文本文件传递到 C++ 中的二维数组中。例如,如果文本文件看起来像
2,4,5,6 3,7,5,3 4,8,4,2 6,7,3,0
请问我怎样才能把它放入一个 4 x 4 的数组中?稍后我需要对其进行计算,一旦它位于二维数组中,我就知道如何计算。先感谢您
到目前为止我有
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
using namespace std;
int main()
{
const int row =4;
const int col =4;
int array[row][col];
int r =0;
int c =0;
ifstream inputfile("numbers.txt");
if (!inputfile.is_open())
{cout<<"error"<<endl;
}
string line,num;
int number;
while(get line(inputfile,line))
{
string stream ss(line);
getline(ss,num,',');
number= stop(num);
for (int r=0; r<row;r++)
{
for (int c=0; c<col; c++)
{
array[row][col] =number;
}
}
inputfile.close();
return 0;
}
解决方案
好消息是你已经收集了正确的拼图来做你想做的事情。坏消息是……你把拼图拼错了……(但不是很严重)。
关键是系统地编程您需要完成的每个步骤,以将 csv 文件读入二维数组。(你应该使用std::vector<std::vector<int>>
,但我怀疑 2D 数组是一个赋值要求——知道如何处理基本类型的数组也很好——遗留代码中有很多)。一直到从文件中读取每一行并填充stringstream
,然后getline
使用','
作为分隔符进行解析,一切看起来都很好。
您缺少的是防止读取的列多于您的存储空间和多于您声明的行数的保护措施。虽然如果您的文件包含您为数组声明的值的数量,这不会影响您从文件中读取值,但这对于正确使用基本类型的数组至关重要。它们的大小是固定的,如果您尝试写入超出数组的范围(您只会损坏程序堆栈),没有自动分配可以节省您的时间
你如何保护你的数组绑定?简单,只需检查当前行不超过分配的数量并且列的数量相同,例如
/* read each line, protect row bounds */
while (r < row && getline (inputfile,line)) {
int c = 0; /* declare c local to loop so it is reset each iteration */
std::string num;
std::stringstream ss (line);
/* loop reading from stringstream, protect column bounds */
while (c < col && getline (ss, num, ',')) {
try { /* try/catch exception handling required for stoi conversion */
array[r][c++] = std::stoi (num); /* convert, increment col count */
}
catch (const std::exception & e) {
std::cerr << "error: invalid conversion " << e.what() << '\n';
return 1;
}
}
if (c != col) { /* validate col number of values read & stored */
std::cerr << "error: invalid number of columns '" << c << "' row: "
<< r << '\n';
return 1;
}
r++; /* increment row count */
}
还要注意try/catch
异常处理的使用。当使用std::stoi
这是您必须验证转换的唯一方式时,请参阅cppreference.com - std::stoi并注意Exception标题详细说明了必须处理的两个异常 (std::invalid_argument
和)。std::out_of_range
您不能简单地猜测所有输入文件都将采用具有正确值的所需格式并希望获得最好的结果——您必须验证每个输入。
这也适用于每行中的列数(以及完成读取循环时填充的行数)。完成读取后stringstring
,您需要验证读取的列值的数量是预期的数量,并且您没有遇到短行。注意:这些是所需的最低验证。您可以自由编写其他验证,例如检查以确保stringstring
为空并且附加值不会保持未读状态(对代码的操作不重要,但可能会标记格式无效的输入文件)
最后,虽然代码的其余部分只是简单地输出值,但请看一下为什么“使用命名空间 std;” 被认为是不好的做法?. 早日养成好习惯。这也意味着不要硬编码文件名。提供在启动时将所需信息传递到程序中的方法的参数main()
- 使用它们,或者至少提示打开文件名。
此外,始终在启用警告的情况下进行编译。这意味着-Wall -Wextra -pedantic -Wshadow
gcc/clang 和 VS /W3
。包括-Wshadow
你会发现你隐藏了先前的变量c
声明for (int c=0; c<col; c++)
总而言之,您可以执行以下操作:
#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#define ROW 4 /* while const int is fine, if you #define your constants */
#define COL ROW /* you have one single location at the top to make changes */
int main (int argc, char **argv) {
const int row = ROW, col = COL; /* optional, you can just use ROW & COL */
int array[row][col], r = 0;
std::string line;
if (argc < 2) { /* validate at least 1 argument given for filename */
std::cerr << "error: insufficient arguments\nusage: ./prog filename\n";
return 1;
}
std::ifstream inputfile (argv[1]); /* open file provided as 1st argument */
if (!inputfile.is_open()) { /* use std::cerr for error output, handle error */
std::cerr << "error: file open failed '" << argv[1] << "'.\n";
return 1;
}
/* read each line, protect row bounds */
while (r < row && getline (inputfile,line)) {
int c = 0; /* declare c local to loop so it is reset each iteration */
std::string num;
std::stringstream ss (line);
/* loop reading from stringstream, protect column bounds */
while (c < col && getline (ss, num, ',')) {
try { /* try/catch exception handling required for stoi conversion */
array[r][c++] = std::stoi (num); /* convert, increment col count */
}
catch (const std::exception & e) {
std::cerr << "error: invalid conversion " << e.what() << '\n';
return 1;
}
}
if (c != col) { /* validate col number of values read & stored */
std::cerr << "error: invalid number of columns '" << c << "' row: "
<< r << '\n';
return 1;
}
r++; /* increment row count */
}
if (r < row) { /* validate row number of arrays stored in 2D array */
std::cerr << "error: invalid number of rows '" << r << "'\n";
return 1;
}
for (r = 0; r < row; r++) { /* loop outputting results */
for (int c = 0; c < col; c++)
std::cout << " " << array[r][c];
std::cout << '\n';
}
}
(注意:这些#define
语句是可选的,但在代码顶部提供一个方便的位置,以便在需要时调整常量)
示例使用/输出
当您的输入文件位于 中时dat/2darr.csv
,您将执行并接收以下输出:
$ ./bin/read2darrcsv dat/2darr.csv
2 4 5 6
3 7 5 3
4 8 4 2
6 7 3 0
如果您还有其他问题,请告诉我。
推荐阅读
- python - 添加 DataFrame 列默认值时,如何将其限制为特定行?
- javascript - 拒绝加载脚本'
' 在 Chrome 扩展程序中 - python - 如何创建包含我的类实现的优先级队列?
- python - 图片不会在谷歌 Colaboratory 中使用 PIL 从响应对象中打开
- php - 如何修复 nav_menu.php 中的“非法字符串偏移 'output_key'”
- c++ - if 语句错误地识别括号中的空格
- java - 需要帮助修复绘制六边形的功能
- java - 使用 Apache POI XSSFWorkbook 时出现 NoClassDefFoundError
- r - 抓取拍摄位置的坐标数据和附加信息
- selenium - Google Chrome 窗口调整大小限制