Solved

Need debug help -->  queue will not store values

Posted on 2006-06-27
10
275 Views
Last Modified: 2010-04-24
Greetings:

The code below is from a 'Data Structures & Algorithms' course I took a while ago.  I need to duplicate the same basic behavior in a .Net Form Application so I included the functions below in my project as a separate file (.cpp).

The problem I'm having is that the queue ( circular - array using MODULUS) won't store more than one 'value' and it's not a pointer problem.  Here's the function in question:

Boolean insert(queueADT *q, dataType value)
     {

          if(!full(*q)){
               q->tail = (q->tail + 1)% MAX_Q_SIZE;
               q->elements[q->tail] = value;       //  DOES NOT SHOW ERROR BUT NO ASSIGNMENT IS MADE
               return TRUE;
          }
          else
               return FALSE;

     }

I have made it convenient to debug by providing all the necessary code below.  All you have to do is copy and paste into a new project.  I'm using .Net 2003 and building a Form Application.   However, the code below will be for a console project and demonstrate the problem.

This program was meant to demonstrate how a print queue works and requires an input file such as this:

qjobs.txt  // or whatever you choose to name it --> stored in your project directory

time         job                // header line --> do not include in the actual file
----------------------
0010        NJR25
0020        BH875
0030
0040        L89V2
0050
0060

For every empty slot in time, the queue deletes or processes one job.  Thus, the queue would be empty after time '0060' above.  So again, if you copy and paste this code into a new project it will compile.  Then set a break-point on the line in question above and set a 'watch' on 'q.'  You will see how the queue will take one insert...  All the rest will appear to have inserted but they don't and no error is reported during runtime.

I don't know if this is a .Net 2003 issue or what, but it simply doesn't make sense because the program works elsewhere?  What am I missing ???   Thanks !

=========================================================================
// This is the main project file for VC++ application project
// generated using an Application Wizard.

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_Q_SIZE 6                             // max length of static queue  
#define ID_LENGTH 10                             // size of print job ID #  

//#using <mscorlib.dll>

using namespace System;

     typedef struct {                             // define the base data type  
          char jobID[ID_LENGTH];            // for the queue: a string  
          unsigned int insertTime;                // and an unsigned int for time  
     } dataType;                                  // ---- DATA TYPE ----  

     typedef struct {                             // define the structure of  
          dataType elements[MAX_Q_SIZE];          // the static queue: a list  
          int head;                               // of elements, a head ptr,  
          int tail;                               // and a tail pointer  
     } queueADT;                                  // ---- QUEUE ADT ----  

     void readFile(queueADT *);

                                    //  Queue Maintainence  
     bool insert(queueADT *, dataType);            // insert an element  
     bool insertJob(queueADT *, dataType);         // non ADT function  
     bool delet(queueADT *, dataType *);           // delete an element  
     bool removeJob(queueADT *, dataType *, unsigned int*);  // non ADT function  
     bool full(queueADT);                       // test for full queue  
     bool empty(queueADT);                      // test for empty queue  
     void initializeQueue(queueADT *);            // set up a new queue  

int _tmain()
{
          
    Console::WriteLine(S"Hello World");
      // Display the menu and get the entry: r, or q    

    char response='b';         // initialize to start while loop  
    dataType Dummy;                // used to destroy the queue upon exit of the proram  
    queueADT queue;
    initializeQueue(&queue);

    while ((response != 'q') && (response != 'Q'))
    {
            fflush(stdin);
        printf("\n\n");
        printf("r)ead,   q)uit,\n\n");
        printf("Selection:\n\n");
        response = getchar();
        fflush(stdin); // flush I/O buffers - in case more than one char was entered  
        printf("\n");

        if ((response != 'q') && (response != 'Q'))
        {
                  switch (response)
            {
                        case 'r':
                case 'R':                        // Access Input File  
                              readFile(&queue);
                    break;
                default:
                    break;
             }                                        // end switch  
        }                                             // end if    
      }                                                // end while  


    while(!empty(queue)){
            delet(&queue, &Dummy);
    }
    printf("Queue destroyed!\n");
      return 0;
}

