Link to home
Start Free TrialLog in
Avatar of appreciative
appreciative

asked on

Print Queue Program...Help!!!

Need help with this program... I really don't know how to make it work... and I'm hoping to finish it tonight.  I'm trying to liberate myself to have time to visit my godfather who was urgently transported to the hospital last night... his last days... cancer.  Since it's out of town, I will worry my head off if I leave without having done this assignment, since I still have to study for 4 finals next week...  Can someone please help me make sense out of this program...???  The coding should remain in the same style. I'm compiling with MS Visual C++, 5.0.
Thank you very much!!!
appreciative

scenario
Design a print queue.  The queue should work for any type of list, even though it will be used with "printjobs" in this case.  The queue should hold as many print jobs as the programmer wants when using the queue.  The queue should contain a Poll method that indicates if it is empty or if a print job is waiting in the queue.

A "printjob" should hold a character string that a user/programmer will specify and then be sent to the queue waiting to be printed. If a print job is removed from the queue, the character string is displayed on the screen.

The menu in the driver program should look like this:

*** Print Queue Test ***
1) New Document   -- create character string & put print job into queue
2) Poll Queue         -- indicates whether there is something in the queue or not
3) Print Document   -- removes longest off queue & displays character string on screen
0) exit

>char string should be statically assigned to 200 chars
>there should be a method to set limit
>dynamically change objects in list
>queue should store "printjob" objects
>queue should work for any data type
>main to test it with int

here is my code up to now:

queue.h
template <class T>
class queue
{
  public:
    queue();
    queue(const queue<int> &);
    ~queue();
    void enqueue(const T &);
    T dequeue();
  private:
    int pollEmpty();
    int pollFull();
    T *queues[200];
    int head;
};

queue.cpp
#include <iostream.h>
#include "queue.h"

template <class T>
queue <T>::queue()
{
  head=0;
}

template <class T>
queue<T>::queue(const queue<int> & q)
{

}

template <class T>
queue <T>::~queue()
{

}

template <class T>
void queue <T>::enqueue(const T & element)
{
  if(!pollFull())
  {
    queues[head]=element;
    head++;
  }
  else
  {
    cout<<"Queue Full!"<<endl;
  }
}

template <class T>
T queue <T>::dequeue()
{
  if(!pollEmpty())
  {
    head--
    return(queues[head]);
  }
  else
  {
    cout<<"Queue Empty!"<<endl;
    return ((T) 0);
  }
}

template <class T>
int queue <T>::pollEmpty()
{
  if(head!=0)
  {
    return 0;
  }
  else
  {
    return 1;
  }
}

template <class T>
int queue <T>::pollFull()
{
  if(head!=  )
  {
    return 0;
  }
  else
  {
    return 1;
  }
}

printjob.h
#include <iostream.h>
#include "queue.h"
#include "printjob.h"

class printjob
{
  public:
    printjob();
    printjob(printjob &);
    ~printjob();
//  void setString(char *); I don't know where to declare the string
    int getDocument();
  private:
//  char *str[200];
    int document;
};

printjob.cpp and driver
#include <iostream.h>
#include "queue.h"
#include "printjob.h"

printjob::printjob()
{
  document=new int;
  document=0;
}

printjob::printjob(printjob & copy)
{
  document=new int;
  document=copy.getDocument();
}

printjob::~printjob()
{

}

int printjob::getDocument();
{
  return document;
}

void main (void)
{
  queue <int> q(5);
  int ok, selection;

  do
  {
    ok=1;
    cout<<endl<<"*** Print Queue Test ***"<<endl;
    cout<<endl<<"1) New Document";
    cout<<endl<<"2) Poll Queue";
    cout<<endl<<"3) Print Document";
    cout<<endl<<"0) Exit";
            
    do
    {
      if(!ok)
      cout<<"Invalid selection...please try again";
      cin>>selection;
      ok=0;
    }while(selection<0||selection>3);

    switch(selection)
    {
      case 1:
        printjob *document;
        document=new printjob;
        cin>document;
        q.enqueue(document);
        cout<<endl<<"Document being printed!"<<endl;
        break;
      case 2:
        break;
      case 3:
        delete document;
        cout<<q.dequeue();
        break;
      case 0:
      break;
    }
  }while(selection!=0);
}
     
