You are here:

C++/C++ program

Advertisement


Question
I would like this program to output the file in reverse order i.e the last five starting with the latest. Can you help please?
#include<iostream>
#include<fstream>
#include<stdlib>
#include<time>
#include<string>
#include<ctype>

#define KBYTE 1024

using namespace std;

class bookobject
{
  protected:          //new fields here which means
     char name[KBYTE];          //changeing the edit function
     int number;          //and books2file -
         //so new constructor << =
  private:          //and methods to access and change fields
         //keep getName() setName() getNumber() setNumber()
  public:
  bookobject(void)
  {
     strcpy(name, "");
     number = -1;
  }

  bookobject(string nam, int num)
  {
     strcpy(name, nam.c_str());
     number = num;
  }

  bookobject(bookobject& bo)
  {
     strcpy(name, bo.name);
     number = bo.number;
  }

  string getName(void)
  {
     return string(name);
  }

  void setName(string s)
  {
     strcpy(name, s.c_str());
  }

  int getNumber(void)
  {
     return number;
  }

  void setNumber(int n)
  {
     number = n;
  }

  int numCompare(bookobject& bo)
  {
     return number - bo.number;
  }

  int alphaCompare(bookobject& bo)
  {
     return strcmp(name, bo.name);
  }

  const bookobject& operator = (const bookobject& bo)
  {
     if (this != &bo)
     {
        strcpy(name, bo.name);
        number = bo.number;
     }
     return *this;
  }

  friend ostream& operator<< (ostream& os, bookobject& bo)
  {
     os << bo.name << ", " << bo.number << endl;
     return os;
  }
};

class bookwithposition : public bookobject
{
  private:
     int position;

  public:
     bookwithposition(void) : bookobject()
     {
        position = -1;
     }

     bookwithposition(bookobject& bo) : bookobject(bo)
     {
        position = -1;
     }

     bookwithposition(bookwithposition& rowp) :bookobject(rowp)
     {
        position = rowp.position;
     }

     void setPosition(int n)
     {
        position = n;
     }


     int getPosition(void)
     {
        return position;
     }

     const bookwithposition& operator =
         (const bookwithposition& rowp)
     {
        if (this != &rowp)
        {
         strcpy(name, rowp.name);
         number = rowp.number;
         position = rowp.position;
        }
        return *this;
     }

     friend ostream& operator<<
         (ostream& os, bookwithposition& rowp)
     {
        os << rowp.name << ", " << rowp.number << ":  ";
        os << rowp.position << endl;
        return os;
     }
};

template <class Buck>
class BuckDoubleLinkedList
{
  class DoubleNode          //inner class for nodes
  {
  private:
     Buck obj;          //data object
     DoubleNode *next;       //pointers for links
     DoubleNode *previous;

  public:
     DoubleNode(void)
     {
        next = NULL;        //pointing nowhere
        previous = NULL;
     }

     DoubleNode(Buck& o)
     {
        obj = o;          //with a data object
        next = NULL;
        previous = NULL;
     }

     ~DoubleNode(void)
     {
     }

     DoubleNode *getNext()
     {
        return next;
     }

     DoubleNode *getPrevious()
     {
        return previous;
     }

     void setNext(DoubleNode *hp)
     {
        next = hp;
     }

     void setPrevious(DoubleNode *hp)
     {
        previous = hp;
     }

     Buck& getObject()
     {
       return obj;
     }
  };

  private:
     DoubleNode head, tail;   //dummy nodes for head and tail
     DoubleNode *current, *temp;  //pointers for insertion and deletion
     char alphanumeric;       //indicates alphabetic or numeric order

  public:
     BuckDoubleLinkedList(char n)
     {
        head.setNext(&tail);   //link head to tail
        tail.setPrevious(&head);  //link tail to head
        if (n == 'n' || n == 'N')
        {
         alphanumeric = 'n';   //numeric order
        }
        else if (n == 'a' || n == 'A')
        {
         alphanumeric = 'a';  //alphabetic order
        }
     }

     ~BuckDoubleLinkedList(void)
     {
        DoubleNode *p = head.getNext();
        while (p != &tail)
        {
         p = p->getNext();  //delete all the nodes
         if (alphanumeric == 'n')
         {          //by number
         deleteNumber(p->getPrevious()->getObject().getNumber());
         }
         else
         {          //or by name
         deleteName(p->getPrevious()->getObject().getName());
         }
        }
     }

