Link to home
Start Free TrialLog in
Avatar of John500
John500Flag for United States of America

asked on

Debugg

The following two functions are virtually identical.  One searches the database by id and the other by name.  The search by id (findStudent) works fine and has been tested.  The search by name(searchStudent)  has crashed every way I have set it up.   That is, using a while loop or for loop hasn't made a difference.  The for loop should work even if it is undesirable by some...  Could the spaces that precede the name field on a typical entry (i.e. 123456, John, 35, 3.4, Born in Boston... screw up the search function?

Student *Database::searchStudent(char *name)
{
      if(!name) {cout<<"Bad entry!"; return 0;}            // nothing to delete
      if(!_head)                                                                  //  no list
            { cout << "Empty list!";
              return 0;
            }


      for (Student *p = _head; p!= 0 && strcmp(p->_name,name)!= 0; p = p -> _next);  //  classic traverse of list
            if(strcmp(p->_name,name)== 0)
                  {
                   cout<<"Found name:\n";
                   print(p);
                  }

            else
                  if(p == 0)
            cout <<"Name not found!\n";
            return 0;
}


Student *Database::findStudent(long ID)
{
      if(!ID) {cout<<"Bad entry!"; return 0;}            // nothing to delete
      if(!_head)                                                                  //  no list
            { cout << "Empty list!";
              return 0;
            }


      for (Student *p = _head; p!= 0 && p->_id != ID; p = p -> _next);  //  classic traverse of list
            if(p ->_id == ID)
                  {
                   cout<<"Found ID:\n";
                   print(p);
                  }

            else
                  if(p == 0)
            cout <<"ID not found!\n";
            return 0;
}

the following are the class definitions
class Student{
      public:
            Student(){_next = _prev = 0; _born = _name = _note = 0;}
            Student(char *buff);
            ~Student();
            print();
            friend class Database;

      private:
            long _id;
            char *_name;
            int _age;
            float _cum;
            char *_born;
            char *_note;
            Student *_prev;
            Student *_next;
};


class Database{
      public:

            void init();
            void print(Student *p);
            void printNames();
            void printAges(int A);
            void readDatabase();
            void writeDatabase();
            void addStudent(Student *pNew);
            int delStudent(long ID);
            Student *findStudent (long ID);
            Student *searchStudent (char *name);
            Database(){_head=0,_numStudents=0;}
            ~Database(){init();}

       private:
            Student *_head;
            int _numStudents;

};
the following is the driver program within main:

case 's':
                  case 'S': // Search a student
                  {
                        char buff[25];

                        printf("\nEnter student Name:\n\n");
                        cin >>buff;
                              database1.searchStudent(buff);
                  }break;
Also, string.h has been included for the strcmp func.
Thanks much for the help!!
Avatar of nietod
nietod

I gave you this answer yesterday.  Here it is again.
Your for loop

for (Student *p = _head; p!= 0 && strcmp(p->_name,name)!= 0; p = p -> _next);

can end two ways.  (1) If the desired name is found within the list or (2) if the end if the list is reached without finding the name.  You should be fine in case (1).  Case (2) will crash.  In case (2) the for loop ends with p set to NULL (that is 0).  Following the for loop the line

if(strcmp(p->_name,name)== 0)

executes.  In case (2) this will cash because p is NULL and you dereference it like p->_name.

The code I posted yesterday should clean this up and make it much neater.  Do you have questions about it?
Avatar of John500

ASKER

I don't believe your answer is true.  My first, and foremost test,  is to see if the student is found which I have entered.  The program is crashing after the student is found!  Also, your saying that the program is not able to react properly to "if" and "else" statements after the loop.  The only thing "dereferenced" (in your words) is the _next pointer which will be null at the end of the list.  This doesn't mean p has vanished and cannot still point to _name!!

I'm inclined to believe the professor, that this routine works (he gave us the find func) since the find function works.    

Also, in my last letter I included the findStudent () which works perfect under all circumstances but you failed say why it is different from the searchStudent() func. in its ability to work.

For credentials, I can offer the fact that I started programming in the days of punch cards.  I am one of the top assembly language programmers in the country.  I have extensive experience in system design.  I also have a great deal of teaching experience.  I program 60 to 80 hours a week and have done so form many years.  

You can trust me on this.

If your professor gave you