Avatar of appreciative
appreciative

ASKER

Edited text of question
Can anyone please help me sort this out...!!!
you are missing a *document.
document = new int;

shouldn't it be..

int* document;

document=new int ?

I am pretty sure of that.


BTW.  My regards to your godfather :(
The copy constructor for the queue is declared wrong.  you have

  queue(const queue<int> &)

Since your queue is in a template, this generates code to create a queue of type T fom a queue of type int.  That is, the queue it is copying from always has to be type of type int.  Note that this is legal and there may be times it is neededd, but I doubt it is needed here.  You should have

queue(const queue<T> &)

and where you define it

queue<T>::queue(const queue<int> & q)
Lets forget the little stuff.   The big problem I see is that your queue is functioning a lot like a stack.  When you place items in the queue, they go in at the "head" position and when they come out, they come out at the head position.  This makes it a stack or FILO (first in last out) container.  Are you familiar with that?  

Queues are ussualy the reverse, that is FIFO or first in first out.  That is items come out in the same order they went in.  However some queues, called priority  queue, may remove items in an order based on some sort of priority of the different items.   I think that is what your teacher wants he says
>> 3) Print Document   -- removes longest off queue & displays character string on screen
that means that when it is time to remove one from the queue we remove the longest one (not the oldest and not the youngest, but the longest).  At least that is how I interpret it.
Now I hate to slow down this whole process--considering your circumstances--but priority queues are ussually implimented using a linked list.  Your approach of using an array is ussually used for a normal queue (when implimented with a fixed array like that it is called a "circular queue")  So I would like to know why you chose to use an array?  Was that suggested, in which case we can get it to work that way, or was that your own doing, in which case I think you might wnat to consider using a linked list.  Are you familiar with linked lists?  (I can't remember what we worked on before?)  I think I will be in most of the day, hopefully this is not too late.
The_Brain, Thanks for your prompt reply... and your concern for my godfather, my mom hopes for a miracle!!!  
I'm on standby... no word yet... the last I heard, the immediate family was rushed to hospital (his wife and 1 son).

Hi nietod,
Good morning and thanks for replying!
Did you see my e-mail before coming in here...??
I was told that I did not need a  linked list -- and we have not learned them yet.
You are very perceptive... 'cause we had actually done a stack program just before this one so I based this one on that... totally forgetting to take into consideration that the queue is FIFO and yes... we are to remove the "longest" first.  He also explained that when you remove the bottom (or longest) it has to be replaced by the next in line, and so on (ie,  4 becomes 3, 3 becomes 2 and 2 becomes 1) I don't really know how I'm supposed to program that!!!
The only array I can see here is the string which should be statically assigned to 200 characters.    

Okay.  Its too bad he is making this a priority queue.  Since you have to use an array, it would be best to do a circular queue--an important type of queue.  But we will make this a priority queue using an array.  Keep in mind the fact, that in practice, you would probably never do this.  For priority queues you would almost always use a linked list or similar type of container.  For a  regular queue, you would use either an array (circular queue) or a linked list as well.

I'll look over the code and comment shortly.
first, lets talk about algorithms.  This type of queue is goind to be a lot like the stack you are familiar with.   You will have an array that can hold up to some number of entries.  (Lets call that MaxItems). That array will probably be using only some of the entries at a time.  The entries used will always start with entry 0 in the array and proceed toward the end of the array.  The "head" member indicates how many entries are actually being used.  That is, entries from 0 to head-1 are being used and the ones after that are "empty".  

That is pretty much what you are used to with stacks.  ie. data is added the same and stored the same.  but the removal process will be different.  In the removal process will will find the lowest item (closest to 0) in the queue with the longest length and we will remove that item.  Now that leaves a "hole" in the array", ie its position is not being used.  To get around that, we will shift all the items after it forwards to fill its hole.  (The point to using linked lists is that this shift is not needed. (Or that the search is not needed, either way a linked list is easier.))    Note the wording I used for the item to be removed I said the LOWEST item with the longest length.  By that I mean we will find the longest item.  But if there are two items that have the same length and this is the longest length, we will take the lower one---because it is older.

Does the algorithm make sense?
Next, lets talk about types.  We are going to make the queue store items of type T, the template  parameter.  Now at times it may be using T *'s or T &'s and it may store T *'s in order to do its work, but its job is to store T's not T *'s.  I mention this, because given an assignment like this, people's first intuition is to think that the queue will store char *'s or strings.  Then they think that T is char and all through out the program they it working with T *'s.  Then when they go to make it work with int's they run into a problem because they don't want to be working with int *.  They want int.  the problem is that T should have been "char *", not just char.  Does that make sense?

anyways to make this work cleanly for a variety of types, the teacher has given you a break (but explained it so poorly that it is no break at all).  He is saying that you can use a fixed array like char[200]; as the data stored in the queue.  i.e. T might be a type declared like char[200] rather than char *.  This is easier to deal with, since this type actualy stores the value you need, just like the int stores the value you need.  while a char * doesn't store the value, it stores a pointer to it.  so this change makes the int and character cases logicaly the same.  Make sense?

I have to go soon, I'm going to have to speed this up.  continues.
>>LOWEST item with the **longest length**

meaning the longest length of time in printing???
Now just keep in mind that T is wnat we want to store, not a pointer to it.  that was the point I was making.   (for this project, not always).

looking at the class def

template <class T>
   class queue
   {
     public:
       queue();
       queue(const queue<int> &);
       ~queue();
       void enqueue(const T &);
       T dequeue();
     private:
       int pollEmpty();
       int pollFull();
       T *queues[200];
       int head;
   };

this is all good.  Note that queues is declared as T *, that is fine (prefered).  as I said the queue's job is to store T's, but it may use T *'s to do that.  (Its job is not to store T *'s, though).

