Я хочу прочитать входной файл на С++, который включает следующие строки

- numberOfStates
- numberOfSymbols
- numberOfFinalStates
- list of final states (one per line)
- numberOfTransitions
- listOfTransitions (one per line. The transitions include two ints and one char)

Важно сказать, что числа разные в каждом входном файле. Мне приходится читать разное количество строк для каждого файла.

Это пример inputFile

10 
3 
1 
9 
12 
0 1 f 
0 3 f 
1 2 a 
2 9 f 
3 4 f 
3 8 f 
4 5 b 
5 6 f 
6 7 a 
8 9 f 

Как я могу объявить каждую переменную при чтении входного файла?

Вот тут я застрял.. не знаю, что делать

ifstream fin("inputFile.txt");

    int numberOfStates;
    int numberOfSymbols;
    int numberOfFinalStates;
    // I'm not sure how to declare the next variables because they will vary in size each time 


    while (fin >> numberOfStates >> numberOfSymbols >> numberOfFinalStates)
    {
        cout << numberOfStates << numberOfSymbols << numberOfFinalStates << endl;
    }

Я хотел бы работать с векторами, если это возможно.

отвечать

Немного поздно, но я все равно опубликую его, чтобы показать, как вы можете создавать свои собственные потоковые операторы и использовать их при создании составных классов.

#include <iostream>
#include <fstream>
#include <vector>

struct transition {
    // rename the variables into something meaningful
    int int1;
    int int2;
    char a_char;

    friend std::istream& operator>>(std::istream&, transition&);
    friend std::ostream& operator<<(std::ostream&, const transition&);
};
// input stream function for reading one transition
std::istream& operator>>(std::istream& is, transition& t) {
    is >> t.int1 >> t.int2 >> t.a_char;
    return is;
}
// output stream function for writing one transition
std::ostream& operator<<(std::ostream& os, const transition& t) {
    os << t.int1 << " " << t.int2 << " " << t.a_char;
    return os;
}
//-----------------------------------------------------------------------------
struct entity {
    int numberOfStates;
    int numberOfSymbols;
    std::vector<int> finalStates;
    std::vector<transition> transitions;

    friend std::istream& operator>>(std::istream&, entity&);
    friend std::ostream& operator<<(std::ostream&, const entity&);
};
// read one entity from a stream
std::istream& operator>>(std::istream& is, entity& e) {
    int numberOfFinalStates, numberOfTransitions;
    int value;

    if(is >> e.numberOfStates >> e.numberOfSymbols >> numberOfFinalStates) {
        // read to value and put it in its vector
        while(numberOfFinalStates-- && is >> value) e.finalStates.push_back(value);

        if(is >> numberOfTransitions) {
            transition ttmp;
            // read to the temporary transition and put it in its vector
            while(numberOfTransitions-- && is >> ttmp) e.transitions.push_back(ttmp);
            // check that we got the number of values we wanted
            // and set the failbit if we didn't (should check size() of the vectors
            // instead)
            if(numberOfFinalStates != -1 || numberOfTransitions != -1)
                is.setstate(std::ios_base::failbit);
        }
    }
    return is;
}
// write one entity to a stream
std::ostream& operator<<(std::ostream& os, const entity& e) {
    os << e.numberOfStates << "\n" << e.numberOfSymbols << "\n" << e.finalStates.size() << "\n";
    for(const int fs : e.finalStates) os << fs << "\n";
    os << e.transitions.size() << "\n";
    for(const transition& t : e.transitions) os << t << "\n";
    return os;
}
//-----------------------------------------------------------------------------
int main() {
    std::ifstream fs("inputfile.txt");
    if(fs) {
        entity e;
        // stream the opened file into the entity 
        if(fs >> e) {
            std::cout << "loaded these values:\n";
            std::cout << e;
        } else {
            std::cerr << "failed loading file\n";
        }
    } else {
        std::cerr << "failed opening file\n";
    }
}

делает

while (fin >> name >> var1 >> var2 >> var3)
{
    cout << name << var1 << var2 << var3 << endl;
}

вы все время переписываете одни и те же переменные, вам нужно поместить значение в вектор, как вы говорите в своем вопросе

вам также необходимо проверить правильность каждого ввода, в настоящее время вы не обнаруживаете недопустимый ввод

и, конечно, вам нужно проверить, что вы открываете файл


Пример :