for (Student *p = _head; p!= 0 && strcmp(p->_name,name)!= 0; p = p -> _next);

    if(strcmp(p->_name,name)== 0)
// other stuff.

Then your professor gave you a bug! Try to follow this explanation.  

Say you are on the last itme in the list, that is, p point to the last item in the list.  Now, if that item doesn't have the name to search for, it executes the statement

p = p->_next;

Since the last item stored NULL or 0 in the _next member, p will now be NULL.  Do you agree so far?  What happens next?  It loops back and tries

p != 0 && strcmp(p->_name,name) != 0

however p is zero so the first part of that p != 0 is false, so the loop terminates.  Agreed?

Now the loop has terminated with p being NULL (or zero.)  The program continues and executes the if statment.

if(strcmp(p->_name,name)== 0)

inside that if statement there is the section that does    

p->_name

do you see that?  if p points to something that is fine.  But in this case p is NULL and therefore p->_name causes a crash.   Does that make sense?
Now for the fine print....

This is a serious bug and is likely to be the one you are experiencing.  However it is not necessarily the one you are experiencing.  So lets get it fixed and see what happens.  If there are still are problems after this is fixed, we'll find them.  But this does need to be fixed.  

If this doesn't fix tje problem you are experiencing, don't feel obligated to ask another EE question on this topic.  I will (most experts will) do what ever it takes to help get a program running.  If in fixing one problem another is encountered you can usually ask the expert and get a "free" answer.  (You could have asked this stuff in your existing question.)

I didn't mention it, but both searches suffer from this bug.  They but can end with p being NULL.  Then afterwords they both try to dereference p.
Avatar of John500

ASKER

Todd,

The program didn't compile at first because of a ")" after the p->_next.  No biggy just wanted to let you know I fixed that before telling you the function still doesn't work.  What happens is that I get "Name not found!"  What you had last night and in the last email was:

Student *p = _head;
>
>       while (p)
>       {
>          if (strcmp(p->_name,name) ==  0)
>             break;
>          p = p -> _next);
>       }
>
>       if (p)
>       {
>           cout << "Name found: ";
>           print(p);
>       }
>       else
>       {
>           cout << "Name not found!\n";
>       }
>       return 0;

You will notice that if (p) returns Name found:  I switched this to Name not found! Correct?
I'm going to take you up on yesterday's suggestion and email you the entire code.  I'm not asking for, or do I want major changes.  I feel I am almost there to making the entire menue for the program work.  I also added a routine to the readDatabase function to change the first letter of the first name to upper case.  It almost works but for some reason it won't go into the second strchr routine.

I figure it may be easier for you to compile the code and see for yourself the problems I have asked about.  One other thing that is occuring and which may be causing problems, is that I have noticed some entries don't make it into the database (see student constructor and addStudent).  I have no clue especially when reading a long file of students.  The name/note selection can verify entries.

Thanks much.  You can zero out my points if necessary which are down to 105.


Avatar of John500

ASKER

The following is a list of students that should be read into the database.  The readDatabase function will read them in and the addStudent function will alphabetize them but for some reason all the students having the longer (9 digits) id don't make it in!

Thanks again!