     void insert(Buck& o)
     {
        DoubleNode *t = new DoubleNode(o); //new node with data in it
        DoubleNode *n = head.getNext(), *p;

         while (n != &tail)  //while not at end of list
        {          //if this is the righ place to insert
         if ((alphanumeric == 'n' && n->getObject().numCompare(o)>0) ||
         (alphanumeric == 'a' && n->getObject().alphaCompare(o)>0))
         {
         break;       //do not go any further
         }
         n = n->getNext();  //try next position
        }
        p = n->getPrevious();   //before insertion point
        t->setNext(n);          //set links for new node to list neighbours
        t->setPrevious(p);
        p->setNext(t);          //set links for neighbours to new node
        n->setPrevious(t);
     }

     bool search(int k)         //search for number in sequential search
     {
        DoubleNode *p = head.getNext();
        while (p != &tail)
        {          //data object must have getNumber() implemented
         if (p->getObject().getNumber() == k)
         {
         return true;
         }
         p = p->getNext();
        }
        return false;
     }

     bool search(string str)      //search for string in sequential serrch
     {
        DoubleNode *p = head.getNext();
        while (p != &tail)
        {          //data object must have getName() implemented
         if (strcmp(p->getObject().getName().c_str(), str.c_str())==0)
         {
         return true;
         }
         p = p->getNext();
        }
        return false;
     }

     DoubleNode *position(int k)   //gets physical position in memory
     {
        DoubleNode *p = head.getNext();
        while (p != &tail)
        {
         if (p->getObject().getNumber() == k) //using data object's getNumber()
         return p;
         p = p->getNext();
        }
        return NULL;
     }

     DoubleNode *position(string str) //gets physical position in memory
     {
        DoubleNode *p = head.getNext();
        while (p != &tail)
        {          //using data object's getNumber()
         if (strcmp(p->getObject().getName().c_str(), str.c_str())==0)
         return p;
         p = p->getNext();
        }
        return NULL;
     }

     void deleteNumber(int k)
     {
        DoubleNode *p;
        if ((p = position(k)) != NULL)  //find actual position
        {
         current = p->getPrevious();  //the one before
         temp = p->getNext();         //the one after
         current->setNext(temp);      //reset links
         temp->setPrevious(current);
         delete p;          //release node
        }
     }

     void deleteName(string str)
     {
        DoubleNode *p;
        if ((p = position(str)) != NULL)     //if name exists
        {
         current = p->getPrevious();       //get pos before
         temp = p->getNext();          //get pos after
         current->setNext(temp);          //set new links
         temp->setPrevious(current);
         delete p;          //release old node
        }
     }

     void printItem(int num)
     {
        DoubleNode *p;
        if ((p = position(num)) != NULL)      //if number exists
        {
         cout << p->getObject();          //display it
        }
        else
        {
         cout << num << " is not in list" << endl;
        }
     }

      void printItem(string str)
     {
        DoubleNode *p;
        if ((p = position(str)) != NULL)      //if name exists
        {
         cout << p->getObject();          //display it
        }
        else
        {
         cout << str << " is not in list" << endl;
        }
     }

     void printList(void)
     {
        DoubleNode *p = head.getNext();  //start with first elemennt
        while (p != &tail)          //while not at end
        {
         cout << p->getObject();       //get element and output it
         p = p->getNext();          //go to next
        }
        cout << endl;
     }
};



int filesize(string fname);
bool another(string str);
void books2file(string fname);
void file2list(string fname, BuckDoubleLinkedList<bookwithposition>& lst);
void edit(string fname);
const char *backupname(string fname);
void initialiseToFalse(bool *pos, int siz);
void backupFile(string fname);
void deleteFromBackup(string fname, bool *toDel);
void erase(string fname);
void latest(string fname);

void main(void)
{
  string filename;
  cout << "Enter filename: " << flush;
  cin >> filename;
  books2file(filename);
  //edit(filename);
  erase(filename);

  system("pause");
}

void latest(string fname)
{
}

void erase(string fname)
{
  BuckDoubleLinkedList<bookwithposition> list('a');
  file2list(fname, list);
  list.printList(); //display list of contents
  int pos, size = filesize(fname)/sizeof(bookobject);
  bool *toDelete = new bool[size];
  initialiseToFalse(toDelete, size);
  do
  {
     cout << "Enter position to delete: " << flush;
     cin >> pos;
     if (pos >= 0 && pos < size)
        toDelete[pos] = true;

  } while (another("position to delete"));
  backupFile(fname);
  deleteFromBackup(fname, toDelete);
  BuckDoubleLinkedList<bookwithposition> newlist('a');
  file2list(fname, newlist);   //make new list to test
  newlist.printList(); //display list of contents to test
}

