Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

JohnMC

macrumors 6502
Original poster
May 5, 2006
386
1
Duluth, MN
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
 
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);
}
 
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?
 
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.
 
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.

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, ... );
 
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.

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.
 
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
 
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.
 
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
 
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

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);
 
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/

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.
 
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.

I said FORMATTING CHARACTERS \n \t \r
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.