7868342, Clinton, 00, 0.00, U.S., has a problem with inhaling
9742977, Camby, 1, 1.01, U.S., Travel's a lot-scores a lot-never in class?
2542341, Dick. V., 92, 2.00, U.S., Annoyingly repeats "Baby"
9953891, babson,23, 2.3, alabama, a great guy
9953886, baden, 12, 4, wyoming, nice person
9889426, balboni, 45, 1.2, kuwait, not too happy
9882137, bastia, 24, 2.7, masachusetts, going far
9487179, berwind, 78, 2.45, new_york, quite tall
9100954, bleiwas, 125, 1.2, maine, nice hair
9041638, buxton, 3, 4, albania, you can't tell
8952897, charron, 16, 3.2, spain, what a guy!
8932284, chen, 18, 2.8, france, lovely person
8895516, cheng, 21, 3.1, wyoming, not too bright
8763883, chesebro, 25, 3.5, wyoming, very persuasive
8539714, dejeu, 23, 4, china, determined
8426881, dibiasio, 67, 2.5, germany, a fried to all
7957376, dinh, 102, 0.13, vermont, wouldn't you like to know
7790720, donati, 98, 2.1, new_york, excellent cook
7489171, dunn, 5, 3.1, france, fine musician
7460615, fenton, 11, 2.1, russia, kind of shy
7145775, foo, 9, 3.5, finland, always in love
7108532, gelasco, 13, 3.2, spain, adored by parents
6812216, giorgi, 25, 2.1, massachusetts, can never find him
6771972, gresh, 43, 4, colorado, loves to party
6609144, hagan, 76, 1.6, california, great boogie dancer
6586296, hruska, 32, 1.8, oregon, marvelous pianist
6568428, julin, 4, 2.6, new_jersey, can't tie his shoes
6568422, kobeissi, 12, 2.5, florida, eats with a shovel
6539625, lo, 13, 1.8, maine, seems retiring
6539612, mathews, 72, 3.4, france, loves to study
6314630, morris, 91, 3.2, england, outstanding polo player
5824521, nelson, 13, 4, ireland, lean and mean
5356457, nelson, 25, 2.6, iceland, liked by everyone
4849596, ng, 35, 1.8, florida, always helpful
4503200, ngai, 32, 2.6, arkansas, shy but strong
4196850, nicolas, 12, 3.7, texas, lots of girlfriends
983650983, Woody, 23, 1.0, United Kingdom, Most likely not
3679988, nixon, 11, 3.6, spain, never studies
3600075, olson, 14, 4, germany, eats only pasta
3322019, oshea, 21, 1.8, ohio, beer is his favorite
3235595, petrillo, 20, 2.9, wisconsin, should learn how to drive
2985140, piazza, 30, 2.7, massachusetts, lots of fun
2817097, rasakula, 31, 3.5, italy, plays the harp
2552844, redlich, 24, 2.4, israel, wants to leave home
2398099, ross, 13, 3.8, china, knows here place
2317478, samji, 17, 2.4, india, great fisherperson
2291673, smarz, 12, 1.8, india, hates baseball
2206164, somerville, 15, 3.5, texas, very gregarious
1531690, stover, 75, 1.9, england, who knows?
1524164, swiniarski, 23, 2.5, hawaii, never stops talking
1521790, tan, 21, 3.5, italy, gets good grades
1498661, tavares, 35, 4, yugoslavia, wants to be a leader
1226654, thomas, 21, 1.9, tibet, shuns all adults
766322, tohline, 12, 2.3, vietnam, loves kids
671381, wei, 23, 4, poland, wants to go west
486341, ye, 21, 3.8, korea, travels all over the world
3774757,Bobrow ,56, 66000, Honolulu, 3
375746, yoffa, 45, 2.5, israel, questions everything
326996, zhao, 11, 4.1, italy, never eats
320614, zhu, 8, 2.6, maine, will be a movie star
027762096, Chuong, 26, 2.8, Sai Gon City, love living in a warm family
099723654, Paul, 29, 3.8, Houston, love hunting
987568765, Mike, 22, 3.3,  Dallas, eat Chinese foods
876459234, Dan, 30, 3.67, Denver, go fishing
234765439, Mike, 38, 3.2, Westborough, like shopping
764532123, Phillip, 24, 2.7, California, like McDonald's food
678543652, Dave, 39, 3.5, Maynard, like perfume
023457612, Bill, 44, 3.7, Burlington, love cook out
765349876, Robert, 55, 39, Boston, 4
765340987, Kumar, 32, 34, India, 2
017800166, tanviakkad, 18, 3.8, Bombay, loves gymnastics
017800160, saloni, 18, 3.2, Bombay, loves dancing
031749774, madhuri, 18, 3.5, Baroda, loves dancing
013245744, sonia, 18, 3.9, Delhi, loves studying
078943399, amita, 18, 4.0, Legos, loves studying
123897223, charu, 21, 3.5, Delhi, likes music
656456488, prerna, 18, 3.8, Muskat, loves partying
789215855, julie, 18, 3.4, Holliston, loves annoying people
416544543, ranjan, 25, 3.6, Gaya, loves drinking
879615664, sachin, 22, 3.8, Bombay, loves debates
130746796, Jason Barrett, 22, 3.0, Walpole, addicted to Simpsons
132536867, Jake Isley, 23, 3.2, Georgetown, likes bugs
325153234, Bib Fortuna, 35, 3.8, Jabbaville, humble servant
342853143, Obiwan Kenobi, 42, 40000, Tattoine, 3
122435375, Yoda, 48, 60000, Dagobah, 2
234382185, Frank Rizzo, 48, 2.2, New York, loud mouth
132435231, Amanda Hugankis, 32, 90000, Chicago, 1
321534532, Joe Spivey, 27, 1.7, Boston, demolishes cars
123252523, Natalie Jergensen, 24, 3.2, Patterson, nuclear physicist
213231422, Jessica Sorvino, 35, 2.9, Denver, heavyweight champion
124578098, Joe Gray, 28, 0.1, Boston, member of DRiLLBiT
436283092, Joseph Laurier, 25, 3.0, Bedford, plays Heavy Gear
438940859, Shtumpa, 25,  3.9, South Hadley, drinks for the government
102948573, Burt, 39, 62000, New York, 4
834729340, Bill Hanley, 54, 1, Montague, 4
934849039, Erishkigal Anana, 4,  4.0, Amherst, Eats spoonfuls of salt
849302948, Tao Jones, 29, 2.0, Pennsylvania, Went to LA to become a star
493059832, Noah Escape, 26,  2.1, Tucson, Can do clover leaf
490943928, Spooky, 24,  3.5, Pennsylvania, Wrote Welfare Mom on her head
563547666, Wayne, 39,  3.9, New York, Is saving for a haircut

