1. Not finding help here? Sign up for a free 30min tutor trial with Chegg Tutors
    Dismiss Notice
Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Why isn't my for loop triggering?

  1. Jul 20, 2017 #1
    1. The problem statement, all variables and given/known data
    First of all, this ISN'T homework. This is independent study. I am in a CS program, but I am going through PPP by Bjarne Stroustrup to keep the language fresh. I'm working on one of the last assignment in chapter 4 which is this:

    Write a program where you first enter a set of name·and·value pairs,
    such as Joe 17 and Barbara 22. For each pair, add the name to a vector
    called names and the number to a vector called scores (in corresponding
    positions, so that if names[7]=="Joe" then scores[7]==17). Terminate
    input by the line No more ("more" will make the attempt to read another
    integer fail ). Check that each name is unique and terminate with an error
    message if a name is entered twice. Write out all the (name,score) pairs,
    one per line

    I know my code isn't complete but I cannot get my for loop to run. I've ran various test cases, the while-loop is working, and it completes the full iteration of the while-loop. However, my for-loop never executes. It simply skips it (that is, code within the while-loop that appears before the for-loop and after the for-loop execute during each iteration). I.E. where hello1 and hello2 appear in the code, these execute fine.

    2. Relevant equations


    3. The attempt at a solution

    I'm pretty sure it has to do with my < sign in the for loop since <= will execute the for-loop but crash the program.

    Code (C):

    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;

    int main() {
        vector<string> all_names;
        vector<int> all_scores;
     
        string names;
        int scores;
     
        while(cin>>names>>scores){
            cout << "hello1";
            for(int i = 0; i < all_names.size(); i++ ){
                if( all_names[i] == names ){
                    cout << "duplicate name.";
                }
                else{
                    all_names.push_back(names);
                    all_scores.push_back(scores);
                }
            cout << "hello2";
            }
        }
        return 0;
    }


     


    However, if I keep the < sign and re-write the for-loop like this, it works. But I'm not seeing why... Since to me this code is essentially the same, just using an unnecessary flag.
    Code (C):

    while(cin>>names>>scores){
           bool valid = true;
           for( int i = 0; i < all_names.size(); i++ ){
               if( all_names[i] == names ){
                   valid = false;
               }
           }
           if(valid){
               all_names.push_back(names);
               all_scores.push_back(scores);
           }
           else{
               cout << "duplicate name";
           }
       }
     
     
    Last edited: Jul 20, 2017
  2. jcsd
  3. Jul 20, 2017 #2

    Mark44

    Staff: Mentor

    Code (C):
    for(int i = 0; i < all_names.size(); i++ )
    In the first iteration of your loop here, all_names is empty, so all_names.size() is zero. Since 0 is not less than 0, the test expression is false and the for loop exits. If you change the comparison to <=, 0 is less than or equal to itself, the body of the for loop is executed.

    BTW, it's not considered good practice for a program to ask for input without prompting the user as to what to enter (e.g. cin >> names >> scores in your while loop. It's also better to input just a single variable at a time unless you're pulling data from a file.
     
  4. Jul 20, 2017 #3
    Thanks. I normally don't use input as the conditions of my loops, but it's what Stroustrup was doing, along with the double input.

    When I change it to <= the program crashes. I forgot to mention that. :/
     
  5. Jul 20, 2017 #4

    Mark44

    Staff: Mentor

    Here's your new version (which you added after I replied earlier)
    Code (C):
    while(cin>>names>>scores){
           bool valid = true;
           for( int i = 0; i < all_names.size(); i++ ){
               if( all_names[i] == names ){
                   valid = false;
               }
           }
           if(valid){
               all_names.push_back(names);
               all_scores.push_back(scores);
           }
           else{
               cout << "duplicate name";
           }
       }
    I don't think the valid variable is an unnecessary flag variable. The code above reads in a name and a score, and assumes that the name is valid (isn't a duplicate). The code then compares the entered name with each name in all_names. If it finds a match, the name is a duplicate, so the code sets the valid flag to false. The code adds the new name and score only if the name wasn't a duplicate.

    In your earlier code, you were comparing all_names and names when the all_names vector was undefined at the index i.
     
  6. Jul 20, 2017 #5
    I guess I'm confused how these two portions of the code vary. Why does the for loop only get executed in code B, when the code in principle looks the same as code A?

    Of course, the method of flagging it with a bool value varies, but nothing differs other than initializing 'valid' before the for-loop. That is, in my first example, it checks to see if it's a valid name by comparin. If it isn't a valid name, it skips it. If it is a valid name it inputs it. Then it should run the while-loop again.

    It seems to me that if the for-loop in code 'A' doesn't run, then neither should it in code 'B'. If you remove the bool value, and the statements within the for-loop, the code is EXACTLY the same. In both examples it appears that the vector has nothing in it at the time of the for-loop.

    Code A:
    Code (C):

        while(cin>>names>>scores){
            for(int i = 0; i < all_names.size(); i++ ){
                if( all_names[i] == names ){
                    cout << "duplicate name.";
                }
     

    Code B:
    Code (C):

    while(cin>>names>>scores){
           bool valid = true;
           for( int i = 0; i < all_names.size(); i++ ){
               if( all_names[i] == names ){
                   valid = false;
               }
     
     
  7. Jul 20, 2017 #6

    Mark44

    Staff: Mentor

    It's the rest of the while loop where the difference shows up.
     
  8. Jul 20, 2017 #7
    Those push_back statements shouldn't be inside the for loop. Only after the for loop is done and you have checked all the names in the list for a duplicate, you must add the name+score to the vectors exactly once.

    Your first program adds the name+score more than once to the list if there's more than one name not equal to the new name in the list, and doesn't add any names if the list is empty. This is a design error.

    You should have a high level description like this:

    repeat while there are still names to read
    read in a name + score
    check if the name is already in the list
    yes?
    output error
    no?
    add the name+score to the list

    If you implement this line by line the part for "check if the name is already in the list" and "add the name+score to the list" shouldn't be mixed.
    You can either use a boolean variable, or implement "check if the name is already in the list" as a function with a boolean result.
     
  9. Jul 21, 2017 #8
    The first program doesn't even enter the for-loop once, so nothing is even entering the vector at all. It skips the for-loop entirely. That's why I'm confused. I know the implementation is different. But, I don't see why one should enter the for-loop and the other doesn't when there's no difference prior to the loop. I don't see why the contents of the loop makes any difference what-so-ever if it's not even entering it. For example:

    Code (C):


    #include <iostream>
    #include <string>
    #include <vector>
    using namespace std;

    int main() {
        vector<string> all_names;
        vector<int> all_scores;

        string names;
        int scores;

        while(cin>>names>>scores){
            cout << "You're in the while-loop\n";
            if(all_names.size() == 0) {
                cout <<"all_names has 0 elements.\n";[
            }
            if(all_names.size() != 0) {
                for(string e : all_names) {
                    cout << e << endl;
                }[/B]
            }
            for(int i = 0; i < all_names.size(); i++ ){
                cout << "You're now in the for-loop";
                if( all_names[i] == names){
                    cout << "duplicate name.";
                }
                else{
                    all_names.push_back(names);
                    all_scores.push_back(scores);
                    ;
                }
            cout << "You're out of the for-loop\n";
            }
        }
        return 0;

    }
     
    This is my I/O from the code above:
    >>Name1 2
    <<You're in the while-loop
    <<all_names has 0 elements.
    >>Name1 3
    <<You're in the while-loop
    <<all_names has 0 elements.
    >>Name1 4
    <<You're in the while-loop
    <<all_names has 0 elements.

    This is running the code ONCE. Note: The edits I made were on Lines 14-17, 24, and 33.

    So based on my output, it's entering the while-loop, and runs all the lines right before the for-loop, but once it hits the for-loop it skips EVERYTHING else. Even the stuff that comes AFTER the for-loop. I don't see why it's not even ENTERING it to check the conditionals. If it's not being added to the vector, or being added to much to the vector, fine, it's something I can fix. But, it's not even reaching that part of the code. If I use the <= sign on my for-loop, it still doesn't enter the loop and the program crashes.

    Maybe you guys are explaining it plain as day, but I'm not seeing it... at all. I can see the implementation is much different, but it still doesn't make sense why it's only repeating the first part of the while-loop and skipping the rest.
     
  10. Jul 21, 2017 #9

    Mark44

    Staff: Mentor

    Are you using a debugger? If you're not, you really should be.

    Here's the relevant part of your code from post #8. I've edited it slightly, removing an extra left bracket and a closing bold tag.
    Code (C):
    while(cin>>names>>scores){
            cout << "You're in the while-loop\n";
            if(all_names.size() == 0) {
                cout <<"all_names has 0 elements.\n";
             }
            if(all_names.size() != 0) {
                for(string e : all_names) {
                    cout << e << endl;
                }
             }
            for(int i = 0; i < all_names.size(); i++ ){
                cout << "You're now in the for-loop";
                if( all_names[i] == names){
                    cout << "duplicate name.";
                }
                else{
                    all_names.push_back(names);
                    all_scores.push_back(scores);
                    ;
                }
            cout << "You're out of the for-loop\n";
            }
        }
     
    First while loop iteration, with input of Name1 and 2
    "You're in the while-loop\n" is printed.
    First if block prints "all_names has 0 elements.\n"
    Second if block does not execute.
    For loop does not execute since all_names.size() is still 0, and 0 is not less than 0.

    Second while loop iteration, with input of Name1 and 3
    "You're in the while-loop\n" is printed.
    First if block prints "all_names has 0 elements.\n"
    Second if block does not execute.
    For loop does not execute since all_names.size() is still 0, and 0 is not less than 0.

    Third while loop iteration, with input of Name1 and 4
    "You're in the while-loop\n" is printed.
    First if block prints "all_names has 0 elements.\n"
    Second if block does not execute.
    For loop does not execute since all_names.size() is still 0, and 0 is not less than 0.

    Etc.

    At no time does the name get added to the all_names vector.


    The only statement after the for loop is the return statement.

    Your indentation fooled you, but it didn't fool the compiler. The last output statement is actually the last statement in the for loop, but the way you have it indented, you apparently meant it to be just after the for loop. This is one reason I prefer to have my left and right braces aligned, rather than having the left brace on the same line is the for, if, while, etc. headers. That way it is abundantly clear exactly which code is part of a loop body or if/else body.

    One other comment:
    Code (C):
     if(all_names.size() != 0) {
                for(string e : all_names) {
                    cout << e << endl;
                }
             }
    This really should be
    Code (C):
     else {
                for(string e : all_names) {
                    cout << e << endl;
                }
             }
    all_names.size() either is or isn't equal to 0. Your if statement already checks to see if the size is 0, so you don't need to check to see if it isn't 0. Just use else, as above.
     
  11. Jul 21, 2017 #10
    I am not. Do you have one that you recommend? I use DevC++ and CLion for C++ programming.

    Oh. My. God. I think I see what you're saying now. *rolls eyes* smh. Haha.

    In code 'b', it added the name to the vector after the for-loop since it didn't trigger a flag. Similarly I could just do a conditional statement before the for-loop saying (in pseudo) if 'i' is 0, then add it to the vector, else proceed to for-loop. In terms of efficiency it seems the same since a conditional gets checked through every loop in both codes.

    This also explains why the <= is crashing since nothing will be in my vector at this time.

    Thanks for this comment. I've always included it on the first line because I felt like it made reading it flow smoother (and looked more aesthetic to me). However, I never come across blocks of code that have tripped be up like this. Initially I learned Python so indentation has always felt natural. But I can see why moving the curly brackets down would actually make it easier to read (and all this time I thought it looked ugly).

    Thanks for your patience...
     
  12. Jul 21, 2017 #11

    Mark44

    Staff: Mentor

    I've been using MSFT Visual Studio for a long time, and the Borland C++ compiler before that, so I'm not familiar with the two compilers you listed. Here's a link to something that might be helpful: https://studylib.net/doc/15537786/tutorial---debugging-in-dev-c---introduction.

    If you do a web search for "dev-c++ debugger" you'll get a lot of hits.

    I strongly recommend that you start using a debugger.
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?
Draft saved Draft deleted



Similar Discussions: Why isn't my for loop triggering?
Loading...