#include <iostream>
#include <fstream>
#include <string>
#include <vector>

int main()
{
  std::ifstream fin("inputFile.txt");

  if (!fin.is_open()) {
    std::cerr << "cannot open inputFile.txt" << std::endl;
    return -1;
  }

  int numberOfStates, numberOfSymbols, numberOfFinalStates;

  if ((! (fin >> numberOfStates >> numberOfSymbols >> numberOfFinalStates))
      || (numberOfStates < 0)
      || (numberOfSymbols < 0)
      || (numberOfFinalStates < 0)) {
    std::cerr << "invalid file" << std::endl;
    return -1;
  }

  // final states are int, so memorize them in a vector of int
  // because their number is known I can size it rather than 
  // to 'push_back' each value
  std::vector<int> finalStates(numberOfFinalStates);

  for (int & ft : finalStates) {
    if (! (fin >> ft)) {
      std::cerr << "invalid file reading final states" << std::endl;
      return -1;
    }
  }

  int numberOfTransitions;

  if (!(fin >> numberOfTransitions) || (numberOfTransitions < 0))  {
    std::cerr << "invalid file reading the number of transitions" << std::endl;
    return -1;
  }

  // you say a transition contains 2 int and a char,
  // I define a structure for
  // i1 i2 and c are 'poor' names but I don't know their goal
  struct Transition {
    int i1, i2; 
    char c;
  };

  // the transitions saved in a vector
  std::vector<Transition> transitions(numberOfTransitions);

  for (Transition & tr : transitions) {
    if (!(fin >> tr.i1 >> tr.i2 >> tr.c)) {
      std::cerr << "invalid file reading transitions" << std::endl;
      return -1;
    }
  }

  // print to check

  std::cout << "numberOfStates=" << numberOfStates << std::endl;
  std::cout << "numberOfSymbols=" << numberOfSymbols << std::endl;
  std::cout << "numberOfFinalStates=" << numberOfFinalStates << "\nfinalStates:";
  for (int ft : finalStates) 
     std::cout << ' ' << ft;
  std::cout << std::endl;
  std::cout << "numberOfTransitions=" << numberOfTransitions
    << "\ntransitions:" << std::endl;
  for (const Transition & tr : transitions)
    std::cout << '\t' << tr.i1 << ' ' << tr.i2 << ' ' << tr.c << std::endl;

  return 0;
}

Компиляция и исполнение:

[email protected]:/tmp $ g++ -pedantic -Wextra -Wall a.cc
[email protected]:/tmp $ cat inputFile.txt
10 
3 
1 
9 
12 
0 1 f 
0 3 f 
1 2 a 
2 9 f 
3 4 f 
3 8 f 
4 5 b 
5 6 f 
6 7 a 
8 9 f 
[email protected]:/tmp $ ./a.out
invalid file reading transitions

Ошибка возникает из-за того, что файл содержит только 10 переходов, а не 12 ожидаемых, что приводит к изменению файла для ожидания 10 переходов:

[email protected]:/tmp $ ./a.out
numberOfStates=10
numberOfSymbols=3
numberOfFinalStates=1
finalStates: 9
numberOfTransitions=10
transitions:
    0 1 f
    0 3 f
    1 2 a
    2 9 f
    3 4 f
    3 8 f
    4 5 b
    5 6 f
    6 7 a
    8 9 f
[email protected]:/tmp $ 

Если у вас есть переменное число чего-либо (определенное во время выполнения), вы используете массив:

std::vector<Type>   store;

Чтобы добавить элементы к вектору, который вы используете push_back()(есть и другие методы, но давайте сделаем их простыми для новичков).

store.push_back(value);

Чтобы прочитать несколько вещей и сохранить их в векторе, вы просто используете цикл.

for(int loop = 0; loop < numberOfThings; ++loop) {
    Type  temp;
    fin >> temp;
    store.push_back(temp);
}

Так что же это за загадочное Type? Здесь вы используете подходящее имя типа. Для «Конечного состояния» это будет целое число ( int), но для «Перехода» это будет тип класса, соответствующий ( int/int/char).

 std::vector<int>   finalState;
 for(int loop = 0; loop < finalState; ++loop) {
     int nextFinal;
     find >> nextFinal;
     finalState.push_back(nextFinal);
 }

 ......
 std::vector<Transition>  Transitions;
 ... Just like above.