阅读任意大小的任意数组

4
以下代码在读取包含两个 5x5 数组的两个 .txt 文件时可以正常工作。
    #include <iostream>
    #include <string>
    #include <fstream>
    #include <sstream>
    #include <stdio.h>
    #include <vector>
    #include <sstream>

    using namespace std;

    int main()
    {
        string myFile, mysecondFile, mystring;
        string DIR;
        string extension;
        int total = 0;

        int number_of_lines = 0;
        string line;

        extension = ".txt";
        DIR = "H:\\Year2\\EE273\\EE273\\Week6\\";

        cout << "Enter the name of the file: \t";
        cin >> myFile;
        cout << "Enter the name of the second file: \t";
        cin >> mysecondFile;

        myFile = DIR + myFile + extension;
        mysecondFile = DIR + mysecondFile + extension;

        ifstream inFile;
        ifstream inFile2;

    int i=5;
    int j=5;
    int i2=5;
    int j2=5;
    int i3=5;
    int j3=5;
    int k;
    int l;

int Array[5][5];
int Array2[5][5];
int Array3[5][5];
string attempt1,attempt2;
int row = 0;
int col = 0;
int row2 = 0;
int col2 = 0;//i = row
                    //y = column

inFile.open(myFile.c_str());


if (!inFile) {
    cout <<"Error opening file"<<myFile<<endl;
    return -1;
}

while (!inFile.eof())
{
    getline(inFile, attempt1);
    stringstream iss( attempt1 );
    string result;
    col = 0;
    while (getline( iss, result, ','))
    {
        //cout << result << endl;
        Array[row][col] = atoi(result.c_str());
        //j = j + 1;
        col = col + 1;

    }
    row = row + 1;
}
inFile.close();

inFile2.open(mysecondFile.c_str());
if (!inFile2) {
    cout <<"Error opening file"<<mysecondFile<<endl;
    return -1;
}
while (!inFile2.eof())
{
    getline(inFile2, attempt2);
    stringstream iss( attempt2 );
    string result2;
    col2 = 0;
    while (getline( iss, result2, ','))
    {   
        //cout << result2 << endl;
        Array2[row2][col2] = atoi(result2.c_str());
        col2 = col2 + 1;
    }
    row2 = row2 + 1;
}
inFile2.close();

/*for (int i=0;i<5;i++){
    for (int j=0; j<5; j++){
        cout<<Array[i][j]<<endl;}}
for (int i2=0;i2<5;i2++){
    for (int j2=0; j2<5; j2++){
        cout<<Array2[i2][j2]<<endl;
    }}

这里我正在执行两个矩阵之间的乘法,并将结果值写入第三个矩阵。

int Total=0;
i=0;
j2=0;
j=0;
j3=0;
for (i3=0; i3<5; i3++) {
    while(j3<5){
            while (j<5){
            for (i2=0;i2<5;i2++){
            Total += Array[i][j]*Array2[i2][j2];
            j++;
            Array3[i3][j3]=Total;

            }}
            j=0;
            j2++;
            j3++;
            Total=0;
            }
    i++;
    j=0;
    j2=0;
    j3=0;
    Total=0;
}

我的问题是:最简单的方法是什么,可以修改代码以便读取包含任意大小数组的两个 .txt 文件,然后成功执行乘法运算?

编辑不幸的是,我只能使用数组进行操作,不能使用向量。

我是否正确地认为涉及到了 new 运算符?


6
使用std::vector代替裸数组。 - Captain Obvlious
2
咦,你不觉得你应该在你的帖子中包含那个约束条件吗? - Captain Obvlious
@Paolokiller 我想你是指赋值... - Borgleader
1
@Paolokiller:编写一个类似于std::vector的东西(当需要超出当前容量时重新分配和移动元素),然后使用它来代替裸数组。(是的,这将涉及到newdelete。您还应该阅读有关三大法则的内容。指针操作很棘手,这就是为什么我们有友好的库设施如vector来管理它的原因。) - Mike Seymour
1
@Paolokiller:你的意思是你不能将数组封装在一个漂亮的类中以供管理吗?那真是一个奇怪的限制;但如果确实是这样的话,就在一个丑陋的未封装代码块中执行相同的操作(分配更大的数组,移动数据并删除旧的数组)。 - Mike Seymour
显示剩余2条评论
3个回答

3

最“简单”的方法是有些幼稚,类似于全面读取文件以获取行数/列数,然后再次读取文件将值实际存储在矩阵中:

unsigned int rows = 0;
unsigned int cols = 0;

std::string line;
while (std::getline(inFile, line)) {
    rows++;
    std::stringstream ss(line);

    std::string col;
    while (std::getline(ss, col, ',')) {
        cols++;
    }
}

// Now allocate the rows*cols matrix
int** matrix = new int*[rows];
for (int i = 0; i < rows; i++) {
    matrix[i] = new int[cols];
}

// and read your values into the matrix ...
// matrix[m][n] = xxx

读取文件两次效率比较低,并且还有其他方法可以预先获取大小。例如,您可以在输入文件中约定包含矩阵的宽度/高度:

[infile.txt]
3,3
1,2,3
4,5,6
7,8,9

现在您可以读取文件的第一行,然后就会知道这个文件的其余部分包含一个3x3矩阵。使用new(类似于上面的示例)分配您的矩阵,然后继续将文件的其余部分读入其中。 记得使用delete[]清理您动态分配的矩阵。每次调用new都应该有1次对delete的调用。
for (int i = 0; i < rows; i++) {
    delete[] matrix[i];
}
delete[] matrix;

这正是我一直在寻找的。只要getline继续找到值,行和列就会增加。我稍后会尝试这段代码,但我相信它会完美地工作。你为什么说它效率低呢?如果我们想打开内容未知的两个.txt文件,这不是最有效的解决方案吗? - Paolo
1
@Paolokiller 做两次同样的事情总是比做一次要花更多的时间。特别是,从磁盘读取文件通常是一个缓慢的操作,因此您需要避免重复执行它。在我的答案中,我包括了一种这样做的方法:在数据之前包含矩阵的宽度/高度 :) 您还可以将文件存储为二进制文件,并使用 seekg()tellg() 确定其大小,但这会带来其他复杂性(例如,不可读)。如果允许的话,std::vector 也可以工作。解决方案之间总是存在权衡。 - Julian

1
最简单的方法是要求文件包含矩阵大小作为其第一个条目。有了这个,您可以回退到使用C语言(C++不支持动态大小的矩阵),并执行以下操作:
  1. Read the dimension of the matrix into variables width and heigh.

  2. Allocate the matrix using

    int (*dynamicMatrix)[width] = malloc(height*sizeof(*dynamicMatrix));
    
  3. Reuse your code to fill the matrix.

如果无法回退到C语言,也无法使用std::vector<>,那么你唯一能做的就是使用双指针:
int**dynamicMatrix = new int*[height];
for(size_t i = width; i--; ) dynamicMatrix[i] = new int[width];

如果您能在文件中定义前两个数字来包含文件中矩阵的宽度和高度,那么这将是最简单的。如果您无法将这两个数字编码到文件中,则必须在进行操作时扩展动态数组:

size_t lines = 0, allocatedLines = 8;
int** dynamicMatrix = new int*[allocatedLines];
while(/* can read a line */) {
    if(lines == allocatedLines) {
        int** temp = new int*[allocatedLines *= 2];
        for(size_t i = lines; i--; ) temp[i] = dynamicMatrix[i];
        delete[] dynamicMatrix;
        dynamicMatrix = temp;
    }

    //add one line
    size_t curLineLength = 0, allocatedLineLength = 8;
    dynamicMatrix[lines++] = new int[allocatedLineLength];

    //fill the line
    ...
}

