如何从txt文件读取具有不同长度的多个数组?

时间:2018-10-24 22:55:49

标签: c++ arrays

我是C ++的新手,并尝试从文本文件中读取具有以下数据的某些数组:

Number_of_students 3
Number_of_assignments 3
Paul Smith 5 6 7
Tina Smith 6 7 7
Andrew Smith 4 5 10

我需要做的是将名称放入一个数组中,并将其后的数字放入一个单独的数组中。下面是我的代码,每当我尝试从一个数组中输出一个值时,我都会得到0。

#include <string>
#include <fstream>
#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    const int MAX_CLASS_SIZE = 100;
    const int MAX_NUMBER_OF_ASSIGNMENTS = 100;
    string names[MAX_CLASS_SIZE][2]
    int scores[MAX_CLASS_SIZE][MAX_NUMBER_OF_ASSIGNMENTS]
    int number_of_students
    int number_of_assignments

    ifstream file;
    file.open("grades.txt");

    if (file.is_open())
    {
        string nos;
        string noa;

        file >> nos >> number_of_students;
        file >> noa >> number_of_assignments;

        for (int i = 0; i < number_of_students; i++) {
            for (int j = 0; j < 2; j++) {
                for (int s = 0; s < number_of_assignments; s++) {
                    file >> names[i][j] >> scores[i][s];

                }
            }
        }

        file.close();
    }

    else cout << "Unable to open file";
    return 0;
}

2 个答案:

答案 0 :(得分:2)

您正在阅读每个学生的6个名字和6个分数。

       for (int j = 0; j < 2; j++) {
            for (int s = 0; s < number_of_assignments; s++) {
                file >> names[i][j] >> scores[i][s];

            }
        }

我想你的意思是

       for (int j = 0; j < 2; j++) {
           file >> names[i][j];
       }
       for (int s = 0; s < number_of_assignments; s++) {
           file >> scores[i][s];
       }

如果可以解决。是时候对其进行最佳实践审查:CodeReview

答案 1 :(得分:1)

#include <cstddef>  // std::size_t
#include <cstdlib>  // EXIT_FAILURE
#include <string>
#include <fstream>
#include <iostream>

int main()
{
    // All caps for MAX_CLASS_SIZE and MAX_NUMBER_OF_ASSIGNMENTS suggests
    // that you #defined them. Better use constant expressions than preprocessor
    // defines since they are typesafe:
    constexpr std::size_t MAX_CLASS_SIZE{ 42 };            // I don't know what would        
    constexpr std::size_t MAX_NUMBER_OF_ASSIGNMENTS{ 42 }; // be good numbers.

    std::string names[MAX_CLASS_SIZE];
    int scores[MAX_CLASS_SIZE][MAX_NUMBER_OF_ASSIGNMENTS];
    std::size_t number_of_students;     // std::size_t because it is guaranteed that
    std::size_t number_of_assignments;  // it is big enough to hold all possible sizes
                                        // of objects in memory and indexes into arrays.

    char const *filename{ "scores.txt" };  // give it a name so you can use it in
                                           // error messages
    std::ifstream file{ filename };        // use the constructor of ifstream to
                                           // open the file
    if (!file.is_open()) {  // if the file couldn't be opened exit early instead
                            // of encasing everything in one giant if-block
        std::cerr << "Couldn't open \"" << filename << "\" for reading :(\n\n";
        return EXIT_FAILURE;
    }

    std::string dummy;  // i named it dummy cause thats just what it is

    // always check if read operations didn't fail:
    if (!(file >> dummy >> number_of_students >> dummy >> number_of_assignments)) {
        std::cerr << "Couldn't read number of students and/or number of assignments from \""
                  << filename << "\" :(\n\n";
        return EXIT_FAILURE;
    }

    if (number_of_students > MAX_CLASS_SIZE ||
        number_of_assignments > MAX_NUMBER_OF_ASSIGNMENTS)
    {
        std::cerr << "I am sorry, but I was not designed to handle more than " 
                  << MAX_CLASS_SIZE << " Students or more than "
                  << MAX_NUMBER_OF_ASSIGNMENTS << " assignments :(\n\n";
        return EXIT_FAILURE;
    }

    std::size_t num_students_read{}; // keep track of how many students we read

                                                 //   / only continue if reading
                                                 //  /  didn't fail
    for (std::size_t i{}; i < number_of_students && (file >> names[i]); ++i) {

        // As long as the next thing we read is not the first score it is
        // part of the name:
        std::string name_part;
        while (!(file >> scores[i][0]) && (file.clear(), (file >> name_part))) {
            names[i] += ' ';
            names[i] += name_part;
        }

        // We read the name and the first score.
        // Now read the following number_of_assignments - 1 scores:

        std::size_t num_scores_read{ 1 };    // keep track of how many scores we actually read
        for (std::size_t s{1}; s < number_of_assignments && (file >> scores[i][s]); ++s)
            ++num_scores_read;

        if (num_scores_read != number_of_assignments) {  // and check if the number
                                                         // of scores read matches
                                                         // the number that was
                                                         // promised
            std::cerr << "There are scores missing for " << names[i] << " :(\n\n";
            return EXIT_FAILURE;
        }
        ++num_students_read;
    }

    if (num_students_read != number_of_students) {
        std::cerr << "There sould be " << number_of_students << " students but I was "
                  << "only able to read " << num_students_read << " :(\n\n";
        return EXIT_FAILURE;
    }

    // print what we read:
    for (std::size_t i{}; i < number_of_students; ++i) {
        std::cout << names[i] << ": ";
        for (std::size_t s{}; s < number_of_assignments; ++s)
            std::cout << scores[i][s] << ' ';
        std::cout.put('\n');
    }

    // no need for file.close() ... the destructor of ifstream will
    // take care of that.
}