/* ------------------------  Read File  ------------------------------
     Input: The initialized queue passed from main
     Output: Prints the average wait time for all print jobs upon termination
     Returns: -
     Assumptions: A .txt data file is input from the user containing a maximum
                          of one time-stamp and print-jobID per line.
     Description: Examines incoming file to determine if each line should be
                          processed as a queue insert or remove.  It also calculates
                          the average elapsed/wait time for all jobs in the queue by
                          receiving each elapsed time from the removeJob function as
                          a pointer to an unsigned int.
     */

     void readFile(queueADT *q)
     {

          FILE *inputFile;                        // input file pointer  
          char fname[40];
          char buff[20];
          char *token;
          unsigned int totalElapsedTime = 0;    // keeps the running total  
          unsigned int avgWaitTime;             // elapsed time divided total jobs (count)
          unsigned int count = 0;                  // counter for all jobs removed from queue  
          unsigned int curElapsed;                 // value received from removeJob  
          unsigned int *elapsed = &curElapsed;
          dataType stamp_job;                      // struct to hold a time-stamp and jobID  
          dataType *stampJob = &stamp_job;

          printf("Enter a file to read:\n\n");
          scanf(" %s", fname);
          inputFile = fopen(fname, "r");

                    if( inputFile == NULL ) {
                         printf("Unable to open datafile %s\n\n", fname );
                         return;
                    }

                    while(!feof(inputFile)){

                         fgets(buff, 20, inputFile);

                         if (strlen(buff) < 3)    // If there is no stamp or data  
                              continue;

                              // strtok() used to obtain time and jobID from buffer  
                              token = strtok(buff, " \n");
                              stamp_job.insertTime = atoi(token);

                              //continue until space or end of line  
                              token = strtok(0, " \n");

                              if(token == NULL){
                                   removeJob(q, stampJob, elapsed);

                     // keep running total of elapsed time for jobs waiting in queue  

                                   totalElapsedTime = (totalElapsedTime + curElapsed);
                                   count++;
                                   avgWaitTime = totalElapsedTime/count;
                                   continue;
                              }
                              else{
                                   strcpy(stamp_job.jobID, token);
                                   insertJob(q, stamp_job);
                              }

                    }       // end of while  
                    printf("Average wait time for print jobs:\n");
                    printf(" %i milliseconds!\n", avgWaitTime);
     }  //end readFile  

     /* ------------------ Initialize Queue -------------------------------
     Input: The queue pointer passed from main
     Output: -
     Returns: -
     Assumptions: The QueueADT struct has been declared within main prior
                          to passing the queue pointer to initializeQueue()
     Description: assigns the head and tail ints to the same position.
     */

     void initializeQueue(queueADT *q)
     {
          q->head = q->tail = MAX_Q_SIZE -1;
     }


     /* ------------------------- Empty -----------------------------------
     Input: The queue passed from delete()
     Output: -
     Returns: - bool, true if the head int is equal to the tail int
     Assumptions: -
     Description: If the head is equal to the tail, the queue has no items
                          in it because the tail is incremented with each insert.
     */

     bool empty(queueADT q)
     {
          if(q.head == q.tail)
               return true;
          else
               return false;
     }


     /* -------------------------- Full -----------------------------------
     Input: The queue passed from insert()
     Output: -
     Returns: - bool, true if the tail + 1 is equal to the head
     Assumptions: -
     Description: If the head int is equal to the tail int, the queue has
                          no items in it because the tail is incremented with each
                          insert.
     */
     bool full(queueADT q)
     {
          int temp;

          temp = (q.tail + 1) % MAX_Q_SIZE;

          if(temp == q.head)
               return true;
          else
               return false;
     }

     /* ------------------------- Insert ----------------------------------
     Input: The queue pointer and dataType struct passed from insertJob()
     Output: -
     Returns: - bool, true if a job was inserted onto the queue
     Assumptions: -
     Description: After ensuring that the queue is not full, the tail is
                          first incremented, then the new dataType is inserted in
                          the tail position.
     */

     bool insert(queueADT *q, dataType value)
     {

          if(!full(*q)){
               q->tail = (q->tail + 1)% MAX_Q_SIZE;
               q->elements[q->tail] = value;
               return true;
          }
          else
               return false;

     }

     /* -------------------------InsertJob --------------------------------
     Input: The queue pointer and dataType struct passed from readFile()
     Output: Generates a message whether the print-job was inserted or not
     Returns: - bool, true if a job was inserted onto the queue
     Assumptions: -
     Description: Solely responsible for printing in order to maintain the
                          ADT functionality of insert()
     */

     bool insertJob(queueADT *q, dataType value)
     {
          int result;
          result = insert(q, value);

               if(result == 1){
                    printf("Job '%s' sent to queue at %i!\n", value.jobID,value.insertTime);
                    return true;
               }
               else{
                    printf("Queue is full, job %s denied!\n", value.jobID);
                    return false;
               }
     }


     /* ------------------------- Delete ----------------------------------
     Input: The queue pointer and dataType struct passed from removeJob()
     Output: -
     Returns: - bool, true if a job was deleted/removed from the queue
     Assumptions: -
     Description: After ensuring that the queue is not empty, the head is
                          first incremented, then the dataType needed is accessed
                          from the real head position.  It isn't until the following
                          call to delete() that the current job is lost/deleted.
     */

     bool delet(queueADT *q, dataType *job)
     {
          if(!empty(*q)){
               q->head = (q->head + 1) % MAX_Q_SIZE;        // update queue head  

               // changes dataType located in readFile()
               *job = q->elements[q->head];
               return true;
          }
          else
               return false;
     }

     /* ----------------------- removeJob ---------------------------------
     Input: The queue pointer, a dataType pointer and unsigned int pointer
     Output: Generates a message whether the print-job was processed or not
     Returns: - bool, true if a job was deleted/removed from the queue
     Assumptions: -
     Description: Responsible for printing to maintain the ADT functionality
           of delete() and to calculate elapsed time of jobs waiting in the
           queue.  The elapsed time is calculated by first accessing the incoming
           dataType time (curTime) read in from the readFile() function.  Second,
           the outgoing or changed dataType from the delete() function is
           accessed using the same dataType pointer as the first, to obtain the
           queue insertTime again.  The second insertTime is then subtracted from
           the first (curTime) to arrive at the elapsed time.
     */


     bool removeJob(queueADT *q, dataType *datatype, unsigned int *elapsed)
     {
          bool result;
          unsigned int curTime = datatype->insertTime;
          unsigned int elapsedTime;

          result = delet(q, datatype);

               if(result == true){
                                                        //the updated insertTime from delete()
                    elapsedTime = curTime - datatype->insertTime;
                    *elapsed = elapsedTime;
                    printf("\nJob '%s' processed at %i!\n", datatype->jobID,curTime);
                    printf("Elapsed time in queue = %i\n\n", elapsedTime);
                    return true;
               }
               else
                    printf("Unable to process job '%s' - queue empty!\n", datatype->jobID);
                    return false;
     }


