如何在 C++ 中将文本文件读入二维数组?

how do I read a textfile into a 2D array in 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>>,但我怀疑二维数组是一项赋值要求——知道如何处理基本类型的数组也很好——遗留代码中有很多)。通过从文件中读取每一行并填充 stringstream 然后使用 ',' 作为分隔符使用 getline 进行解析,一切看起来都很好。

您缺少的是防止读取的列多于存储空间和行多于声明的保护。如果您的文件包含 恰好 您为数组声明的值的数量,这不会影响您从文件中读取值,但正确使用基本类型的数组至关重要.它们的大小是固定的,如果您尝试超出数组范围进行写入(您只会破坏程序堆栈)

,则没有 auto-allocation 可以拯救您

你如何保护你的数组绑定?很简单,只需检查当前行不超过分配的数量并且列数相同,例如

    /* 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_argumentstd::out_of_range) 必须处理。您不能简单地猜测所有输入文件都将采用具有正确值的所需格式并希望得到最好的结果——您必须 验证每个输入 .

这也适用于每行中的列数(以及 read-loop 完成后填充的行数)。当您完成从 stringstring 的读取后,您需要验证读取的 column-values 的数量是预期的数量并且您没有遇到短行。 注意:这些是需要的minimum-validations。您可以自由编写额外的验证,例如检查以确保 stringstring 为空,并且额外的值不会保持未读状态(对代码的操作不重要,但可能会标记格式无效的输入文件)

最后,虽然代码的其余部分只是输出值,但请看一下 Why is “using namespace std;” considered bad practice?。早点养成好习惯。这也意味着 不要硬编码文件名 main() 的参数提供了一种在启动时将所需信息传递到程序中的方法——使用它们,或者至少提示输入要打开的文件名。

此外,编译时始终启用警告。这意味着 -Wall -Wextra -pedantic -Wshadow 对应 gcc/clang 和 VS /W3。包括 -Wshadow 你会发现你隐藏了之前在 for (int c=0; c<col; c++)

中对变量 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 语句是可选的,但在代码顶部提供了一个方便的位置,以便在需要时调整常量)

例子Use/Output

当您在 dat/2darr.csv 中输入文件时,您将执行并收到以下输出:

$ ./bin/read2darrcsv dat/2darr.csv
 2 4 5 6
 3 7 5 3
 4 8 4 2
 6 7 3 0

如果您还有其他问题,请告诉我。