GIDForums  

Go Back   GIDForums > Computer Programming Forums > C++ Forum
User Name
Password
Register FAQ Members List Calendar Search Today's Posts Mark Forums Read

 
 
Thread Tools Search this Thread Rate Thread
  #1  
Old 06-Nov-2005, 16:55
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Trees and Keys (not for the faint-hearted!)


Hello All..you have always been able to get me out of the rut in times past and now I come to you again asking for a second pair of eyes to see what I am doing wrong. I am working on an assignment that reads from a .dat file and organizes elements (fake bank account information) in a tree and assigns keys to them. I have the application compiling and SOMEWHAT working..but it is only reading the first 3 items from the .dat file and saying everything after that does not exist! Most of the code was already provided and is good..so I will just post my code and then the files as an attachment if anyone wants to pick their brain with me...


first part of main.cpp
CPP / C++ / C Code:
// Read the database file and build the index
    //     While there are records in the database
    //         Read the record
    //         Insert the <account ID, record number> item in the index
    //         Increment the record number

    // TODO: Add your code to implement the algorithm here
	if (acctFile){
	  while(acctFile.good()){
        acctFile.seekg(recordNum*bytesPerRecord);
        acctFile >> acctRec.acctID >> acctRec.firstName
        >> acctRec.lastName >> acctRec.balance;

		index.insertItem(acctRec.acctID, recordNum);
		recordNum++;
	  }
	}
        else {
	cout << "File Cannot Be Opened!" << endl;
	}

second part of main.cpp
CPP / C++ / C Code:
// TODO: Add your code to implement the algorithm here
			cout << "Enter Account ID:";
			cin >> account;
            p = index.find(account);
			if(p.isNull())
			  cout << "This Account ID Does Not Exist" << endl;
			else{
			  account = p.key();
			  recordNum = p.element();
			  acctFile.seekg(recordNum*bytesPerRecord);
			  acctFile >> acctRec.acctID >> acctRec.firstName
               >> acctRec.lastName >> acctRec.balance;
		     cout << recordNum << ":" << acctRec.acctID << " " << acctRec.firstName
			  << " " << acctRec.lastName << ": $" << acctRec.balance << endl;
		}

I am attaching the .cpp and .h files in a .zip file for any gracious soul who might want to help me out! Everything else was pre-coded except for a few functions in the LinkedBinaryTree.h file which are absolutely correct (sibling, parent, and rightChild) and the Exception.h file.

Also, when I create the while loop for reading from the .dat file..when I type in acctFile. to bring up the list of functions..the "good()" function is not there although it should be inherited from iostream...not sure whats going on there either...



thanks!
dlv
Attached Files
File Type: zip HW4.zip (5.5 KB, 12 views)
  #2  
Old 06-Nov-2005, 17:51
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Trees and Keys (not for the faint-hearted!)


