Thread: While loop with variable problem

  1. #1
    Registered User
    Join Date
    Apr 2008
    Posts
    122

    While loop with variable problem

    Okay, so I am making a project where a user inputs a different variable to change, delete, print, or add to an array. When they type a q, the program quits. My problem is that when they type two of the same character (say p then another p after the if executes) the array does not print out the second, third.....billionth time. What is the issue here? (I haven't added any other selections yet because I still need to figure out the algorithms for those.)

    Code:
        cout << "Please enter a selection. \nTo print the array, type P.\n";
        cout << "To change a test score in the array, type C.\n";
        cout << "To add a student to the array, type A.\n";
        cout << "To delete a student from the array, type D.\n";
        cout << "To quit, type Q. \nPlease enter selection now: ";
        cin >> selection;
       
    while (selection != 'q' || selection != 'Q')
    {
          
        if (selection == 'p' || selection == 'P')
        {
        cout << setw(8) << "Name" << setw(15) << "ID" << setw(20) << "Score\n\n";
    
        for (counter = 0; inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score; counter++)
        {
             cout << setw(8) << studentList[counter].Name <<  "\t";
             cout << setw(8) << studentList[counter].ID << "\t";
             cout << setw(8) << studentList[counter].score << "\t" << endl;
             }
             }
    
        cout << "Please enter a selection. \nTo print the array, type P.\n";
        cout << "To change a test score in the array, type C.\n";
        cout << "To add a student to the array, type A.\n";
        cout << "To delete a student from the array, type D.\n";
        cout << "To quit, type Q. \nPlease enter selection now: ";
        cin >> selection;
    
    }

  2. #2
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Code:
        for (counter = 0; inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score; counter++)
        {
             cout << setw(8) << studentList[counter].Name <<  "\t";
             cout << setw(8) << studentList[counter].ID << "\t";
             cout << setw(8) << studentList[counter].score << "\t" << endl;
             }
    Seems to me that you're reading from the file inFile here. That will probably only work once, and then you'll get to the end of the file or something that's an invalid ID or whatever.

    Therefore, the first time you execute this loop, it will read in data from the file, and print it out at the same time. All subsequent executions will result in nothing happening, unless you rewind the file.

    I think you probably didn't mean to have the inFile>> code in that loop, since 'p' is supposed to print the data.
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Once you have read the file, your second loop will encounter a end-of-file immediately.

    There are three (make that at least five) approaches you can take:
    1. Load the entire file up-front, before you even ask the user what they want to do.
    2. Load data on demand, so whenever you need the data from the file, you check if it's been loaded, and if not, read in the entire file then.
    3. Read the file each time it's needed, opening and closing the file before/after the read-loop.
    4. use fstream::reset() to reset the end-of-file situation and fstream::seekg() to set the file-pointer (where you are next going to read from in the file) to the start of the file.
    5. Use mmap/MapViewOfFile to map the file into memory, and use pointer arithmetics to get the data.

    I would probably recommend #1, based on your early-stage of learning. It's pretty simple method, it solves/avoids nearly all the potential problems with any of the other solutions with little effort. The only drawback is if the list of students is REALLY huge, and it takes a long time to load them, and the user didn't need to do anything with the students - but that would be the rare variant, don't you think.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Registered User
    Join Date
    Apr 2008
    Posts
    122
    To load the file upfront at the beginning of the program I used the following function with a for loop to initialize the data:

    Code:
    void initialize (ifstream& inFile, studentType list[], int listSize)
    {
        int counter;
    
        for (counter = 0; counter < listSize; counter++)
        {
             inFile >> list[counter].Name >> list[counter].ID >> list[counter].score;
             }
    }
    With this at the top of the file after the struct:

    Code:
    void initialize (ifstream& inFile, studentType list[], int listSize)
    And this within the if where the selection == 'p' or 'P':

    Code:
    initialize (inFile, studentList, listSize)
    Is this correct?

  5. #5
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Yes, except you probably want to add to the loop-condition that you successfully read a line of data [unless listsize is a known value that indicate exactly how much data is in the file, rather than the MAX size of the list].

    And I recommend that you call initialize() _BEFORE_ you ask what the user wants to do.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  6. #6
    Registered User
    Join Date
    Apr 2008
    Posts
    122
    What loop condition is that?

  7. #7
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Well, what you had originally would do.
    Code:
        for (counter = 0; inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score; counter++)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  8. #8
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Code:
        for (counter = 0; counter < listSize; counter++)
        {
             inFile >> list[counter].Name >> list[counter].ID >> list[counter].score;
             }
    The one in red - but like skinning cats, there's many different ways to make read-loops.

    My point is that if listSize is, say, 500, and you only have 30 items in the file, then reading "nothing" 469 times when you could have bailed out after the 31st time seems a bit sub-optimal - and whilst optimizing code prematurely is a bad thing, writing pessimal code is also a bad thing.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  9. #9
    Registered User
    Join Date
    Apr 2008
    Posts
    122
    Yeah, the file size varies because we have to use two separate files that have different numbers of students. I still don't know how to make it stop reading at the end of the file. Sorry but I am JUST starting to learn C++ and am having a lot of difficulty understanding some concepts.

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by Todd88 View Post
    Yeah, the file size varies because we have to use two separate files that have different numbers of students. I still don't know how to make it stop reading at the end of the file. Sorry but I am JUST starting to learn C++ and am having a lot of difficulty understanding some concepts.
    dwks gave the answer. Of course, unless you are 100% sure that the content will ALWAYS be smaller than listSize, you should ALSO make sure you don't exceed listSize.

    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    . . . so the condition you probably want is something like this:
    Code:
        for (counter = 0; counter < listSize && inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score; counter++)
    The first condition makes sure you don't overrun your array studentList. After all, the file could have more data than your array can hold, which would be a problem if you didn't have this condition. (matsp explained this above.)

    The second condition requires a little bit of explanation. When you read data from an istream, with cin>> or inFile>> or whatever, it evaluates to the file stream itself, or to NULL if an error was encountered. It's a good thing that it evaluates to the stream itself -- this way, you can chain several reads to occur at once, with inFile>>this>>that and so on.

    When it evaluates to NULL, you have an error. Perhaps the end of the file; perhaps you tried to read a number and all it found was "abc". Regardless, in this case, you just want to stop reading. This condition evaluates to NULL and breaks the loop when an error is encountered.

    The second condition is just like this.
    Code:
        for (counter = 0; (inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score) != NULL; counter++)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

  12. #12
    Registered User
    Join Date
    Apr 2008
    Posts
    122
    Okay so I figure everything initializes properly but I am having trouble printing it all out. I used the following for loop but I'm not sure as to what to put for the conditions.

    Code:
    void printIt (studentType list[])
    {
        int counter;
         
        cout << setw(8) << "Name" << setw(15) << "ID" << setw(20) << "Score\n\n";
    
        for (counter = 0; (don't know what to put here); counter++)
        {
             cout << setw(8) << list[counter].Name <<  "\t";
             cout << setw(8) << list[counter].ID << "\t";
             cout << setw(8) << list[counter].score << "\t" << endl;
             }
    }
    Last edited by Todd88; 04-05-2008 at 04:40 PM.

  13. #13
    and the Hat of Guessing tabstop's Avatar
    Join Date
    Nov 2007
    Posts
    14,336
    You need to know how many students you have -- perhaps you should pass that around too.

  14. #14
    Registered User
    Join Date
    Apr 2008
    Posts
    122
    It's a different number of students according to the file that the user wants to use.

  15. #15
    Frequently Quite Prolix dwks's Avatar
    Join Date
    Apr 2005
    Location
    Canada
    Posts
    8,057
    Well then, after you use a loop like this to initialize the array,
    Code:
        for (counter = 0; counter < listSize && inFile >> studentList[counter].Name
                                 >> studentList[counter].ID
                                 >> studentList[counter].score; counter++)
    take note of the value of counter after the loop has finished executing. studentList[counter-1] will be the last element (assuming some were read at all). If you pass counter to other functions, you can use it for the "(don't know what to put here)". Like so.
    Code:
    for(c = 0; c < counter; c ++)
    dwk

    Seek and ye shall find. quaere et invenies.

    "Simplicity does not precede complexity, but follows it." -- Alan Perlis
    "Testing can only prove the presence of bugs, not their absence." -- Edsger Dijkstra
    "The only real mistake is the one from which we learn nothing." -- John Powell


    Other boards: DaniWeb, TPS
    Unofficial Wiki FAQ: cpwiki.sf.net

    My website: http://dwks.theprogrammingsite.com/
    Projects: codeform, xuni, atlantis, nort, etc.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. weired problem in while loop
    By avisik in forum C Programming
    Replies: 14
    Last Post: 12-01-2008, 01:41 PM
  2. Problem with a loop
    By wiggsfly in forum C Programming
    Replies: 5
    Last Post: 11-30-2008, 12:45 PM
  3. Problem with for loop
    By irsmart in forum C++ Programming
    Replies: 3
    Last Post: 09-29-2006, 04:26 PM
  4. having problem with string statement during a loop!
    By Hp7130p in forum C++ Programming
    Replies: 5
    Last Post: 04-21-2005, 09:40 AM
  5. While loop problem
    By nadkingcole in forum C Programming
    Replies: 2
    Last Post: 05-09-2002, 06:14 AM