Solved

store data of a linked-list

Posted on 2003-12-10
15
1,212 Views
Last Modified: 2013-12-14
Hi C++ Experts,

    The following is an unfinished program, but I guess it would be enough to demostrate the question that I want to ask :
-----------------------------------------------
#include <cstdio>
#include <list>
#include <iostream>
#include <string>

int main()
{
   list<string> person;
   int flag = 1 ;

 while(flag){
   system("clear") ;
   cout << "-----------------------------------" << endl ;
   cout << " Choose one of the following items : " << endl ;
   cout << " 0. exit and save "<< endl ;
   cout << " 1. add a name " << endl ;
   cout << " 2. delete a name " << endl ;
   cout << " 3. select a name and change " << endl ;
   cout << " 4. display the list " << endl ;
   cout << " Please enter a number : " << endl ;

  char choice ;
   cin >> choice ;

   switch(choice){
     case '0' :
       flag = 0 ; break ;
     case '1' :
     {   cout << "please enter the name : " << endl ;
         string temp ;
         cin.ignore(80,'\n');
         getline(cin, temp) ;
         person.push_back(temp) ;
         break ;
     }
     case '2' :
     {   cout << "please enter the name : " << endl ;
         string temp ;
         cin.ignore(80,'\n');
         getline(cin, temp) ;
         person.remove(temp) ;
         break ;
     }

    case '3' :
     {   cout << "please enter the name : " << endl ;
         string temp ;
         cin.ignore(80,'\n');
         getline(cin, temp) ;
         list<string>::iterator it ;
         for(it=person.begin() ; it!=person.end() ;it++){
           if(temp == *it) person.remove(temp) ;}
         cout << "we will change " << temp << endl ;
         cout << "please enter the new name :" << endl ;
         cin.ignore(80,'\n') ;
         getline(cin,temp) ;
         person.insert(it,temp) ;
         break ;
      }

      case '4' :
      {   list<string>::iterator it ;
         system("clear") ;
         for(it=person.begin() ; it!=person.end() ;it++){
           cout << *it << endl ;}
         cout << endl << endl << endl << endl;
         cout << " Press a key to continue ....... " << endl ;

         getchar() ;
         cin.ignore() ;
         break ;
      }
      default :
      {
        break ;
      }

   }//swithch
 }//flag

  return 0 ;

}
---------------------------------------
  Here is my question. Everytime we exit the program, we will lose all the data we typed in this time. I am wondering how to save them, so that next time when I run the code again, the data I typed today would still be there. I might be able to dump them into a text file for now since it is only a list of strings. However, I understand that it won't be that easy while I have a list of "blah_blah" in the future .... because the "blah_blah" could be a very complicated structure.

  Therefore, I am wondering what's the standard way of dealing with this situation ? Do people link the database ? or what do they do ? Also, if I want to do things like this, which topic should I go ahead and study ? Thanks very much !!!

meow.....
0
Comment
Question by:meow00
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 5
  • 3
15 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 9913866
>>  Therefore, I am wondering what's the standard way of dealing with this situation ?

There is no 'standard' way - the most common one would be add 'serialization' support to the classes that you want to store in the STL container, e.g.

class foo {

//...

public:

  void read ( ostream& os) {

      // read contents from file
  }
  void write ( istream& os) {

      // write contents to file
  }

};
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9913888
If this is a study excercise, I'd suggest looking at writing/reading the strings to a text file.

You already have

--------8<--------
         for(it=person.begin() ; it!=person.end() ;it++){
           cout << *it << endl ;}
--------8<--------

That writes the strings to the standard output.

Your next step should be to look at writing the strings in a similar manner to a file instead of cout.

e.g.
--------8<--------
         {
             ofstream fout("strings.txt"); // See http://www.cplusplus.com/ref/iostream/ofstream/
             for(it=person.begin() ; it!=person.end() ;it++){
                 fout << *it << endl ;}
         } // End the scope - this automatically closes fout
--------8<--------

You already have
--------8<--------
         getline(cin, temp) ;
         person.push_back(temp) ;
--------8<--------

Look at loading persons from a file, using ifstream
e.g.
--------8<--------
         {
             ifstream fin("strings.txt"); // See http://www.cplusplus.com/ref/iostream/ifstream/
             string temp;
             while (getline(cin, temp))
                 person.push_back(temp) ;
         } // End the scope - this automatically closes fin
--------8<--------
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9913908
Ooops....

Look at loading persons from a file, using ifstream
e.g.
--------8<--------
         {
             ifstream fin("strings.txt"); // See http://www.cplusplus.com/ref/iostream/ifstream/
             string temp;
             while (getline(fin, temp))  /* I meant fin not cin - you can see that they work similarly */
                 person.push_back(temp) ;
         } // End the scope - this automatically closes fin