>> You will notice that if (p) returns Name found:  I switched this to Name not found! Correct?

No.  The loop ends with either p pointing to the student object with the specified name or with p as NULL if there were no students with the specified name.  Oh I know what the problem is.  I should have written it as

if (p != 0)
 {
     cout << "Name found: ";
     print(p);
 }
 else
 {
     cout << "Name not found!\n";
 }

note that "if (p)" and "if (p != 0)" is the same.  An if() executes the "if statement" if the experssion in the parenthesis is not zero.  If the expression is zero, it executes the "else statement", if there is one.  So it is very common to say "if (somepointer)" rather than "if (somepointer != 0)"  The work the same.  
Now the curent behaviour of it not finding the name is actually what I suspected would happen (I mentioned that before so you were prepared).  You previous code would crash when a student was not found with the specified name and it was crashing every time, so I fugured it was never finding a student.  You fix a bug to find a bug...

Before I go to the trouble of compiling this stuff (which I will do if I have to). Try a few tests first.  Print out the names that you are comparing, like

 while (p)
 {
 printf("*%s*\n*%s*\n\n"p->_name,name);
 if (strcmp(p->_name,name) ==  0)
    break;
  p = p -> _next);
 }

se if any of the names do match.  (most likely one of the names--the name to search for or the name to test against--isn't shat you expect it to be.  For example on might contain leading spaces, that sort of thing.  the printf() I used there will print *'s before and after the strings.  This let you see exavly how long each string is.  If a string has spaces at the end, you can tell that from the position of the *'s.  Not that the strings "name" and "name   " are not the same.  Those trailing spaces are important.

Try this and let me know.  If you do want me to compile this.  e-mail me the database file. (if you didn't already).  Copying out of here works poorly, the browser adds formating.
Avatar of John500

ASKER

Todd

You were right about the leading spaces.  The result of this line  
 printf("*%s*\n*%s*\n\n"p->_name,name) is * John* verses *John*

I had considered this but handled it a different way.  I entered the search name with a leading space (to try and prove the problem) but this didn't make the difference.  Anyway, any suggestions on how to correct the problem.

Two requirements for the program are: 1) leading spaces in any fields are deleted and 2)  The first character of the name field is set to upper case (first name only).
Up until now I felt that there would be no spaces before each field when it was dynamically created because the constructor would just put the characters in.

I was attacking the second problem before the first.  Is there a I/O function that will read in a file and delete the spaces or do I also have to make one.  If so are there any functions that do part of the job as did strchr for the lower to upper problem??

John
>> For credentials, I can offer the fact that I started programming in the days of punch cards.  I am one of the top assembly language programmers in the country.

And I thought dinosaurs were supposed to be extinct...
Alex,
(to be honest, I only wrote one program on punch cards...)  But the assembly part...