void deleteFromBackup(string fname, bool *toDel)
{
  ofstream os(fname.c_str(), ios::binary);       //empty new file
  ifstream is(backupname(fname), ios::binary);  //backup file to copy
  int pos = 0;
  bookobject bo;
  while(is.read(reinterpret_cast<char *>(&bo), sizeof(bookobject)))
  {
     if (!toDel[pos++])
     {  //if not to be deleted, copy to new file
        os.write(reinterpret_cast<char *>(&bo), sizeof(bookobject));
     }
  }
  os.close();  // close files when done
  is.close();
}

void initialiseToFalse(bool *pos, int siz)
{
   for (int i = 0; i < siz; i++)
   {
      pos[i] = false;
   }
}

void backupFile(string fname)
{
  bookobject bo;
  ifstream is(fname.c_str(), ios::binary);  //open our file to make backup
  ofstream os(backupname(fname), ios::binary); //create new backup file
  while (is.read(reinterpret_cast<char *>(&bo), sizeof(bookobject)))
  {
     //copy from file to backup file
     os.write(reinterpret_cast<char *>(&bo), sizeof(bookobject));
  }
  is.close();   //close both files when we have done
  os.close();
}

const char *backupname(string fname)
{
  return (fname + ".bak").c_str();
}

void edit(string fname)
{
  BuckDoubleLinkedList<bookwithposition> list('a');
  file2list(fname, list);
  list.printList(); //display list of contents
  //open binary input/output file
  fstream fs(fname.c_str(), ios::in | ios::out | ios::binary);
  int size = filesize(fname)/sizeof(bookobject);
  do
  {
     int pos, newnum;
     string newstr;
     bookobject bo;
     cout << "Input position to edit: " << flush;
     cin >> pos;   //get position
     if (pos >= 0 && pos < size)  //if in range
     {
        fs.seekg(pos * sizeof(bookobject)); //go to position
        fs.read(reinterpret_cast<char *>(&bo), sizeof(bookobject));  //read number
        cout << "change name " << bo.getName() << " to: " << flush;
        cin >> newstr;    //get new name
        bo.setName(newstr);
        cout << "change number " << bo.getNumber() << " to: " << flush;
        cin >> newnum;    //get new number
        bo.setNumber(newnum);
        fs.seekp(pos * sizeof(bookobject)); //move to correct pos
        fs.write(reinterpret_cast<char *>(&bo), sizeof(bookobject));  //overwrite
     }
  } while (another("book to edit"));
  fs.close();   //close when done
  BuckDoubleLinkedList<bookwithposition> newlist('a'); //new list
  file2list(fname, newlist);   //make new list to test
  newlist.printList(); //display list of contents to test
}


void books2file(string fname)
{
  //open binary output file in APPEND MODE
  ofstream os(fname.c_str(), ios::app | ios::binary);
  do
  {
     string nam;
     int num;
     cout << "Input name of book: " << flush;
     cin >> nam;   //get name
     cout << "Input number of book: " << flush;
     cin >> num;   //get number
     bookobject bo(nam, num);  //make instance of bookobject
     os.write(reinterpret_cast<char *>(&bo), sizeof(bookobject));
  } while (another("book to add"));
  os.close();     //close when done
}

void file2list(string fname, BuckDoubleLinkedList<bookwithposition>& lst)
{
  int index = 0;
  bookobject bo;

  ifstream is(fname.c_str(), ios::binary);   //open binary input file

  //while we can read a book from the file
  while (is.read(reinterpret_cast<char *>(&bo), sizeof(bookobject)))
  {
     bookwithposition bwp(bo);  //make book with position
     bwp.setPosition(index++);  //set position
     lst.insert(bwp);          //add to list
  }
  is.close();   //close file when we have done3
  cout <<endl;
}

int filesize(string fname)
{
  ifstream is(fname.c_str(), ios::binary);
  is.seekg(0, ios::end);
  int pos = is.tellg();
  is.close();
  return pos;
}

bool another(string str)
{
  char yesno = '\0';
  do
  {
     cout << "Another " << str << " Y/N?" << flush;
     cin >> yesno;
     yesno = (char)toupper(yesno);
  }
  while (yesno != 'Y' && yesno != 'N');
  return yesno == 'Y';
}