lets make two changes.  "queues" is a bad name, that is not an array of queuues.  You could call it pointer array (PtrArray) item array (ItemArray) something lie that.  More importantly, lets make its size a little easier to change in the future.  we'll use a constant to denote the size, like

template <class T>
   class queue
   {
     public:
      const int QueueSize = 200;
       queue();
       queue(const queue<int> &);
       ~queue();
       void enqueue(const T &);
       T dequeue();
     private:
       int pollEmpty();
       int pollFull();
       T *queues[QueueSize];
       int head;
   };

continues.
well it all makes sense to me but... not to my programming skills...!!!
Lets talk algorithms again.  There are two ways that a container can store data.  it can just
store a pointer to the data that the caller specified or it can store a private copy of the data.  The first method is fast because no copy need to be made, but it is dangerious.  The problem is that since it has a pointer to the caller's data, if the caller changes the data, the item in the container is changed,  That is ussually a problem.    Thus the container will store its own T, not a pointer to the caller's T.  But to do this, when a T is added, it will create a new T dynamically and will initialize it as a copy of some T the caller specified using new T(Src)"   (Src is the name of the T to be copied--the one the caller specified).  This means that it is responsible for deleting any T that it creates.  Thus--and here is the point--the queue destuctor must delete any T's left in the queue.  So if the queue is not empty, the destructor must use delete to delete any items still in the queue.  (One easy cheat for this is to just have the destructor call dequeueu() until the queue is empty. )
Fix that.  I will be back in about 45 minutes.



The queue is going to store its own T's, not the T's supplied to it when an item is added, but its private copy of the T.    

template <class T>
   queue<T>::queue(const queue<int> & q)
   {

   }
I'm back.   I didn't see your comments before.  

you wrote
>> >>LOWEST item with the **longest length**

>>     meaning the longest length of time in printing???

I suggested that because you said in the original question

>> 3) Print Document   -- removes longest off queue & displays character string on screen

What does longest mean in that sense?  I was assuming the longest string in the queue.  Do you mean the one that was there the longest?  (That would be preferable, since then we could do a circular queue.)


I've made the following changes and you can see the errors below.

template <class T>
class queue
{
    public:
(5)    const int queueSize=200;
        queue();
        queue(const queue<int>&);
        ~queue();
        void enqueue(const T &);
        T dequeue();
    private:
        int pollEmpty();
        int pollFull();
(14)  T *itemArray[queueSize];
        int head;
};