--------8<--------
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:meow00
ID: 9913909
Hi jkr ..... thanks a lot ! And I am wondering is there any good text book or website giving tutorial about the "serialization" ? I am new to this and I could not find them in the standard C++ books ..... Thanks very much !

meow...
0
 
LVL 1

Author Comment

by:meow00
ID: 9913949
Hello rstavely, Thanks for the answers !
But I guess my biggest problem would be :
If I have a list of person object
------------------------
class person{
   float weight ;
   int age ;
   string name ;
   class car ;
} ;

class car{ blah } ;
------------------------
I couldn't really dump them to a file ....... do you have any better ideas ? thanks !

meow.
0
 
LVL 86

Assisted Solution

by:jkr
jkr earned 80 total points
ID: 9914142
>>And I am wondering is there any good text book or website giving tutorial about the "serialization" ?

There are actually a lot - I remember http://www.codeproject.com/cpp/serialization_primer1.asp being pretty informative (even though it deals with MFC), but the site gives an internal server error at the time...
0
 
LVL 1

Author Comment

by:meow00
ID: 9914239
>There are actually a lot - I remember >http://www.codeproject.com/cpp/serialization_primer1.asp being pretty informative (even >though it deals with MFC), but the site gives an internal server error at the time...

er.... is the website there ??? or my webbrowser has problems ? thanks

meow.
0
 
LVL 86

Expert Comment

by:jkr
ID: 9914285
The site is there, as I wrote: The server seems to have problems at this time...
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9914793
This should give you an idea about reading/writing person from/to file. I've delimited fields with '|' for no very good reason. I've used getline so that strings can contain ' ';

--------8<--------
#include <iostream>
#include <fstream>
#include <string>
#include <list>
#include <limits>

class car {
      std::string name;
      template<class c> friend std::basic_ostream<c>& operator<<(std::basic_ostream<c>&,const car&);
      template<class c> friend std::basic_istream<c>& operator>>(std::basic_istream<c>&,car&);
public:      car() {}
      car(const std::string& name) : name(name) {}
      car(const car& copycar) : name(copycar.name) {}
};

// This allows the car class to be written to an ostream
template<class c> std::basic_ostream<c>& operator<<(std::basic_ostream<c>& os,const car& buggy)
{
      return os << buggy.name;
}

// This allows the car class to be read from an istream, it assumes that the field
// is delimited by '|'
template<class c> std::basic_istream<c>& operator>>(std::basic_istream<c>& is,car& buggy)
{
      if (!getline(is,buggy.name,'|'))
            return is;

      //is.ignore(std::numeric_limits<std::streamsize>::max(),'|');

      return is;
}

class person{
      float weight;
      int age;
      std::string name;
      car buggy;
      template<class c> friend std::basic_ostream<c>& operator<<(std::basic_ostream<c>&,const person&);
      template<class c> friend std::basic_istream<c>& operator>>(std::basic_istream<c>&,person&);
public:      person() {}
      person(const std::string& name,int age,float weight,const car& buggy)
            : weight(weight),age(age),name(name),buggy(buggy) {}
};

// This allows the person class to be written to an ostream
template<class c> std::basic_ostream<c>& operator<<(std::basic_ostream<c>& os,const person& bod)
{
      return os
            << bod.name << '|'      /* Use this delimiter so we can have spaces in the name */
            << bod.age << '|'
            << bod.weight << '|'
            << bod.buggy << '|';
}

// This allows the person class to be read from an istream, where fields are delimited by '|'
template<class c> std::basic_istream<c>& operator>>(std::basic_istream<c>& is,person& bod)
{
      if (!getline(is,bod.name,'|'))
            return is;

      //is.ignore(std::numeric_limits<std::streamsize>::max(),'|');

      if (!(is >> bod.age))
            return is;

      is.ignore(std::numeric_limits<std::streamsize>::max(),'|');

      if (!(is >> bod.weight))
            return is;

      is.ignore(std::numeric_limits<std::streamsize>::max(),'|');

      return is >> bod.buggy;
}

int main()
{
      std::list<person> folk;

// Read the folk.dat file, if it exists and load the folf into our list

      {
            std::ifstream fin("folk.dat");
            if (fin) {
                  std::cout << "\nHere's the folk we read:\n\n";
                  person temp;
                  while (fin >> temp) {
                        folk.push_back(temp);
                        std::cout << '\t' << temp << '\n';
                  }
            }
      }

// Let's add some more folk

      folk.push_back(person("Fred Bassett",46,120,car("Ford Cortina")));
      folk.push_back(person("Krazy Kat",87,97,car("Datsun Sunny")));

// Write the folk back to file

      {
            std::ofstream fout("folk.dat");
            if (fout) {
                  std::cout << "\nHere's the folk we are writing:\n\n";
                  for (std::list<person>::const_iterator citr = folk.begin();citr != folk.end();++citr) {
                        std::cout << '\t' << *citr << '\n';
                        fout << *citr;
                  }
            }
      }

}
--------8<--------

