I can not come up with a solution. I have a certain doubly linked list:

struct Tourism { string country; int number_of_vouchers; float cost_of_voucher; string hotel_name; int hotel_status; int tour_duration; }; struct List { Tourism tourism; List * prev; List * next; }; 

there is a list.txt file

 Spain 100 12.3 Madrid 4 12 Ukrain 120 100 Odessa 5 5 и т.д. 

How do I properly go through the file and record all the data in the list? Suppose I do a record like this.

 begin = new List; begin->prev = NULL; fin>>begin->tourism.country; fin>>begin->tourism.number_of_vouchers; fin>>begin->tourism.cost_of_voucher; fin>>begin->tourism.hotel_name; fin>>begin->tourism.hotel_status; fin>>begin->tourism.tour_duration; begin->next = NULL; 

But for each new element of the list to prescribe in a new way the same code is stupid. It is necessary to create some kind of cycle to go through the file that will write data. How to do it, I do not know.

  • one
    struct list_head { List *first, *last} head = {0, 0}; List *t; while(t = get_list_elem(fin)) add_to_list(&head, t); Well, in get_list_elem() place your code returning begin or 0 if there is nothing more to read. With add_to_list() , I hope you can add_to_list() it. - avp

1 answer 1

Are you writing in C ++? So let's do a normal streaming input.

 #include <string> #include <vector> #include <fstream> using namespace std; struct Tourism { string country; int number_of_vouchers; float cost_of_voucher; string hotel_name; int hotel_status; int tour_duration; }; istream& operator >> (istream& s, Tourism& t) { return s >> t.country >> t.number_of_vouchers >> t.cost_of_voucher >> t.hotel_name >> t.hotel_status >> t.tour_duration; } int main(int argc, char* argv[]) { vector<Tourism> v; fstream s { тут имя файла }; Tourism t; while (s >> t) v.push_back(t); } 

And do not use samopisnymi containers at the risk of a mistake.


Update :

The above solution only works correctly if there are no spaces in the lines. If there are spaces, s >> t.country reads only up to the first space. The fact is that reading a string works before the whitespace, and not to the end of the string, so it’s not so easy to subtract the entire string.

The problem is that we can not switch to using getline for t.country : getline and streaming through >> not friendly. Entering through >> ignores the start whitespace characters, and leaves the final \n in the string, but not getline , so the code will not work when they are mixed.

The solution that is usually proposed is to change for our stream s what it considers to be a space character. If we tell him that only \n is a space, he will read the lines to the end!

This requires the following spell:

 int main(int argc, char* argv[]) { fstream s { тут имя файла }; // заведём пустую таблицу категорий символов ctype<char>::mask mask[ctype<char>::table_size] = {}; // обозначим `\n` как пробельный символ mask['\n'] = ctype_base::space; // объясним потоку, что он должен пользоваться этой таблицей s.imbue(locale(s.getloc(), new ctype<char>(mask))); vector<Tourism> v; Tourism t; while (s >> t) v.push_back(t); } 

Now the code works.


Perhaps a simpler ideologically variant is to read everything via getline and refuse >> to enter. To convert the resulting string to a value, we use istringstream , as usual. The code is a little less elegant, but simple and straightforward (which is not so bad):

 #include <string> #include <vector> #include <fstream> #include <sstream> using namespace std; struct Tourism { string country; int number_of_vouchers; float cost_of_voucher; string hotel_name; int hotel_status; int tour_duration; }; istream& getrecord(istream& s, Tourism& t) { string line; // пропускаем пустые строки while (line == "" && getline(s, line)) ; // если поток в хорошем состоянии, мы прочитали непустую строку if (s) t.country = line; if (getline(s, line)) istringstream(line) >> t.number_of_vouchers; if (getline(s, line)) istringstream(line) >> t.cost_of_voucher; if (getline(s, line)) t.hotel_name = line; if (getline(s, line)) istringstream(line) >> t.hotel_status; if (getline(s, line)) istringstream(line) >> t.tour_duration; return s; } int main(int argc, char* argv[]) { vector<Tourism> v; fstream s { тут имя файла }; Tourism t; while (getrecord(s, t)) v.push_back(t); } 

Magic with a locale is not needed.

  • this is the course. vectors are too early to use. But the idea of ​​overloading the operator, I will redo it for myself. should work. Thanks, thought caught. - V. Rotenberh
  • @ V.Rotenberh: Ah, coursework, well then, yes, restrictions. Pay attention to the condition of exit from the cycle, it is not self-evident. - VladD
  • I can't understand it yet. Do not tell me how to make the condition of checking out of the loop differently, based on the list. If s >> pointer to the list? - V. Rotenberh
  • @ V.Rotenberh: But this condition is very worth understanding. Think about what kind of expression s >> t . Other ways are possible, but this is against the C ++ style. So spend time and master this logic - it will come in handy (not for coursework, for work). - VladD
  • @ V.Rotenberh: Read, for example, this answer: ru.stackoverflow.com/a/421084/10105 . It describes exactly what you need. - VladD