John,
   I'm not sure what to recomend at this time.  There are lots of possible solutions that will work.  I'm not sure what the best solution is.  (A bad solution is likely to work but will be MUCH more work).  I'll look over it this afternoon (next few hours) and let you know.
What i would recomend is that you create a function that you can use in the student constructor that will "extract" the student's name from the input string. This function will
take an input string that is terminated by either NUL or a ','.  It will figure out the length of the string NOT including the leading and trailing spaces.  It will allocate new memory of this length, copy the string to this memory and return a pointer to the memory.

Now I recomend that all this be done in a function, not hard coded.  Each of the string parameters in the student class (name, note, date of birth, maybe more) can be handled by this one procedure.  (look at how that will simplify the code).  What's more the same procedure can be used to make sure that the name entered by the user (to search for) also has no leading or trailing spaces.

On more thing to consider.  Often it is best to store first and last name seperately.  This is because you often want to search just by last name.  That may or may not be the best for you needs, you might want to consider it.

Let me know if you need more details.  Otherwise try this and let me know how it works.  By the way do you now understand the bug I pointed out (with the pointer after the for loops?)  And was that bug in your professor's code or did you change his/her code?
Avatar of John500

ASKER

Yes,

I understand the bug.  I have to take your word that once p reaches the last item in the doubly linked list it is not able to point to the last item's characteristics.  In the tapes, the professor drew many pictures of this list.  We were taught that when p reaches the end, the _next pointer will be zero because the last student points to nothing.  He didn't say that p would not be able to point to the last student's _prev (previous) _id, _name, _cum, _born, _note.

If I understood you correctly, your saying that once p reaches the end, p is worth ZERO.

Thanks for the help on the read routine.  I'll have to work on that tomorrow.  I'm imagining that you meant to use the "new char" statement to dynamically create memory for the calculated string length?

John




Yes, dynamically allocate memory for the strings like you are doing now.  Just do it in a procedure that also takes care of the spaces issue.  The nice thing is that it will mean that your tests to see if new fails will be in only one place.  Even though your code will be doing more, you entire program will be shorter and simler...  That's the goal.

You don't quite have the bug down yet.  Your understanding of what I said was

>> once p reaches the last item in the doubly linked list it is not
>> able to point to the last item's characteristics

not quite.  When p points to the last item, everything is fine.  It can access the last item fine.  But then you do

p = p->_next.

Now p doesn't point to the last item anynore.  Now its value is what the last item had in _next.  That is 0 or NULL.  So now p is a NUL pointer.  

Does that make sense?  This is important (you will see it again!), so if you don't have it, let me know.  (And Alexo will explain it to you <g>.)
Avatar of John500

ASKER

Todd,

In reply to your last note on the bug, I will step through the explanation you sent a few days back.

...    Say you are on the last itme in the list, that is, p point to the last item in the list.  Now, if that item doesn't
    have the name to search for, it executes the statement

    p = p->_next;

    Since the last item stored is NULL or 0 in the _next member, p will now be NULL.  Do you agree so far?  

>  Yes, as long as your not saying that p->_name is null, only p->_next is null

What happens next?  It loops back and tries

    p != 0 && strcmp(p->_name,name) != 0

however p is zero so the first part of that p != 0 is false, so the loop terminates.  Agreed?

>  yes, the loop terminates but p is still able to point to the last student and its various >characteristics as _id, _name, _age, _cum, _born, _note, _prev =(previous student), >_next= null


Now the loop has terminated with p being NULL (or zero.)  

>Yes, if you mean only p->_next is null


The program continues and executes the if statment.

    if(strcmp(p->_name,name)== 0)

    inside that if statement there is the section that does      p->_name

    do you see that?  

>yes

if p points to something that is fine.  But in this case p is NULL and therefore p->_name causes a crash.   Does that make sense?

>As I said, the instructor taught that p is able to point to all the contents of the last >student, and just because the loop terminated doesn't mean there is a problem and just >because p->_next = 0   doesn't mean  p->  _id= 0, p->_name= 0, p->_age= 0, p->_cum= 0, p->_born= 0, p->_note= 0, p->_prev= 0

The statements after the loop can still evaluate what p points to.  I'm still inclined to believe what I've stated is true because the findStudent() never gave me any problems.  My problems with searchStudent, as was proven yesterday, deal with spaces.

Let me know what you think.

John
No, you don't have it.