Answer
I probably could give you a better answer if you could reduce the amount of code posted - I do not have the time to spend reverse engineering your code - and a quick look raises questions along the lines of "eh? Which file? Which function?" I think it may be books2file from the name, but I am not sure as it seems to just write the book information you enter directly to a file - in which case what is the doubly linked list for?

In short this is a case of not being able to see the wood for the trees - you have given me too much detail in the code. However you have not given many hints in the question text that accompanies your code or better yet an overview of what your code should be doing.

I would suggest that you enter book data objects onto a list then output the book items in the list to the file in the required order. For example you could obtain the book item data and push them to the top of the list each time. Then you have to just output each item on the list from top to bottom (or front to back if you prefer) and the last entry will be the first written to the file and the first item the last written to the file. Alternatively you can append the items to the end of the list each time and then output them last to first (bottom to top or back to front) - which you can do as you have a doubly linked list

Why did you create your own list? Why not use std::list? std::list is part of C++ and so others like myself are familiar with it - also why recreate the wheel? Or possibly you could use std::vector or std::deque if you only needed to insert or remove items to the end or the beginning or the end. If you do not have information on the standard library containers or other STL parts check out the documentation at http://www.sgi.com/tech/stl/. If you require an implementation of the C++ standard library then check out http://www.stlport.org/.
Note that using the standard library components allows you to use other standard library functionality - such as sorting your container's data - for very little effort.

On another note try to avoid the use of #defines as in:

#define KBYTE 1024

You can do something like the following instead:

const int KBYTE = 1024;

or using constructor call syntax:

const int KBYTE(1024);

or even:

int const KBYTE(1024);

Alternatively you could place the constant in the scope of the class namespace where it is used to size the name array:

class bookobject
{
       static const int KBYTE = 1024;
// ...
};

Note that you cannot use constructor style syntax here as the compiler tends to think you are trying to declare a member function!

class bookobject
{
// OOPS! - compiler thinks KBYTE is a static member function...
       static const int KBYTE(1024);
// ...
};

or if your compiler does not support initialising static constant members in class definitions you can use the enum trick instead:

class bookobject
{
       enum { KBYTE = 1024 };
// ...
};

You can adjust the access as required and if it is public access KBYTE from elsewhere like so: bookobject::KBYTE

A better choice of name would be something like MAX_NAME_LENGTH - it states exactly what the value is used for.

Finally, beware of using:

using namespace std;

and the like in header files - it can cause unexpected problems see http://www.gotw.ca/gotw/053.htm answer to question 2 (about a third of the way down the article). There are other GoTW articles - see the index page at http://www.gotw.ca/gotw/index.htm.  

C++

All Answers


Answers by Expert:


Ask Experts

Volunteer


Ralph McArdell

Expertise

I am a software developer with more than 15 years C++ experience and over 25 years experience developing a wide variety of applications for Windows NT/2000/XP, UNIX, Linux and other platforms. I can help with basic to advanced C++, C (although I do not write just-C much if at all these days so maybe ask in the C section about purely C matters), software development and many platform specific and system development problems.

Experience

My career started in the mid 1980s working as a batch process operator for the now defunct Inner London Education Authority, working on Prime mini computers. I then moved into the role of Programmer / Analyst, also on the Primes, then into technical support and finally into the micro computing section, using a variety of 16 and 8 bit machines. Following the demise of the ILEA I worked for a small company, now gone, called Hodos. I worked on a part task train simulator using C and the Intel DVI (Digital Video Interactive) - the hardware based predecessor to Indeo. Other projects included a CGI based train simulator (different goals to the first), and various other projects in C and Visual Basic (er, version 1 that is). When Hodos went into receivership I went freelance and finally managed to start working in C++. I initially had contracts working on train simulators (surprise) and multimedia - I worked on many of the Dorling Kindersley CD-ROM titles and wrote the screensaver games for the Wallace and Gromit Cracking Animator CD. My more recent contracts have been more traditionally IT based, working predominately in C++ on MS Windows NT, 2000. XP, Linux and UN*X. These projects have had wide ranging additional skill sets including system analysis and design, databases and SQL in various guises, C#, client server and remoting, cross porting applications between platforms and various client development processes. I have an interest in the development of the C++ core language and libraries and try to keep up with at least some of the papers on the ISO C++ Standard Committee site at http://www.open-std.org/jtc1/sc22/wg21/.

Education/Credentials

©2016 About.com. All rights reserved.