类似的块用于重新分配一行需要放入循环中,该循环用于读取单行元素。这很繁琐,但唯一提高的方法是使用你不允许使用的东西。


顺便说一下:即使是重新分配内存,在C语言中也更容易,因为它提供了realloc()函数:

size_t lines = 0, allocatedLines = 8;
int** dynamicMatrix = malloc(allocatedLines * sizeof(*dynamicMatrix));
while(/* can read a line */) {
    if(lines == allocatedLines) {
        //realloc takes care of copying the data to a new location (if that is necessary):
        allocatedLines *= 2;
        dynamicMatrix = realloc(dynamicMatrix, allocatedLines * sizeof(*dynamicMatrix));
    }

    //add one line
    size_t curLineLength = 0, allocatedLineLength = 8;
    dynamicMatrix[lines++] = malloc(allocatedLineLength * sizeof(**dynamicMatrix));

    //fill the line
    ...
}

由于在使用new/delete时没有与realloc()等效的函数,因此您需要在C++中使用std::vector<>或像上面那样自行复制。


1
我正在使用C++编写程序,因此我认为我不应该使用malloc。我最初处理这个问题的想法是使用getline读取txt文件,并有一个变量用于行和一个变量用于列,根据读取的文件递增。那样做有意义吗?我不确定如何操作,但我认为如果我可以让程序知道文件中有多少行/列,我就可以让其余部分正常工作... - Paolo
1
我现在已经删除了std::vector<>的提及,并用C++中不需要它的基本描述进行了替换。希望这有所帮助。 - cmaster - reinstate monica

1
使用std::vector而不是原始数组。例如,您可以将项目push_back到向量中。更重要的是,您可以仅在运行时中已知大小的情况下创建它,例如从文件中获取信息。

1
根据提问者的评论,向量不能使用,因为这是一项任务,并且他们被告知要使用数组。 - Borgleader
@Borgleader:是的,他在我回答后发布了那个。我不会追着变化的需求去做更改。 - Cheers and hth. - Alf
1
你可以随意处理这些信息,我只是提供了它。反正这个要求很愚蠢。 - Borgleader

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接