You've got the same problem throughout you last comment, but I'm going to target one spot and see if we can break through.  You say

 just >because p->_next = 0   doesn't mean  p-> _id= 0.

Agreed.  But if p->_next = 0 and you THEN do

p = p->_next;

p now has a new value.  That new value is what used to be in p->_next (with the old p).  This value we agreed was zero (look 3 lines up).  Thus p must now have the value 0 (also know as NULL).  That means that p no longer points to a valid object.  That is okay, that happens a lot.  You can have pointers that are invalid, however, you must never dereference an invalid pointer.  If you do you will (usually get a crash).
Does that help?  By the way I'm leaving for a trip tommorow afternoon and will be gone until Tuesday morning.  (USA central time).  Hopefully we can get this fixed before I leave.
Avatar of John500

ASKER

Todd,

Thanks for your concern on this program and the heads up on your trip.

What I feel the for loop does once p moves to the last object is the following:

(Student *p = _head; p!= 0 && strcmp(p->_name,name)!= 0; p = p -> _next);

the first condition is evaluated again,  p!=0, because this is true the loop terminates and no other statement is considered.  That means in the loop strcmp(p->_name,name)!= 0 is not considered again and p=p->_next is not considered either.  If p!=0 is true, why would any other elements of the loop be considered.

So when you say, "...But if p->_next = 0 and you THEN do  p = p->_next;...
I say p = p->_next doesn't happen.  If it does happen, is there any common text that would say this, like my on-line help that comes with Borland's Turbo C++?

Also, for my other problem, I know how to dynamically create new char space, and I know how to use strcpy, what can I use to evaluate a string so that the number of spaces will be excluded?

John


I can't teach without a blackboard!!!!

twice there you say
>> p!=0, because this is true the loop terminates
but it terminates when it is false, not true.  However, I think that was a mistake in you explanation, not in your understanding.  Right?
Step by step.

step 1:  p point to the last item.
           computer evaluates:  p!= 0 && strcmp(p->_name,name)!= 0 (in the following 2 steps) to see if the loop should run.

Step 2: Test if p is 0.  It is not because it points to the last item.  so computer tests the name in step 3.

Step 3: it tests the last item's name.  In this case it does not match, so strcmp() returns non-zero (true).  so the computer decides to execute the contents of the loop.

Step 4: There are no contents to the for loop. So the computer has a long lunch and then decides to do the next iteration expresion: p = p -> _next.

Step 5:  The computer tries to make p point to the next item.  It executes p = p->_next.  However, since p points to the last item, p->next is 0.  So this loads 0 or NULL into p.

Step 6.  We go back and see if the loop should run, that means evaluating
           p!= 0 && strcmp(p->_name,name)!= 0  again.

Step 7: this time when it gets to the p != 0, it finds that p IS 0.  So it decides the loop is over.