0
Comment
Question by:John500
  • 4
  • 4
  • 2
10 Comments
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
I don't have VS.NET available at he moment, but I can verify that the above code works fine when compiled and executed under VC6.  (I removed the 'using namespace System' and the Console::Writeline to make it compile)

At the indicated point, the content of the data structure
     value
 is copied to the queue slot
     q->elements[q->tail]

I can see nothing wrong with the syntax nor think of any reason that the assignment should fail.  What is your program output?  Mine looks like this:

Job 'NJR25' sent to queue at 10!
Job 'BH875' sent to queue at 20!

Job 'NJR25' processed at 30!
Elapsed time in queue = 20

Job 'L89V2' sent to queue at 40!

Job 'BH875' processed at 50!
Elapsed time in queue = 30


Job 'L89V2' processed at 60!
Elapsed time in queue = 20

Average wait time for print jobs:
 23 milliseconds!
Queue destroyed!
0
 
LVL 15

Expert Comment

by:lakshman_ce
Comment Utility
1. Replace your read file method

void readFile(queueADT *q)
{

FILE *inputFile;                      // input file pointer  
char fname[40];
char buff[20];
char *token;
unsigned int totalElapsedTime = 0;    // keeps the running total  
unsigned int avgWaitTime;            // elapsed time divided total jobs (count)
unsigned int count = 0;                // counter for all jobs removed from queue  

dataType stamp_job;                    // struct to hold a time-stamp and jobID  
dataType *stampJob = &stamp_job;

printf("Enter a file to read:\n\n");
scanf(" %s", fname);
inputFile = fopen(fname, "r");

if( inputFile == NULL ) {
printf("Unable to open datafile %s\n\n", fname );
return;
}
else
{
for (int i=0;i<2;i++)
fgets(buff, 80, inputFile);
}

while(!feof(inputFile)){


fgets(buff, 20, inputFile);

if (strlen(buff) < 3)    // If there is no stamp or data  
continue;

// strtok() used to obtain time and jobID from buffer  
token = strtok(buff, " \n");
if (token != NULL)
{
stamp_job.insertTime = atoi(token);
//continue until space or end of line  
token = strtok(0, " \n");
if(token == NULL)
{
removeJob(q, stampJob, elapsed);
// keep running total of elapsed time for jobs waiting in queue  
totalElapsedTime = (totalElapsedTime + curElapsed);
count++;
avgWaitTime = totalElapsedTime/count;
continue;
}
else
{
strcpy(stamp_job.jobID, token);
insertJob(q, stamp_job);
}
}

}      // end of while  
printf("Average wait time for print jobs:\n");
printf(" %i milliseconds!\n", avgWaitTime);
}  //end readFile  