Try it out and do have a look at the contents of the text file "folk.dat", which (be warned) does not separate persons with lineline characters. I'll leave that to you if you want it :-)
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9914796
> lineline

newline
0
 
LVL 1

Author Comment

by:meow00
ID: 9916911
Thanks for all the answers ! Just another short question ... so for the above example provided by rstaveley, is that a kind of "serialization" as well ? or it is something else ???
Thanks very much !!!

meow...
0
 
LVL 17

Accepted Solution

by:
rstaveley earned 220 total points
ID: 9917945
Reading and writing of objects to file to allow them to persist is known as serialisation - with a 'z' really, but I can't get used to American spellings :-)

The codeproject tutorial at http://www.codeproject.com/cpp/serialization_primer2.asp shows Microsoft's approach for serialisation, but that's by no means the only way of doing it. I like human-readable files where performance isn't an issue and ideally I'd like my objects to persist in XML files, but that adds the complexity of a SAX parser for reading objects so the delimited text file is a happy compromise.

The approach I've outlined is pretty sketchy, because it doesn't address issues like what to do if one of your strings has a '|' character in it (that's where XML looks apealing), but it works nicely enough for most purposes.

The example I showed you makes the ostream operator<< overload always show the object in the manner required for serialisation. You can improve upon the design by using an ios::iword flag for "serialization mode"/"non-serialization mode" to get the ostream operator<< to display the serialization-friendly format when the ostream is in "serialization mode" and something human-friendly, when it is not.

e.g. Here's an example with a simple structure unimaginatively called X - you could easily adopt the same approach for your person and car classes:
--------8<--------

/* Demonstrating use of a iword formatting flag for serialisation in the stream */

#include <iostream>

// Globals for serialization
namespace serializer {

        const int NotSerializing = 0; // Stream is not serializing - default mode is 0
        const int Serializing = 1; // Stream is serializing

        // Allocate out global ios::iword index
        const int index = std::ios_base::xalloc();

        // Returns true if the ostream is in serialisation mode
        template<class C>
        inline bool is_serializing(std::basic_ostream<C>& os)
        {
                return os.iword(index) == Serializing;
        }

        // Set the ostream's serialisation mode
        template<class C>
        inline void serialize(std::basic_ostream<C>& os,bool goforit = true)
        {
                os.iword(index) = goforit ? Serializing : NotSerializing;
        }

} // serializer namespace

struct X {
        int a,b;
        X(int a,int b) : a(a),b(b) {}
};

// Display the X object on an ostream - display depends on serialization mode
template<class C>
std::basic_ostream<C>& operator<<(std::basic_ostream<C>& os,const X& x)
{
        if (serializer::is_serializing(os)) {
                os << x.a << '|' << x.b;
        }
        else {
                os << "A value is " << x.a << ", and B value is " << x.b;
        }
        return os;
}

int main()
{
        X x(1,2);

        // ostreams are by default not in serialization mode
        std::cout << "x without serialization: " << x << '\n';

        serializer::serialize(std::cout); // Put the stream into serialization mode
        std::cout << "x with serialization: " << x << '\n';

        serializer::serialize(std::cout,false); // Put the stream into non-serialization mode
        std::cout << "x without serialization: " << x << '\n';
}
--------8<--------
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9917974
meow00, looking at http:/QH_1517700.html I see that you have questions open dating back to October :-(
0
 
LVL 1

Author Comment

by:meow00
ID: 9917990
Thanks very much for all these ..... I need to spend next few days on the serialization now :-)
0
 
LVL 17

Expert Comment

by:rstaveley
ID: 9918649
Glad to have been able to help. Best of luck.
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

When writing generic code, using template meta-programming techniques, it is sometimes useful to know if a type is convertible to another type. A good example of when this might be is if you are writing diagnostic instrumentation for code to generat…
What is C++ STL?: STL stands for Standard Template Library and is a part of standard C++ libraries. It contains many useful data structures (containers) and algorithms, which can spare you a lot of the time. Today we will look at the STL Vector. …
THe viewer will learn how to use NetBeans IDE 8.0 for Windows to perform CRUD operations on a MySql database.
The viewer will learn how to use and create new code templates in NetBeans IDE 8.0 for Windows.

691 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question