Step 8:  So far everything is perfect.  The code went the whole way through the list and there were no crashes.  (No name was found, but that's not necessarily a problem)  Not the computer goes on to the if after the for loop.  

Step 9: it evalues the strcmp(p->_name,name)== 0 inside the if.
But inside that expression is must dereference p.  But p is 0 so it crashes

Does that help?  If not.   (405) 844-8647.  I'm tired of typing!

About the string copying.  There probably is no existing function that is what you need.  You will have to do it yourself.  let me get you 1 or 2 suggestions and a little starting code.  
I thing the easiest way is with pointers.  But two pointers.  one points to the start of what you want to copy and the other to the end.  The idea is this.  

Set the start pointer to the start of the string.  

Do a loop (while-not for) with this pointer to skip spaces.  Basically what the loop does is if the pointer points to a space, make it point to the next character. The loo will end when you come to the start of the name (or if the name is left out, when you come to the end of the string (0) or a coma that indicates the next item on the line).

You've now go the staring pointer  the end pointer to this starting pointer.  Now execute another loop that continues until you reach the end of the string (0), a space (or a coma?)

Now you can use these two pointer to copy with memcpy().  (just like strcpy(), but you tell it how many characters to copy.)  The pointer to the string to copy is the starting pointer (not the input string).  The length to copy is the difference (subtraction) between the end pointer and the starting pointer.  You might not know this, but you cn subtract two pointers and it will return an integer that indicates the number of items that are between them.  So if you do endpointer-startpointer you will get the number of characters in the string that you want to copy.

Does that get you started?
Avatar of John500

ASKER

Wow, got it!  That is terrible on my part!

Would you believe I was thinking the &&  operator was working like the || operator.  I don't know why I put the && in there, I really wanted an either/or evaluation.  I tried the || and the program still crashed for reasons I think I understand.  This whole episode has been good.  That's one thing I won't do so easily in the future.

The other problem:
Now that I have been alerted to the spaces which preceed almost every field, I think this is the cause of a couple big problems.  The addStudent function serves to alphabetize the newly constructed students.  Is it possible that the leading white spaces mess up that alphabetizing?  Something is also prohibiting entries to be made.    

I've been looking at the scanf function to provide formatting of the input stream, are you familiar with it?

You said, "before I compile this, see if you can..." Aren't you interested at this point to see how this thing operates?  It would only be a couple of copy and paste operations to put it into your compiler,  no?  I sent the class definitions separate because they are entitled mydefs.h and included in the main file.  I was hoping you could read in that list of students I sent you so that you could see how the whole list doesn't get read in, only part.  How could this be?

John
John
you will see

if (somepointer && somepoint->something)

alot.  If the pointer is NULL, the right side of the && will not be run.  Which is good because if the pointer is NULL and it did run it would crash.  

Do leading spaces affect alphabatizing?  Yes spaces are the first (printing) character int eh ASCII sort sequence.  That is a space comes before all other prrinting character  (control characters come before that, but you aren't going to have then in a name.)  So the string " Zoo" comes before "apple" because the space before the Z.

I'm vaguely knowledgable of scanf(). I have to reread the docs on it every time.   I program in windows where we don't do console I/O (prinf(), scanf() and other text based input and output functions).  But I help lots of people who do use them.  I find that it works well for many simple needs, but fails as things get harder and then you have to do it yourself.  You could try it.

I answer these questions as my compiler (or other tools) are chugging away).  I rather not close the project I'm on and start a new projects (which takes me a while to set up) if I don't have to.

I wasn't aware that only part of the list is being read in.  it looks like that is next...
I looked over the code that reads the file.  Its got problems.  I'm not sure where to begin thoug, because I'm not sure what you are trying to accomplish.  Could you (briefly) describe to me what you are trying to do within the while loop that handles each line read?
Avatar of John500

ASKER

Todd,

I just sent the readStudent() function to you which I know works.  The one included in the whole program I sent you, has the code which I was working on to do the lower to upper.

You will see that only part of the students get read to the database instead of all of them.
As I said in the e-mail, don't forget to uncomment the readStudent() called in the main.

Don't worry about keeping that other code, I'll have something different I'm sure.

John
The data file you gave me had 83 students and it appears to read all of them.  (I printed out the count of students after reading them.)  What was your test or why do you think it is not reading them all?
Avatar of John500

ASKER

Ok,

If your able to get an acurate read on the files going in, then my Names/note function isn't working.  Type "n" after you read the files in, you shouldn't get 83 names and notes.

John
I found this much so far.  It was dying on student bobrow for me.  When I looked at bobrow's entry in the data file I noticed that there was no space before the name...  So I added a space and then it went farther and stopped on a different student. The root of the problem is the parsing of the data into your student.  I'll look at that next.
I see you haven't started the changes we discussed there.  Why don't you try creating the strings without spaces?--if you can.
Avatar of John500

ASKER

The student constructor, that which parses or dynamically creates a name field was given by the instructor.  I'm far enough ahead in the tapes to that the other students handed in the project and the Student::Student constructor was never made an issue.  My gut feeling is that the constructor is fine and that the problem does lie in the leading spaces of each field.

I have been lucky enough to spend the last two days here on the job, doing school work.  That's how much time I've put into the issue of eliminating spaces and finding a routine to do the lower to upper trick.

If I get over this one, I can assure you it will be because someone handed me the answer!
Avatar of John500

ASKER

The student constructor, that which parses or dynamically creates a name field was given by the instructor.  I'm far enough ahead in the tapes to that the other students handed in the project and the Student::Student constructor was never made an issue.  My gut feeling is that the constructor is fine and that the problem does lie in the leading spaces of each field.

I have been lucky enough to spend the last two days here on the job, doing school work.  That's how much time I've put into the issue of eliminating spaces and finding a routine to do the lower to upper trick.

If I get over this one, I can assure you it will be because someone handed me the answer!
Don't take this the wrong way, but I am serious, if you instructor gave you that constructor and/or that nasty for loop error, you should consider a different instructor.  I mean it that code is what you expect from a beginning student, that is far from tolerable from an advanced student and, well, no one who writes that code should be teaching!  If that is the way you instructor writes code, I would say he is doing you more harm than good!.  Seriously.

Anyway, I'm not sure what to tell you.  The problem is in the spaces in these field names.   The only reasonable way to fix it is to change the constuctor to do a better job.  You can make changes elsewhere to get it to work, but it is going to be much more work.  I don't have time to help tonight.  I might be able to find time tomorrow, but no promises.  If you can attempt something it will be easier for me to look over it than to have to start from scratch.  If not, others might help, but you will probably need to offer more points.  
Avatar of John500

ASKER

Todd,

How about we end this session with a different question that I'm sure can be answered easily.

I need to know how to clear the buffer for an input to any of the following functions:
delete, ages, search, find

In any of the above situations, if a correct argument (int verses char)  is passed the first time, there is no problem.  The second time, if a char is passed when an int should have been (example: k instead of ID) the function will not reject it properly.  The third time the particular menu item is selected, the user isn't even given the choice to input anything but instead the buffer holds the bad input character from the last input and returns the user to the main menu.

The instructor gave us (!_id) {cout<<"Bad entry!"; return 0;}  But this doesn't work for incorrect character inputs.  At this point I don't know if I just need to clear the buffer after every use or give the function a way to evaluate for int verses char.  Either way, I don't know how to fix the problem, I don't know of any functions that address these issues.  Therefore, I could search for two days hoping to find something that applies to my situation in the online help.  Or, you can give me the answer.  You can be sure the answer will stick in my brain.  I desire to know the answer!
I'm really not sure if C++ provides a good way to deal with this.  (I don't do the console I/O stuff.)  In C (not ++) and most languages the answer is no.  They provide procedure for reading things like dates and numbers, but no one ever uses them because they cause horrible problems if the user enters bad data.  Some even crash.  That is not good.  The tranditional way around this is to read everything as a string and then convert from a string to a number (like for age) yourself (C++ has atoi() and atof() to help with this).  If the user enters a bad value, like "ten" instead of "10", then you can detect it safely in the string.  