2. Move these to global (from readfile)

 unsigned int curElapsed;               // value received from removeJob  
     unsigned int *elapsed = &curElapsed;

Following is the output. Is this what you expected?

qjobs.txt
Job 'NJR25' sent to queue at 10!
Job 'BH875' sent to queue at 20!

Job 'NJR25' processed at 30!
Elapsed time in queue = 20

Job 'L89V2' sent to queue at 40!

Job 'BH875' processed at 50!
Elapsed time in queue = 30


Job 'L89V2' processed at 60!
Elapsed time in queue = 20

Average wait time for print jobs:
 23 milliseconds!
0
 

Author Comment

by:John500
Comment Utility
lakshman_ce/Dan,

What I'm saying is that I can get this program to run in Visual Studio 6, but I can't get it to run in VS .Net either way I use it:

1)  As a console project shown above
2)  As an additional cpp (although it's 'C' code) to my Form Application

As an additional cpp, I leave out readFile() and main() and pass the queue a different data structure from Form1.cpp

I need to use it in case '2' above but I can't get it to work in either case.  It seems as though I must be doing something wrong with VS .Net project properties.   Here's what 'q' looks like when I place a watch on it:

q->elements 0:  {LineUpNum = 1 SideNum = 500}  {elements={Length=5} head=4 tail=0
q->elements 1:  {LineUpNum = 0 SideNum = 0}  {elements={Length=4} head=4 tail=1}    // should be 2, 501  
q->elements 2:  {LineUpNum = 0 SideNum = 0}  {elements={Length=4} head=4 tail=2}    // should be 3, 502  
q->elements 3:  {LineUpNum = 0 SideNum = 0}  {elements={Length=4} head=0 tail=3}    // should be 4, 503  
q->elements 4:  {LineUpNum = 0 SideNum = 0}  {elements={Length=4} head=0 tail=4}    // should be 5, 504  

The queue has a max size of '5' so this is where it stops.  The fields above reflect the new structure I'm passing between my Form1.cpp and my queue.cpp.  Since it would not work in my Form Application I created a new project just using the code from my original project (my first post above) and it still had the same problem.  It only accepts one value into 'elements' but the program doesn't show any errors at all !!

This tells me the problem isn't about how I'm passing the structure between cpps because it doesn't work in either project:

q->elements 0:  {jobID = "NJR25" insertTime = 10}  {elements={Length=5} head=4 tail=0
q->elements 1:  {jobID = "" insertTime = 0}  {elements={Length=4} head=4 tail=1}    // should be "BH875", 20  
q->elements 2:  {jobID = "" insertTime = 0}  {elements={Length=4} head=4 tail=2}    // should be "",  30
q->elements 3:  {jobID = "" insertTime = 0}  {elements={Length=4} head=0 tail=3}    // should be "L89V2", 40  
q->elements 4:  {jobID = "" insertTime = 0}  {elements={Length=4} head=0 tail=4}    // should be "", 50  

What could possibly be the issue if it were related to .Net ?   ..... or anything else for that matter ?

I'm going to try to put all the code in my Form1.cpp just to prove that it doesn't work anywhere no-how !
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
The reason I showed my output was so that you could compare your output to it.

What happened when you did that?
0
 
LVL 49

Expert Comment

by:DanRollins
Comment Utility
The reason I ask that is because I think the program is working OK, but you are setting up your watch window incorrectly so you *think* it is malfunctioning.
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:John500
Comment Utility
Now that you mention it, I do get the same output but this doesn't make sense.  Why would the watch window show the first insert for each project but not show any succeeding inserts ?

Between this problem and my inability to access the data, I'm convinced something isn't right.  Did you have the same results as me from your watch window ?
0
 
LVL 49

Assisted Solution

by:DanRollins
DanRollins earned 250 total points
Comment Utility
Again, I'me working with VS 6... my watch output does not show curly braces exactly like that ...

At the breakpoint, I right-click on the variable q and choose QuickWatch.
In the QuickWatch window, I then click on q and click [Add Watch]
In the Watch window there is now an entry like
   + q  {...}

I click the plus and it looks like..
   - q  0x0012ff14
     |  + elements
     |- head             5
     '- tail                0
 
I then click on the pluis in front of "elements" to reveal the five elements and it looks like..
   - q  0x0012ff14
     | - elements
     |  |+ [0]       {...}
     |  |+ [1]       {...}
     |  |+ [2]       {...}
     |  |+ [3]       {...}
     |  '+ [4]        {...}
     |- head         5
     '- tail            0

To look at the element[0], I click the plus in front of it...

   - q  0x0012ff14
     | - elements
     |  | + [0]
     |  |  |  + jobID   0x0012ff04
     |  |  |                "NJR25"
     |  |  '- insertTime 10
     |  |+ [1]       {...}
     |  |+ [2]       {...}
     |  |+ [3]       {...}
     |  '+ [4]        {...}
     |- head         5
     '- tail            0

=-=-=-=-=-=-=-=-=-=-=-
My guess is that you have set the watch up as if there were an array of five 'q' variables.  In fact, there is just one and it contains the five element values.

-- Dan
0
 
LVL 15

Accepted Solution

by:
lakshman_ce earned 250 total points
Comment Utility
It appears to be a problem in VS7. But in VS6 the values are shown correctly in the watch.

You would see the following variable's value changing for inserts.

q->elements[q->tail]

0
 

Author Comment

by:John500
Comment Utility
Dan/lakshman_ce,

Dan first --> you delivered me out of the woods last night under the pressure of a demo or peer review before management today !  I listened to your reasoning and sure enough, the queue was getting populated as necessary.  This enabled me to finish up the logic.  As I tested the 'container', it did in fact hold the values that should have been there.  Although this is some-what a simple queue, it has served to demonstrate more complex capabilities.

lakshman_ce --> I'm guessing you still remember me.  This is the same project you helped me to get off the ground almost one year ago.  I appreciate you taking a look at the code.  I wouldn't be where I'm at if it weren't for the questions you answered previously.

Until next time,

John
0
 

Author Comment

by:John500
Comment Utility
Guys,

After looking at the way EE processed my grading, it isn't accurate.  I simply wanted to spit the points.  There is no "Assisted Answer."

Dan, you provided the detailed 'watch' explanation..... lakshman_ce provided the evidence beyond dispute.....

This whole grading thing can put a conscientious guy under a lot of pressure !

(o o)
   L
  ~
0

Featured Post

How to improve team productivity

Quip adds documents, spreadsheets, and tasklists to your Slack experience
- Elevate ideas to Quip docs
- Share Quip docs in Slack
- Get notified of changes to your docs
- Available on iOS/Android/Desktop/Web
- Online/Offline

Join & Write a Comment

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
In Easy String Encryption Using CryptoAPI in C++ (http://www.experts-exchange.com/viewArticle.jsp?aid=1193) I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Illustrator's Shape Builder tool will let you combine shapes visually and interactively. This video shows the Mac version, but the tool works the same way in Windows. To follow along with this video, you can draw your own shapes or download the file…

762 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

Need Help in Real-Time?

Connect with top rated Experts

6 Experts available now in Live!

Get 1:1 Help Now