queue.h(5) : error C2258: illegal pure syntax, must be '= 0'
queue.h(5) : error C2252: 'queueSize' : pure specifier can only be specified for functions
queue.h(14) : error C2065: 'queueSize' : undeclared identifier


>>The queue is going to store its own T's, not the T's supplied to it when an item is >>added, but its private copy of the T.

is this what you mean:

template <class T>
queue<T>::queue(const queue<int> & q)
{
      T=new T();
}
it's the only way that does not give me errors...

I would think ('cause I'm not too sure here)  he meant the one that has been in there the longest...

>> I was assuming the longest string in the queue
is this a very common way of programming a queue, because I think what he wants should be very common...
I'm actually going to assume that we do want a circular queue, that is, that items should removed in the same order they went in.  Let me know if that is wrong!

For a circular queue, you have two indexes, head as before, and tail as well.  There are different ways of dealing with head and tail, but the way I like it is

Head is the index of the next spot where an item can be placed.  Thus if head is 10, the next item added will go in the array at [10].

Tail is the index of the next spot with an item to be removed.  That is if tail is 5, the item [5] hould be removed next.

If head equals tail, that makes no sense, the spot to add doesn't have an item, so how can that be the spot to remove.  It doesn't mkae sense, so we will use that as a special case, to indicate that the queue is empty.  i.e. tail is the spot to remove at, unless it is the same as head, in which case there is nothing to remove.

Now items are added in the array pretty much as before.  Head starts at 0, when an item is added, it is placed at [0] and head is made 1, and so on.  

Tail starts out at [0], when you remove an item, the item is removed from [tail], and tail is increased.  

so what you have is that array starts filling at the front and fills toward the end.  It is emptied from the front and empties toward the end.  That is the propper FIFO order.  Make sense?  

it looks like this  0's are empty spot1 1's are used spots.

000000 empty
100000 1 added
110000 1 more added
111000 1 more added.
011000 1 removed
011100 added again
001110 removed

As you see, this "uses" the empty portion towards the end of the array and leaves a new empty portion toward the start of the array.

Problem.  What happens when we reach the end of the array?  What if you have

000111

the array has 3 empty spots, but where to we put the next item to be added.  We make the array "seem" circular.  What we do is say that conceptionally the first position, comes after the last one.  thus those three empty spots in a sense follow the 3 used ones.  Thus the next one to be added is like

100111 added 1
110111 and 1 more.

Make sense?

The way this works, is that head and tail "wrap back"  at the end, that is when they have to go past the end, they are set back to 0, the start.  

given this design.  how can you tell when the queue is full and when it is empty?  (you tell me.)

Answer that question, add a tail, make the destructor empty the queue, and repost the code.
Okay, then the last comment was not a waste.  I'll check in in about 1 hour.
by the way he explained it (drawing a container), it was like:

31
15
27
5
72
remove 72 and 5 drops in 72's position, 27 in 5, 15 in 27 and 31 in 15 ... always leaving only one spot at head to be filled...???  
That's a non-circular queue.  Not as good an algorythm, but easier to write (not a lot).  It can be very inefficient because you have to do a lot of shifting, that is,each time you remove an item, al the items after it has to be shifted forward.  The circular queue doesn't do that shift and is therefore much more efficient.  However there is a lot to be said for easy assignments...

okay.  

1.  keep the head (no2 tail needed).
2. make the destructor empty the queue.
3. make the dequeue procedure return the item in the lowest position ([0]) and then shift all the items after it forwards.  To do this, you need to save the item in the lowest position in a local (temporary) variable.  Adjust head.  Then use a for loop to shift the remaining items forward.  then return this saved item.

that leaves you pratically done for the queue.

The print job should store a char[200] not a char *[200];

I don't think you need the document stuff, also I don't think you need a destructor or a copy constructor, you do need a getString() so change it to

class printjob
   {
     public:
       printjob();
       void setString(const char *);
       const char * getString();
     private:
     char str[200];
   };

The constructor just setts the string to a NUL string.  (empty).
The SetString copies in the source string.
The GetString returns the stored string.

Give that a try.  I have to go for a little while.  good luck.