I'll be here a few more hours.  I will see what I can do.
Here is a start at getting a trimmed string.  I doubt it is bug free, it probably won't even compile, but it should get you started.

// char *buf pointer to string to be parsed.
char *StartPtr = Buf;
char *EndPtr;

// Skip over initial spaces.  Ends on first non-space character or the end of the string.
while (*StarPtr == ' ') // While point to a space.
   ++StartPtr;  // Skip the space.

EndPtr = StartPtr; // Begin with end at the the first non-space.

// Skip until the first space, comma, or end of string.
while (true)
{
    char ch = *EndPtr++
    if (ch == 0 || ch == ' ' || ch == ',')
      break;
}

int Len = EndPtr - StartPtr; // Length of trimmed string.
char *StrPtr = new char[Len];
// error message if new fails.
memcpy(StrPtr,StartPtr,Len);

That should be it.  Put it in a procedure and get the bugs worked out.  Then make the constructor use it.  Also use it when the user enters a name to search for.  Good luck.  I leave in 3 hours, so comment fast if you need help.
Avatar of John500

ASKER

Thanks, that should do it.  I tried twice to get a grade screen, but it wasn't coming up.  Let me know what's up so I can finish grade portion of the question.
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
Avatar of John500

ASKER

What I was most pleased with was your patience throughout.  You did offer good food for thought, but as your writeup states, you are still learning C++.  I feel a C++ programmer could have notified me of the function "isspace" quickly and then helped me to modify it so that it also did the lower to upper routine.

Thanks,
I wasn't aware of the isspace() function.  but I don't think you need it.  for your purposes you can use

char ch  = something;

if (ch == ' ')

That is what I used in my sample code.  The isspace() function is used when your program has to deal with non-ANSII text, like foreign languages.  There may be other characters in those langauges that act like a space does in our language.  It will work fin for you, but it is overkill.