C Program Do ... While Loop Question/Problem

Discussion in 'Mac Programming' started by JohnMC, Jan 24, 2010.

  1. JohnMC macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
    #1
    Hi All,

    I'm having trouble with my program I wrote for school. Our assignment was to build a program that takes inputted scores until a negative number is entered and then returns a report including the average values, minimum score, maximum score, number of assignments, etc. After working several bugs out of my program I have one remaining that I don't understand. When I enter assignment values in the console and enter a negative number to stop data collection, I have to enter one more integer and press enter before my report will print. It most be a simple problem, but I don't understand it. We have not covered the basis of using if..else or do..while in class yet, so I might be misunderstanding their use. Please give advice, this is a graded assignment, but I really need some explanation on what is wrong in my approach. Thanks.

    Code:
    #include <stdio.h>
    
    int main (int argc, const char * argv[]) {
        // ints and float used are assigned below
        int lastScore ;
    	int minScore = 100;
    	int maxScore = 0 ;
    	int numberAssign = 0;
    	int pointTotal = 0;
    	float assignAverage = 0.00;
    
    	
    	printf("Enter assigment scores relative to a one hundred point system.\nOnly use integer values (e.g. Do NOT enter 95.5) <0-100>.\nEnter a negative number to end input.\n");
    	//Last line prints program use instrutions
    	
    	do {
    		scanf("%d\n", &lastScore);									//scans for input scores
    		
    		if ((lastScore >= 0) && (lastScore <= 100)) {				//checks entered score to confirm it is between 0 and 100 then stores the data
    				pointTotal = pointTotal + lastScore;				//keeps a running total of all scores entered
    				numberAssign++;										//keeps a running total of the number of assignments
    			}
    		
    		if ((lastScore <= minScore) && (lastScore >= 0)) {			//should store the lastScore just entered in minScore if it is the smallest value entered so far  
    				minScore = lastScore;
    			}
    			
    		if ((lastScore >= maxScore) && (lastScore <= 100)) {		//should store the lastScore just entered in maxScore if it is the largest value entered so far 
    				maxScore = lastScore;
    			}
    			
    				
    	}	while (lastScore >= 0);
    		
    		
    		
    		assignAverage = (float)pointTotal/numberAssign;				//calculates the average score on the assignments entered
    		
    		/*PRINTS THE REPORT AND ENDS THE PROGRAM*/
    		printf("The summary of the assignments is as follows:\n");
    		printf("	Total number of points earned:					%d\n", pointTotal);
    		printf("	Total number of assignments graded:			%d\n", numberAssign);
    		printf("	Minimum score from the assignments:			%d\n", minScore);
    		printf("	Maximum score from the assignments:			%d\n", maxScore);
    		printf("	Mean score on the assignments:					%5.2f\n\n", assignAverage);
    		printf("This Report is completed.");
    		return 0;
    		
    		
    }
    

    This is an example of the console:

    Enter assigment scores relative to a one hundred point system.
    Only use integer values (e.g. Do NOT enter 95.5) <0-100>.
    Enter a negative number to end input.
    34
    65
    87
    98
    67
    89
    45
    -99
    1
    The summary of the assignments is as follows:
    Total number of points earned: 485
    Total number of assignments graded: 7
    Minimum score from the assignments: 34
    Maximum score from the assignments: 98
    Mean score on the assignments: 69.29

    This Report is completed.

    What I am trying to eliminate is the need to enter "1" after "-99" to get the program to print the report.

    Any comments or suggestions would be great. Thanks Again.

    John
     
  2. cmaier macrumors G3

    Joined:
    Jul 25, 2007
    Location:
    California
    #2
    do...while loops always execute once. In other words the "do" part executes, and THEN it checks the while.

    You probably just want to switch to a while loop. Something like:


    scanf("%d\n", &lastScore);
    while (0<=lastScore) {
    ....
    scanf(...&lastScore);
    }
     
  3. JohnMC thread starter macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
    #3
    In our assignment we are required to use a do ... while loop, otherwise I would use a simple while loop. My confusion is: if it runs through x times, but then I enter a negative number, when it gets to the end of the loop it should stop the loop and print the report, right? BTW, if I use an if statement like I do above, must I include an else as well?
     
  4. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
  5. JohnMC thread starter macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
    #5
    Wow... That fixed the problem, Thanks a lot. Can I ask why that line break would have interfered like that?
     
  6. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #6
    Um, because scanf doesn't ever use any formatting characters. So I guess it is undefined behavior.
    http://www.cplusplus.com/reference/clibrary/cstdio/scanf/
     
  7. JohnMC thread starter macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
  8. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #8
    I don't know how far your teacher goes in grading, but another bug of your program is if the user inadvertently enters non-numeric input, your program is stuck in an infinit loop and never returns :

    Code:
    $ ./test
    Enter assigment scores relative to a one hundred point system.
    Only use integer values (e.g. Do NOT enter 95.5) <0-100>.
    Enter a negative number to end input.
    99
    23
    43
    100
    23
    a
    43
    44
    -1
    11
    1
    11
    -1
    
    This is a known limitation of scanf unfortunately. You have to take in consideration it's return value to make sure the conversion was performed (from input to an integer in your case) and then find a way to empty out the non-numerical characters. The best would be to make a seperate function for input and use something like fgets() or getline().

    Also, in proper C, you should never return 0 from main. You should use stdlib.h and return the EXIT_SUCCESS value so that your code is portable.
     
  9. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #9
    True, but he did mention "Only use integer values (e.g. Do NOT enter 95.5) <0-100>." So he already warned the user that there would be bugs.

    To bad scanf isn't devined as
    Code:
    int  scanf ( const char * format_string_that_doesnt_contain_any_special_or_formatting_characters, ... );
    
     
  10. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #10
    Actually, that's just telling the user what is proper input. Your code should validate and sanitize input at all times.

    Again, don't know how your teacher grades your assignments, but back in college, ours had all sorts of messed up input to make sure we did all the proper checks.
     
  11. JohnMC thread starter macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
    #11
    KnightWRX, thanks for the comments. Our assignment was to write a single function to average entered scores. So far, we have not talked about reading or writing to a file. Thus I have no idea how to do what you describe. I understand your reasoning completely and hope I will understand how to do that soon. As far as not ending the program by returning "0", I will ask my professor how to do that this week.

    John
     
  12. KnightWRX macrumors Pentium

    KnightWRX

    Joined:
    Jan 28, 2009
    Location:
    Quebec, Canada
    #12
    Simply add #include <stdlib.h> at the top and instead of return 0; use return EXIT_SUCCESS;

    The reason for this is simple, not every OS out there uses 0 as a measure of success. On those systems, EXIT_SUCCESS will be set to the proper value in stdlib.h.
     
  13. JohnMC thread starter macrumors 6502

    Joined:
    May 5, 2006
    Location:
    Duluth, MN
    #13
    I changed my return value to EXIT_SUCCESS using the stdlib.h library. Thanks for explaining that to me. I think I learned more in this thread than I did in class the last two weeks. Thanks again.

    John
     
  14. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #14
    Well then, while we are learning, lets learn what scanf() returns.
    "Return Value

    On success, the function returns the number of items succesfully read. This count can match the expected number of readings or fewer, even zero, if a matching failure happens.
    In the case of an input failure before any data could be successfully read, EOF is returned."

    So scanf() will return 0 if it doesn't find any input.

    You can use this in your current program with slight modification inside your do while loop.

    Code:
    do {
         if ( scanf("%d", &lastScore) ){
              // scanf() was successful, so do the test on lastScore you want.
              //.....
         } else {
              // scanf() was unsuccessful, so terminate loop
              lastScore = -1;
         }
    } while (lastScore >=0);
    
     
  15. kakusan macrumors newbie

    Joined:
    Jan 25, 2010
    #15
    Actually, you CAN use constant characters in the format string for scanf. For example:

    int money;
    scanf("$%d", &money);

    will assign an integer value to money only if the input number is proceeded by a literal $. The tricky part of the OP's problem is that for white space characters this is not true. White space characters in the format string will match any amount of white space in the input. So "%d\n", "%d\t", and "%d " would all behave the same.

    The reason this causes a problem in your code, JohnMC, is that when you enter a number and hit return your computer sends that input to scanf. But scanf keeps waiting for more input, because it must read in ALL white space characters until it finds something that is not white space. Until you hit return AGAIN on the next line and send the next number to scanf, it doesn't know that there is no more white space. Unfortunately there is no easy way to read up to and including a '\n' with scanf which makes it rather counterintuitive.

    Also, as a matter of style, you may want to rename your variable assignAverage. Verbs are usually only used in function names, so 'assign' seems a bit out of place in a variable name.
     
  16. jared_kipe macrumors 68030

    jared_kipe

    Joined:
    Dec 8, 2003
    Location:
    Seattle
    #16
    I said FORMATTING CHARACTERS \n \t \r
     

Share This Page