Menu

Loop Question

TrakerJon
2008-10-25
2012-09-26
  • TrakerJon

    TrakerJon - 2008-10-25

    I'm having problems within a for loop getting the loop to continue where it left off after an invalid entry. This is what the output should look like:

    This program calculates the average of as many grades you wish to enter.

    First, enter the number of grades to process: 4

    Now enter the 4 grades to be averaged.

    Enter grade #1: 90
    Enter grade #2: 80
    Enter grade # 3: -20
    *** Invalid entry. Grade must be 0 to 100. ***
    Enter grade #3: 25
    Enter grade #4: 54

    The average of the 4 grades entered is 62

    You have a letter grade of F

    This is what I have so far...I'm guessing I need to use "continue" after the if else statements but I'm not sure about the placement or what additional entries I need to make it work...this is what I have so far (this is homework and your guidance is greatly appreciated).

     /* This program calculates the average of as many grades entered.*/
    

    include <stdio.h>

    int main(void)

    {
    / declare variables. /

    int numOfGrades, i, grade;
    int gradeTotal = 0;
    int gradeAvg;
    
    /* Comment about the function of the program. */
    
    printf (&quot;\nThis program calculates the average of as many grades you wish to enter.\n&quot;);
    
    /* Prompt user for number of grades to process. */
    
    printf (&quot;\nFirst, enter the number of grades to process: &quot;);
    scanf (&quot;%i&quot;, &amp;numOfGrades);
    fflush(stdin);
    
    /* Prompt user for the number of grades to be averaged. */
    
    printf (&quot;\nNow enter the %i grades to be averaged.\n&quot;, numOfGrades);
    
    /* Define loop, calculate average for total number of grades */
    
    for ( i = 1; i &lt;= numOfGrades; ++i )
    
        {
    
        /* Prompt user for grades. */
    
        printf (&quot;\nEnter grade #%i: &quot;, i);
        scanf (&quot;%i&quot;, &amp;grade);
        fflush(stdin);
    
        /* Display error message when entry is less than 0 or more than 100 */
    
        if ( grade &lt; 0 )
           printf (&quot;*** Invalid entry. Grade must be 0 to 100. ***\n&quot;);
        else
        if ( grade &gt; 100 )
           printf (&quot;*** Invalid entry. Grade must be 0 to 100. ***\n&quot;);
    
        gradeTotal = gradeTotal + grade;
    
        }   /* End for loop*/
    
    gradeAvg = gradeTotal /numOfGrades;
    
    /* Display the overall average of the grades entered. */
    
    printf (&quot;\nThe average of the %i grades entered is %i\n&quot;, numOfGrades, gradeAvg);
    
    /* Display the letter grade based on the average and grading standards. */
    
    if ( gradeAvg &gt;= 90 &amp;&amp; gradeAvg &lt;= 100 )
       printf (&quot;\nYou have a letter grade of A\n&quot;);
    else
    if ( gradeAvg &gt;= 80 &amp;&amp; gradeAvg &lt;= 89 )
       printf (&quot;\nYou have a letter grade of B\n&quot;);
    else
    if ( gradeAvg &gt;= 70 &amp;&amp; gradeAvg &lt;= 79 )
       printf (&quot;\nYou have a letter grade of C\n&quot;);
    else
    if ( gradeAvg &gt;= 60 &amp;&amp; gradeAvg &lt;= 69 )
       printf (&quot;\nYou have a letter grade of D\n&quot;);
    else
    if ( gradeAvg &lt; 60 )
       printf (&quot;\nYou have a letter grade of F\n&quot;);
    
    getchar( );
    

    } / End main /

     
    • cpns

      cpns - 2008-10-26

      > you still need to get each score (the outer loop) until
      > it is valid (the inner loop). That is how you need to be thinking.

      To clarify that point, when describing requirements, you might put it like that in English (or your native language), the assignment may say that, and you should be able to identify phrases such as "get each" and "until it is valid" as directly mapping to programming constructs; then you are thinking like a programmer.

      Clifford

       
    • TrakerJon

      TrakerJon - 2008-10-25

      I figured out continue is not what I'm looking for and a trap is closer to the mark but I'm still at a loss for how to define it. I cleaned up the if statement in the loop. This is what I have so far...how do I get the program to prompt me again for the #3 grade when an invalid entry is made?

       /* This program calculates the average of as many grades entered.*/
      

      include <stdio.h>

      int main(void)

      {
      / declare variables. /

      int numOfGrades, i, grade;
      int gradeTotal = 0;
      int gradeAvg;
      
      /* Comment about the function of the program. */
      
      printf (&quot;\nThis program calculates the average of as many grades you wish to enter.\n&quot;);
      
      /* Prompt user for number of grades to process. */
      
      printf (&quot;\nFirst, enter the number of grades to process: &quot;);
      scanf (&quot;%i&quot;, &amp;numOfGrades);
      fflush(stdin);
      
      /* Prompt user for the number of grades to be averaged. */
      
      printf (&quot;\nNow enter the %i grades to be averaged.\n&quot;, numOfGrades);
      
      /* Define loop, calculate average for total number of grades */
      
      for ( i = 1; i &lt;= numOfGrades; ++i )
      
          {
      
          /* Prompt user for grades. */
      
          printf (&quot;\nEnter grade #%i: &quot;, i);
          scanf (&quot;%i&quot;, &amp;grade);
          fflush(stdin);
      
          /* Display error message when entry is less than 0 or more than 100 */
      
          if ( grade &lt; 0 || grade &gt; 100 )
             printf (&quot;*** Invalid entry. Grade must be 0 to 100. ***\n&quot;);
      
          gradeTotal = gradeTotal + grade;
      
          }   /* End for loop*/
      
      gradeAvg = gradeTotal /numOfGrades;
      
      /* Display the overall average of the grades entered. */
      
      printf (&quot;\nThe average of the %i grades entered is %i\n&quot;, numOfGrades, gradeAvg);
      
      /* Display the letter grade based on the average and grading standards. */
      
      if ( gradeAvg &gt;= 90 &amp;&amp; gradeAvg &lt;= 100 )
         printf (&quot;\nYou have a letter grade of A\n&quot;);
      else
      if ( gradeAvg &gt;= 80 &amp;&amp; gradeAvg &lt;= 89 )
         printf (&quot;\nYou have a letter grade of B\n&quot;);
      else
      if ( gradeAvg &gt;= 70 &amp;&amp; gradeAvg &lt;= 79 )
         printf (&quot;\nYou have a letter grade of C\n&quot;);
      else
      if ( gradeAvg &gt;= 64 &amp;&amp; gradeAvg &lt;= 69 )
         printf (&quot;\nYou have a letter grade of D\n&quot;);
      else
      if ( gradeAvg &lt; 64 )
         printf (&quot;\nYou have a letter grade of F\n&quot;);
      
      getchar( );
      

      } / End main /

       
    • cpns

      cpns - 2008-10-26

      Goog for you for being honest about it being homework. You of course realise that we need to be careful about how much help we can give.

      Think clearly (like a programmer ;-) ): What you are trying to do is "do something until it is right". Now C does not have a do-until construct, so switch it around: "do something while it is still wrong"

          do
          {
              /* Prompt user for grades. */
      

      ...

              /* Display error message when entry is less than 0 or more than 100 */
      

      ...
      } while( grade < 0 || grade > 100 ) ;

      Want perhaps a few extra marks? Consider you if/else if/else construct at the end. You can make the conditions far simpler if you reverse the order of the tests - starting from F. Only the first matching condition is executed, so you only then need to test the upper bound in each case because the lower bounds would have been trapped by a preceeding condition. Also it is simpler (visually at least) to test the bound in such a way as to use < rather than <=:

      if( gradeAvg &lt; 64 )
      {
          ...
      }
      else if( gradeAvg &lt; 70 )
      {
          ...
      }
      else if ...
      

      Of course you need not reverse it you could test the lower bounds

      if( gradeAvg &gt; 89 )
      {
          ...
      }
      else if( gradeAvg &gt; 79 )
      {
          ...
      }
      else if ...
      

      Note that you never need to test for >100 because you validated the inputs in the first instance. Also you never need a test to the final condition because if it gets that far, it must be true, so that can (and should) be just a plain else not an "else if".

      Some style points you may take or leave:

      1) Don't place a blank line between a comment and the block the comment refers to. They should be tightly coupled.

      2) Always use {...} around a conditional block even if it is a single line. It is easier to read and maintain (i.e. you may later add more code to the block) and is less error prone. Less importantly perhaps when you post the code here and the forum removes all your indenting, it is easier to distinguish.

      3) Conventionally in if/else if/else constructs the "else if" is placed on one line, and the subsequent block is not indented. Although it is in fact syntactically a series of nested if/else constructs, it is generally considered a different construct and laid out accordingly. For example, I reformatted your code in VC++ using its auto-format and it laid the code out with increasing indentation, placing the if and the else together causes it to us a more conventional vertical layout even though it is syntactically identical.

      On the whole however, nice job - the code you posted compiled cleanly and executed without error.

      Clifford

       
    • TrakerJon

      TrakerJon - 2008-10-26

      I think I follow you on the do loop but I'm missing the mark a little...is the do loop within the for loop or instead of the for loop?

       
    • TrakerJon

      TrakerJon - 2008-10-26

      Hey Clifford,

      Thank you for the quick reply, after some effort back at the drawing board I think I'm close but the grade average calculation is incorrect (13 instead of 62?) and I don't see where I funked it up...here's what I have now (I'll definitely work on the style after the do =):

       /* This program calculates the average of as many grades entered.*/
      

      include <stdio.h>

      int main(void)

      {
      / declare variables. /

      int numOfGrades, i, grade;
      int gradeTotal = 0;
      int gradeAvg;
      
      /* Comment about the function of the program. */
      
      printf (&quot;\nThis program calculates the average of as many grades you wish to enter.\n&quot;);
      
      /* Prompt user for number of grades to process. */
      
      printf (&quot;\nFirst, enter the number of grades to process: &quot;);
      scanf (&quot;%i&quot;, &amp;numOfGrades);
      fflush(stdin);
      
      for ( i = 1; i &lt;= numOfGrades; ++i )
      
         do
         {
      
          /* Prompt user for grades. */
      
          printf (&quot;\nEnter grade #%i: &quot;, i);
          scanf (&quot;%i&quot;, &amp;grade);
          fflush(stdin);
      
          /* Display error message when entry is less than 0 or more than 100 */
      
          if ( grade &lt; 0 || grade &gt; 100 )
             printf (&quot;*** Invalid entry. Grade must be 0 to 100. ***\n&quot;);
      
          } while ( grade &lt; 0 || grade &gt; 100 );
      
      gradeTotal = gradeTotal + grade;
      gradeAvg = gradeTotal /numOfGrades;
      
      /* Display the overall average of the grades entered. */
      
      printf (&quot;\nThe average of the %i grades entered is %i\n&quot;, numOfGrades, gradeAvg);
      
      /* Display the letter grade based on the average and grading standards. */
      
      if ( gradeAvg &gt;= 90 &amp;&amp; gradeAvg &lt;= 100 )
         printf (&quot;\nYou have a letter grade of A\n&quot;);
      else
      if ( gradeAvg &gt;= 80 &amp;&amp; gradeAvg &lt;= 89 )
         printf (&quot;\nYou have a letter grade of B\n&quot;);
      else
      if ( gradeAvg &gt;= 70 &amp;&amp; gradeAvg &lt;= 79 )
         printf (&quot;\nYou have a letter grade of C\n&quot;);
      else
      if ( gradeAvg &gt;= 64 &amp;&amp; gradeAvg &lt;= 69 )
         printf (&quot;\nYou have a letter grade of D\n&quot;);
      else
      if ( gradeAvg &lt; 64 )
         printf (&quot;\nYou have a letter grade of F\n&quot;);
      
      getchar( );
      

      } / End main /

       
    • Ron McHugh

      Ron McHugh - 2008-10-26

      You should do it twice.
      Once to validate the number of grades input (before the for loop).
      Next to validate each of the grades input (inside the for loop).
      It might help to create a function that can do this.

      int GetInteger(const char *prompt, const int min, const int max)
      {
      int input;

      do
      {
      printf("%s",prompt);
      scanf("%i",&input);

        if(input &lt; min || input &gt; max)
        {
           puts(&quot;error: value is out of range.&quot;);
        }
      

      } while(input < min || input > max);

      return input;
      }

       
      • cpns

        cpns - 2008-10-26

        > You should do it twice.
        > Once to validate the number of grades input (before the for loop).

        Good point; although entering a negative number or zero, the loop will simply fall through, which might be acceptable. Of course a reasonable maximum might be in order, but that is arguable, the user might be there a long time entering data, but it won't break the code.

        Clifford

         
    • Ron McHugh

      Ron McHugh - 2008-10-26

      As for the bug you mention, is the scope of the for loop.

      for ( i = 1; i <= numOfGrades; ++i )
      { // add this opener...............................................

      ...

      gradeTotal = gradeTotal + grade;
      } // add this closer..................................................
      gradeAvg = gradeTotal /numOfGrades;

       
    • TrakerJon

      TrakerJon - 2008-10-26

      Thanks Ron!

      Doah! Hand smack to the forehead! I just noticed that too. I do appreciate it guys, this class I'm taking is a little tough for an old man like me. I owe you both a Guinness.

      Cheers!

       
    • cpns

      cpns - 2008-10-26

      > is the do loop within the for loop or instead of the for loop?

      Within, you still need to get each score (the outer loop) until it is valid (the inner loop). That is how you need to be thinking.

      > but the grade average calculation is incorrect (13 instead of 62?)

      You broke it! ;-) You have been hoisted on your own petard, and I did warn you always use {...} even for single statement blocks. In updating the code you seem to have removed the {..} from the for loop, so only the while loop is contained within the loop, the accumulation of gradeTotal is outside the loop and only executed once for the last value entered.

      An conventional and consistent code indentation style should have highlighted that problem - it is impossible to tell because of this forums removal of such layout.

      If you always follow an if, for, while, or do with a { even when you don't technically need to, you will more easily be able to spot such errors. Using {...} in all cases is consistent. When it is missing, you have to think - "was this intentional, or was it a screw-up?", save yourself the bother, just do it.

      > I'll definitely work on the style after the do =):
      Probably a good idea, but style is something taht should become a habit, not something you apply afterwards. As I said, consistent layout should help show up faults such as the omission of the {..} in teh for loop.

      Clifford

       

Log in to post a comment.