nietod,
I'll have to try it later, also have to go for a while... out of town regarding my godfather... probably be back tomorrow am... or very late tonight (around 11:00)... hope to be able to finish it, since it is due Mon. am.  Thanks for your help... back in touch later...Hope you'll be around...!
Once again THANK YOU!!!
appreciative
nietod,
can I send my code via e-mail... having problems (slow)???
That would be fine.
I think there might be a problem, I replied to ALL of your e-mails, but you don't seem to be getting them.  I will try one more time.  if you don't get it soon and if you see this, let me know and i will post here.
no nietod, I did not receive any of your replies to my messages... I was starting to think that you had simply abandoned me... or something....!!!  What a relief to hear from you...I will check the site out, regularly, also could you please send the window for accepting/marking reply, from my end I only have the edit or delete question window... Thanks
appreciative
ASKER CERTIFIED SOLUTION
Avatar of nietod
nietod

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi nietod,

I still have not received any e-mail... thanks for posting here....
I've been trying out different combinations in order to get the program to work, without success... I don't know, but I guess my eyes are not meant to see this program work...!!!

I'm posting the errors, maybe if you see them you will be able to resolve them, if you have the time of course, thanks nietod!!!  I wonder what's happening with the e-mail...

***for   str='\0'
printjob.cpp(6) : error C2439: 'str' : member could not be initialized
printjob.cpp(7) : error C2166: l-value specifies const object

***for   strcpy(str,string);
printjob.cpp(18) : error C2664: 'strcpy' : cannot convert parameter 1 from 'const char [200]'                          to 'char *'

***for   queue <printjob> q(5);
printjob.cpp(45) : error C2664: 'queue<class printjob>::queue<class printjob>(const class                          queue<class printjob> &)' : cannot convert parameter 1 from 'const int' to                          'const class queue<class printjob> &'

***for   getline(cin,MaxStringLength-1);******I've also tried getSring in every possible way
queue\printjob.cpp(62) : error C2065: 'getline' : undeclared identifier

***for   if(q.pollFull())*****I've resolved these 2 by declaring them in public instead of private.
printjob.cpp(68) : error C2248: 'pollFull' : cannot access private member declared in class                                              'queue<class printjob>'

***for  if(q.pollEmpty())
printjob.cpp(74) : error C2248: 'pollEmpty' : cannot access private member declared in                                                  class 'queue<class printjob>'

***and when I compile from the "queue"  instead of  "printjob"  I get
error LNK2001: unresolved external symbol _main
I'm now up to 25 points, so I increased the points to 95 since you helped me so much on this program nietod...
Thanks.  
By the way, I did get messages back that your e-mail server (hotmail?) is not responding, but that the server sending to it is retrying and will for 4 more days.  So you should eventually get the files.
Opps, I didn't see that previous message.

str='\0'  should be  str[0] = '\0';  (that is what appears above.)

>> cannot convert parameter 1 from 'const char [200]'
That sounds like a const got added somewhere, like the function SetString is not declared const, like
class PrintJob
{
   void SetString(const char *string) CONST;
}
extra const in CAPS.

getine is defined . iostream.h, make sure that is included.  I changed the syntax (by mistake) to the form used with string classes, rather than the one used with char * strings.  It was

getline(cin,MaxStringLength-1);

it should be

cin.getline(string,MaxStringLength-1);

>>error LNK2001: unresolved external symbol _main
Are these two in a single "project"?  Then need to be linked together in some way.

If you need more help, ask a 0 point question for me.  This one is getting too slow.
thanks for everything nietod.  I finished school, for xmas holidays, yesterday.  Got home at 4:30 pm, called my mom and dad (no word of my godfather) and went straight to bed....got up at approx. 8:30 pm went back to bed at 10:30 pm and slept straight through to 9:00 this am...!!!  I really needed that.... I was quite tired... and that is not even the word...!!!!

Well,

for(int i=0; 1<1000000000000000000; i++)
        cout<<"THANK YOU VERY MUCH!  MERCI BEAUCOUP!";

have a very MERRY XMAS nietod and a very HAPPY NEW YEAR, health, love and prosperity!!!! respectively...!!!

appreciative
ps  one of my class mates said he sent me an e-mail, I never got it??? and I never got your last ones either...
bye!!!