Quote:
Originally Posted by greymalkin
I am working on an assignment that reads from a .dat file and organizes elements (

Your data file has '\r\n' at the end of each line. I assume you are using a Microsoft compiler on a Windows system (since other compilers complain bitterly about ... but that's another thread).

My question is: why the heck do you think you need to use seek????
Just read the data and check for a fail condition on the input after each read.

1. Seeking is not reliable unless you open the file in binary mode. If you really want to do this, then realize that your record length is 38 bytes, not 37. You could use a text editor or some utility on the file to delete the carriage returns from each line, but I really, reallllllly, reallllllllllly don't think this is the way to go. This is a text file after all; I think you should use normal input and output functions and to heck with the seeking stuff. I might increase the size of the char arrays that hold input fields so that there is some chance of recovering in case someone slips in a data item that's too big. But that's another story.

2. Excuse me if you have heard this before, but why the heck do you think you need to seek? You are reading the records sequentially, starting from the beginning of the file. Just read the data. Check the state of the input stream after each read operation. (You really should check the input stream after every single read operation in every single program you write ---ever. But that's just my opinion; I'm sorry if it sounds like I am getting emotional, but there are so many crappy programs out there vulnerable to unspeakable exploits just because someone didn't check the input.)

Anyhow, when I have a new program that deals with user input (console or file), I always (always) print out input data as it comes in.

So, first of all, try this with your program and your data file exactly as you posted them. (Here, I just print out the first data field on each line, but in general, I print out everything.)


CPP / C++ / C Code:
    while(acctFile.good()){

      cout << "Seeking byte " << recordNum * bytesPerRecord << endl;

      acctFile.seekg(recordNum*bytesPerRecord);
      acctFile >> acctRec.acctID >> acctRec.firstName
      >> acctRec.lastName >> acctRec.balance;

      cout << "acctRec.acctID = " << acctRec.acctID << endl;
      if (!acctFile) {
        cout << "There is a problem with acctFile" << endl;
        break;// Or do something, maybe more drastic.
      }

      index.insertItem(acctRec.acctID, recordNum);
      recordNum++;
    }


If you want to see why I am saying this:
first try this:

CPP / C++ / C Code:
    while(acctFile.good()){

      //cout << "Seeking byte " << recordNum * bytesPerRecord << endl;
      //acctFile.seekg(recordNum*bytesPerRecord);

      acctFile >> acctRec.acctID >> acctRec.firstName
      >> acctRec.lastName >> acctRec.balance;

      cout << "acctRec.acctID = " << acctRec.acctID << endl;
      if (!acctFile) { // end of file or error? Maybe do some checks here
        //cout << "There is a problem with acctFile" << endl;
        break;
      }     

      index.insertItem(acctRec.acctID, recordNum);
      recordNum++;
    }

Note that the input test after the acctFile >> stuff is one way to quit out of the loop when you reach end-of-file. It's actually a pretty good way, I think. The while() stuff at the beginning of the loop is inadequate.


If you like what you see, then comment out the cout << statement inside the loop, and you are off to the races.

Regards,

Dave

Why do I say that, "seeking is not reliable with text files when the text files have carriage-return linefeed sequences?" Because the bytes in the file are "processed" as they are read into memory. Carriage return-newline sequences in the file are become newlines in the buffer. The seek function actually works on what is in the buffer when it decides to get more stuff from the file. So after the first buffer full, the file pointer is not pointing to the same byte in the file that the memory pointer is pointing to in memory. (How's that for fracturing the language?)
  #3  
Old 06-Nov-2005, 18:36
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: Trees and Keys (not for the faint-hearted!)


thanks for the lengthy reply! The reason i used seek is because that is the example we were given for reading data from a file by our teacher...i really don't understand the language enough to know the best route to take especially when reading from an external file..when I get stuck unfortunately I don't know a "better way" to do it . I'll try the couts and try and find out where the program is failing reading the file...

Thanks again for taking the time to look at this..

..Alright..I just removed the seekg lines and now it's loading up the entire contents of accounts.dat into the buffer..as oppossed to only the first 3 entries when the seekg lines were there! the problem, however...is that after the 3rd entry the information it loads up isn't matching with what is in the dat file...when i try to output the data it's progressively less formatted as it should be...i have no idea what is going on...
Attached Images
File Type: gif HW4-ScreenShot.gif (7.3 KB, 10 views)
  #4  
Old 06-Nov-2005, 20:14
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Trees and Keys (not for the faint-hearted!)


Quote:
Originally Posted by greymalkin
thanks for the lengthy reply! The reason i used seek is because that is the example we were given for reading data from a file by our teacher...
.
.
.
information it loads up isn't matching with what is in the dat file..

How are you printing it out? (You do realize that the insertion operator (>>) ignores leading whitspace when reading strings and numerical data, right? That's one reason why I think it's kind of silly to treat it as a binary file (using seekg) and then losing any information other than data variable values.)

I'm not looking at any other part of your program. I just want you to be sure that it's reading every bit of user input data (and not a bit more);

With your original program and data files, I made the following changes (and these only:

CPP / C++ / C Code:
  if (acctFile){
    while(acctFile.good()){
        //acctFile.seekg(recordNum*bytesPerRecord);
        acctFile >> acctRec.acctID >> acctRec.firstName
        >> acctRec.lastName >> acctRec.balance;
        if (!acctFile) {
          break;
        }
        cout << "acctRec.acctID = " << acctRec.acctID << endl;
        cout << "acctRec.firstName = " << acctRec.firstName << endl;
        cout << "acctRec.lastName = " << acctRec.lastName << endl;
        cout << "acctRec.balance = " << acctRec.balance << endl;
        cout << endl;

    index.insertItem(acctRec.acctID, recordNum);
    recordNum++;
    }

My output (using visual c++ 6){
Code:
acctRec.acctID = 6274 acctRec.firstName = James acctRec.lastName = Johnson acctRec.balance = 415.56 acctRec.acctID = 2843 acctRec.firstName = Marcus acctRec.lastName = Wilson acctRec.balance = 9217.23 acctRec.acctID = 4892 acctRec.firstName = Maureen acctRec.lastName = Albright acctRec.balance = 51462.6 acctRec.acctID = 8337 acctRec.firstName = Debra acctRec.lastName = Douglas acctRec.balance = 27.26 acctRec.acctID = 1892 acctRec.firstName = Bruce acctRec.lastName = Gold acctRec.balance = 719.32 acctRec.acctID = 9523 acctRec.firstName = John acctRec.lastName = Carlson acctRec.balance = 1496.24 acctRec.acctID = 3165 acctRec.firstName = Mary acctRec.lastName = Smith acctRec.balance = 918.26 acctRec.acctID = 3924 acctRec.firstName = Simon acctRec.lastName = Becker acctRec.balance = 386.85 acctRec.acctID = 6023 acctRec.firstName = John acctRec.lastName = Edgar acctRec.balance = 9.65 acctRec.acctID = 5290 acctRec.firstName = George acctRec.lastName = Truman acctRec.balance = 16110.7 acctRec.acctID = 8529 acctRec.firstName = Ellen acctRec.lastName = Fairchild acctRec.balance = 86.77 acctRec.acctID = 1144 acctRec.firstName = Donald acctRec.lastName = Williams acctRec.balance = 4114.26

What did you do and what did you get?

By the way, there are numerous errors of language in your program that visual c++ cheerfully accepts. It compiles the program without complaint with visual c++ (well, actually it wanted you to put "return 0" or some other return value, but leaving it as it is (just falling off of the end of the program without a return statement) actually complies with the C++ standard. I haven't tried to look at anything other than input, and that can work, as I have shown here.

Regards,

Dave
  #5  
Old 06-Nov-2005, 21:01
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: Trees and Keys (not for the faint-hearted!)


I had it cout the information in one big lump after it read all the data from accounts.dat so that when I launch the app it looks like this:

6274JamesJohnson415.562843MarcusWilson9217.234892M aureenAlbright51462.68337Debra
Douglas27.261892BruceGold719.329523JohnCarlson1496 .243165MarySmith918.263924Simo
nBecker386.856023JohnEdgar9.655290GeorgeTruman1611 0.78529EllenFairchild86.771144
DonaldWilliams4114.26Display account information? (Y/N):

The problem appears to be in Maureen Albrights record..in the actual .dat file it looks like this:

4892 Maureen Albright 51462.56

However, when read by the program it displays the balance as 51462.6
From this point on, every record is messed up...

DonaldWilliams4114.26Display account information? (Y/N): y
Enter Account ID:6274
0:6274 James Johnson: $415.56
Display account information? (Y/N): y
Enter Account ID:2843
1:2843 Marcus Wilson: $9217.23
Display account information? (Y/N): y
Enter Account ID:4892
2:4892 Maureen Albright: $51462.6
Display account information? (Y/N): y
Enter Account ID:8337
3:6 8337 Debra: $51462.6
Display account information? (Y/N): y
Enter Account ID:1892
4:26 1892 Bruce: $51462.6
Display account information? (Y/N): y
Enter Account ID:9523
5:26 : $51462.6
Display account information? (Y/N):

It starts shifting the information and putting it in different categories and the balance stays the same...after the program reads the albright record incorrectly it just creates a domino effect after that...

I just removed the Albright Entry from the list and every entry is working as it should....even using seekg it works properly and sees every record...

Again, I don't know why I've been asked to use seekg..i'm just doing what I was instructed because I don't know any other way..I am a tiny grasshoppa! I was able to hang with it for stacks, queues, and doubly linked lists (introducing positions)..but i'm sad to say i'm at a loss on this one...

This is the example file our teacher gave us:

CPP / C++ / C Code:
// ReadRecordSample.cpp
// Retrieves a record from an accounts database file.

#include <iostream>
#include <fstream>
using namespace std;

//--------------------------------------------------------------------
//
// Declarations specifying the accounts database
//
//--------------------------------------------------------------------
const int nameLength      = 11;   // Maximum number of characters in
                                  //   a name
const long bytesPerRecord = 37;   // Number of bytes used to store
                                  //   each record in the accounts
                                  //   database file

struct AccountRecord {
    int acctID;                   // Account identifier
    char firstName[nameLength],   // Name of account holder
         lastName[nameLength];
    double balance;               // Account balance
};

//--------------------------------------------------------------------

int main(){
    ifstream acctFile ("accounts.dat");   // Accounts database file
    AccountRecord acctRec;                // Account record
    long recNum;                          // User input record number

    //Get the record number to retrieve
    cout << "\nEnter record number: ";
    cin >> recNum;

    //Move to the corresponding record in the database file using seekg()
    acctFile.seekg(recNum*bytesPerRecord);

    //Read in the record
    acctFile >> acctRec.acctID >> acctRec.firstName
             >> acctRec.lastName >> acctRec.balance;

    //Display the record
    cout << recNum << " : " << acctRec.acctID << " "
         << acctRec.firstName << " " << acctRec.lastName << " "
         << acctRec.balance << endl;
}

I understand it may be sloppy and perhaps not the right way to do it and maybe it's making it excessively difficult..but thats the way we were shown to do it...

ACK!

I just deleted and re-downloaded the .dat file and it's working now! I suppose opening the file changed it somehow...bizarre!
  #6  
Old 06-Nov-2005, 22:22
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Trees and Keys (not for the faint-hearted!)


Quote:
Originally Posted by greymalkin
4892 Maureen Albright 51462.56

However, when read by the program it displays the balance as 51462.6


Default is for cout<< to print six significant digits (and it rounds off after that).

You can use settings from <iomanip> to change the format of the output:

CPP / C++ / C Code:
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
  double x;

  cout << "Using default precision (six significant digits):" << endl;
  x = 12.34;
  cout << "  x = " << x << endl;

  x = 123.45;
  cout << "  x = " << x << endl;

  x = 1234.56;
  cout << "  x = " << x << endl;

  x = 12345.67;
  cout << "  x = " << x << endl;

  x = 123456.78;
  cout << "  x = " << x << endl;

  x = 1234567.89;
  cout << "  x = " << x << endl << endl;

  cout << "After setting precision for 10 significant digits:" << endl;
  cout << setprecision(10);

  x = 12.34;
  cout << "  x = " << x << endl;

  x = 123.45;
  cout << "  x = " << x << endl;

  x = 1234.56;
  cout << "  x = " << x << endl;

  x = 12345.67;
  cout << "  x = " << x << endl;

  x = 123456.78;
  cout << "  x = " << x << endl;

  x = 1234567.89;
  cout << "  x = " << x << endl;

  return 0;
}

Code:
Using default precision (six significant digits): x = 12.34 x = 123.45 x = 1234.56 x = 12345.7 x = 123457 x = 1.23457e+06 After setting precision for 10 significant digits: x = 12.34 x = 123.45 x = 1234.56 x = 12345.67 x = 123456.78 x = 1234567.89

Opening a file for reading (which is all that you can do with an ifstream) will not change its contents.


Regards,

Dave
  #7  
Old 06-Nov-2005, 22:40
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Trees and Keys (not for the faint-hearted!)


Quote:
Originally Posted by greymalkin

DonaldWilliams4114.26Display account information? (Y/N): y
Enter Account ID:6274
0:6274 James Johnson: $415.56
Display account information? (Y/N): y
Enter Account ID:2843
1:2843 Marcus Wilson: $9217.23
Display account information? (Y/N): y
Enter Account ID:4892
2:4892 Maureen Albright: $51462.6
Display account information? (Y/N): y
Enter Account ID:8337
3:6 8337 Debra: $51462.6
Display account information? (Y/N): y
Enter Account ID:1892
4:26 1892 Bruce: $51462.6
Display account information? (Y/N): y
Enter Account ID:9523
5:26 : $51462.6
Display account information? (Y/N):

It starts shifting the information and putting it in different categories and the balance stays the same...after the program reads the albright record incorrectly it just creates a domino effect after that...

OK, OK, I see why you need to use seekg. But ya gotta use it right, right?

I have told you how to use seekg for this data file (since the data file has \r\n at the end of each line). I have told you why. Seekg is only reliable for binary files on Windows systems, since text files result in having different byte positions in memory than are in the files. If you open a text file (with \r\n line terminations) in binary mode, the \r and \n end up in memory (the buffer) and the total line length for seekg purposes includes both characters. Each line in your data file (the one that I unzipped after downloading from your post) has 36 characters plus '\r' plus '\n'; therefore bytesPerRecord is 38.

Open the file in binary mode and change the bytesPerRecord to 38. (And don't forget setprecision(10) or some such thing.)


Here's the result, with seekg back in place:

CPP / C++ / C Code:
const long bytesPerRecord = 38; 
.
.
.
    ifstream acctFile ("accounts.dat", ios::bin);
.
.
.
  if (acctFile){
    while(acctFile.good()){
        acctFile.seekg(recordNum*bytesPerRecord);
        acctFile >> acctRec.acctID >> acctRec.firstName
        >> acctRec.lastName >> acctRec.balance;
        if (!acctFile) {
          break;
        }
        cout << setprecision(10);
        cout << "acctRec.acctID = " << acctRec.acctID << endl;
        cout << "acctRec.firstName = " << acctRec.firstName << endl;
        cout << "acctRec.lastName = " << acctRec.lastName << endl;
        cout << "acctRec.balance = " << acctRec.balance << endl;
        cout << endl;

    index.insertItem(acctRec.acctID, recordNum);
    recordNum++;
    }
  }
.
.
.

Code:
acctRec.acctID = 6274 acctRec.firstName = James acctRec.lastName = Johnson acctRec.balance = 415.56 acctRec.acctID = 2843 acctRec.firstName = Marcus acctRec.lastName = Wilson acctRec.balance = 9217.23 acctRec.acctID = 4892 acctRec.firstName = Maureen acctRec.lastName = Albright acctRec.balance = 51462.56 acctRec.acctID = 8337 acctRec.firstName = Debra acctRec.lastName = Douglas acctRec.balance = 27.26 acctRec.acctID = 1892 acctRec.firstName = Bruce acctRec.lastName = Gold acctRec.balance = 719.32 acctRec.acctID = 9523 acctRec.firstName = John acctRec.lastName = Carlson acctRec.balance = 1496.24 acctRec.acctID = 3165 acctRec.firstName = Mary acctRec.lastName = Smith acctRec.balance = 918.26 acctRec.acctID = 3924 acctRec.firstName = Simon acctRec.lastName = Becker acctRec.balance = 386.85 acctRec.acctID = 6023 acctRec.firstName = John acctRec.lastName = Edgar acctRec.balance = 9.65 acctRec.acctID = 5290 acctRec.firstName = George acctRec.lastName = Truman acctRec.balance = 16110.68 acctRec.acctID = 8529 acctRec.firstName = Ellen acctRec.lastName = Fairchild acctRec.balance = 86.77 acctRec.acctID = 1144 acctRec.firstName = Donald acctRec.lastName = Williams acctRec.balance = 4114.26 Display account information? (Y/N): y Enter Account ID:1144 11:1144 Donald Williams: $4114.26 Display account information? (Y/N): y Enter Account ID:8529 10:8529 Ellen Fairchild: $86.77 Display account information? (Y/N): y Enter Account ID:5290 9:5290 George Truman: $16110.68 Display account information? (Y/N): y Enter Account ID:4892 2:4892 Maureen Albright: $51462.56

Of course, after you have finished testing, you can remove the "cout<<" statements that show the records as they are being read in (if you want to, that is).

Regards,

Dave
  #8  
Old 07-Nov-2005, 07:54
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: Trees and Keys (not for the faint-hearted!)


that is fantastic! I knew how to use the setprecision and other iomanip features, but my next question would have been "what good will setprecision(10) do if the program isn't capturing the last character???"..but you answered that as well! I know you were asking me to open the file in binary mode but I simply didn't know how to do it..I suppose that ios::bin takes care of that! I tried bumping up the buffer to 38 as you said previously but it still truncated the long balance entries when inputting it into the buffer..so i'm guessing the ios::bin is what takes care of that...

thanks for being so patient with me..i know it's frustrating explaining these things to a novice ..i'll #include<iomanip>, use setprecision(10), and use the ios::bin on the ifstream(accounts) and that should take care of me!

Then I just need to put try/catch blocks around areas that may throw exceptions and I'll ALMOST be done...theres another anomaly in the program I'd like to shore up that I'm not quite sure how to do...

code fragment needing to be modified:
CPP / C++ / C Code:
// TODO: Add your code to implement the algorithm here
cout << "Enter Account ID:";
cin >> account;
p = index.find(account);
   if(p.isNull())  // wanting to modify this line to block alpha characters
     cout << "This Account ID Does Not Exist" << endl;
   else{
     account = p.key();
     recordNum = p.element();
     acctFile.seekg(recordNum*bytesPerRecord);
     acctFile >> acctRec.acctID >> acctRec.firstName
      >> acctRec.lastName >> acctRec.balance;

     cout << recordNum << ":" << acctRec.acctID << " " << acctRec.firstName
     << " " << acctRec.lastName << ": $" << acctRec.balance << endl;
		}


when I get prompted to Enter the account ID and enter a numeric value that is not one of the account numbers, the find function obviously doesn't find it and apparently therefore p is Null and i get the appropriate message "This Account ID Does Not Exist"..
HOWEVER! If I'm buzzing along and accidentally insert an alpha character (such as 'y' or 'n' when i'm supposed to enter a number, the program goes into an endless loop saying the Account ID Does Not Exist. I need to put an OR clause in the if statement that says if (p.isNull() || ???)..i tried loading account into a string named accountTest right after the cin >> account line, then using if(p.isNull() || isalpha(accountTest)) ...but the program didn't like that...i think that is my last hurdle..

thanks for everything you've helped me with so far!
  #9  
Old 07-Nov-2005, 08:47
davekw7x davekw7x is offline
Outstanding Member
 
Join Date: Feb 2004
Location: Left Coast, USA
Posts: 4,703
davekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to beholddavekw7x is a splendid one to behold

Re: Trees and Keys (not for the faint-hearted!)


Quote:
Originally Posted by greymalkin

when I get prompted to Enter the account ID and enter a numeric value that is not one of the account numbers, the find function obviously doesn't find it and apparently therefore p is Null and i get the appropriate message "This Account ID Does Not Exist"..
HOWEVER! If I'm buzzing along and accidentally insert an alpha character (such as 'y' or 'n' when i'm supposed to enter a number, the program goes into an endless loop

This is one of those things that, if someone told you about it before you wrote your program, you might not "get it". Now, I think you are ready to get it.

When you use cin>> to read a numerical quantity, here's what happens when the user enters something:

The program ignores any leading white space and starts getting numerical characters ('0'-'9', maybe a '.' if it's a float or double) and stops whenever it sees something that can't be part of a number (whitespace, alpha char, etc.)

Now, if the very first thing it sees can't be part of a number (like when you enter a 'y', for example), then --- and this is the crux of the matter--- cin enters what is known as the "fail" state. When cin is in the "fail" state, you can do nothing else (nothing) until you clear it. For file io instead of cin, the answer is the same: you can close the file or you can clear it. If you don't clear it, you can't use it for anything else (anything). How do you clear it? There is a member function called clear() for istream objects like cin.

Also note that the clear() function lets you do more with cin (or with your ifstream), but "clear" means that it resets the state to "good"; it does not empty out the input buffer, so whatever stuff was in there is still there.

So recovery is a two-step process: clear() the stream and then empty the stream buffer --- in that order. Or you could read it into a string so that you can tell the user what he did wrong--- but I'll leave that up to you.

Here's an example with cin:

CPP / C++ / C Code:
#include <iostream>

using namespace std;

int main()
{
  double x;

  while (1) {
    cout << "Enter an integer or floating point number (-1 to quit):  ";
    cin >> x;
    if (!cin) {
      cin.clear(); // You must do this before you do anything else with cin

      while (cin.get() != '\n') // now empty the stream input buffer
        ;                       // an "empty loop"

      cout << "Illegal entry." << endl << endl; // you could be more polite?
    }
    else if (x == -1.0) {
      break;
    }
    else {
      cout << "You entered " << x << endl << endl;
    }
  }
  cout << endl << "Bye for now. It's been fun." << endl;
  return 0;
}

Here's a run. (Comment out the clear() line and see what happens.)

Code:
Enter an integer or floating point number (-1 to quit): 12.3 You entered 12.3 Enter an integer or floating point number (-1 to quit): -99.12566666 You entered -99.1257 Enter an integer or floating point number (-1 to quit): y Illegal entry. Enter an integer or floating point number (-1 to quit): 33 You entered 33 Enter an integer or floating point number (-1 to quit): -1 Bye for now. It's been fun.

Bottom line: whenever you use ">>" to read a numerical quantity from cin or any other ifstream, always (always) test the state after the ">>".

Regards,

Dave
  #10  
Old 07-Nov-2005, 21:01
greymalkin greymalkin is offline
New Member
 
Join Date: Oct 2005
Location: near Houston, TX
Posts: 10
greymalkin is on a distinguished road

Re: Trees and Keys (not for the faint-hearted!)


alright..i got the alpha characters problem taken care of..but when i try to compile using ios::bin it doesn't like that at all. I assume that is how i open the file in binary mode?

This is the error message I receive:
error C2039: 'bin' : is not a member of 'std::basic_ios<_Elem,_Traits>

man..this assigment was supposed to just be about using trees and it ended up being a battle for getting the input/output!
 
 

Recent GIDBlogHalfway done! by crystalattice

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Rate This Thread
Rate This Thread:

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Forum Jump

Network Sites: GIDNetwork · GIDWebHosts · GIDSearch · Learning Journal by J de Silva, The

All times are GMT -6. The time now is 21:15.


vBulletin, Copyright © 2000 - 2008, Jelsoft Enterprises Ltd.