Grade Program Question

R

Randy Howard

I meant no offense. We know K&R2 is using void main, and it is not the first
time to talk about this. If one day you teach someone how to write C
language, you will point out the void main is wrong, right ?

I've never seen a "void main" in K&R2. Perhaps my copy is defective?
Or, perhaps it has been used so much that all the "void"'s just wore
off the pages?

:)
 
J

Jeff

Randy Howard said:
I've never seen a "void main" in K&R2. Perhaps my copy is defective?
Or, perhaps it has been used so much that all the "void"'s just wore
off the pages?

:)

Yes.. I made a mistake. It should be "main()" :-(
 
P

pete

Henry wrote:
I tried it both ways , and both ways worked.

Let me get this straight.
Are you saying that even though you understand
that your code is operating outside the rules of C,
you're satisfied that you are in fact learning C
because you got the results that you expected ?
 
S

Steve Zimmerman

Henry said:
I was doing this program for an exercise in a book. The point was to create
a program that would take a numerical grade from a user and convert it to a
letter grade (yeah really easy). I tried to incorporate the while loop to
keep the program running continuously so the user could keep entering grades
to get the letter number, but I had little success and just kept creating
infinite loops. My question is:

How could I modify my program to read the last letter of the input and add +
or - to the end of the letter grade..
1-3 = -
4-6 = <blank>
7-9 = +

Here is my program so far:

#include <stdio.h>
#include <string.h>
main()
{
int letter_grade;
int numeric_grade;
int grade[100];

(void)printf("Enter the Numeric grade: ");
(void)fgets(grade, sizeof(grade), stdin);
(void)sscanf(grade, "%d", &numeric_grade);

if (numeric_grade <= 60)
letter_grade = "F";
if (numeric_grade > 60 && numeric_grade <= 70)
letter_grade = "D";
if (numeric_grade > 70 && numeric_grade <= 80)
letter_grade = "C";
if (numeric_grade > 80 && numeric_grade <= 90)
letter_grade = "B";
if (numeric_grade > 90 && numeric_grade <= 100)
letter_grade = "A";

(void)printf("The Letter grade is: %s\n", letter_grade);
}

Thank you for your post. You've made an excellent try. Here

is a program that works, except when you enter non-numeric input.
Maybe someone else can fix that part.

--Steve

#include <stdio.h>

int main()
{
char *letter_grade; /* Use the asterisk when you want to hold */
/* more than one character (i.e., */
/* char *letter_grade; not */
/* char letter_grade; */

int numeric_grade;
int grade[100];

printf("Enter the numeric grade (or negative number to quit): ");
scanf("%d", &numeric_grade);

if (numeric_grade > 100) {
printf("Grade entered must be less than 101. Try again: ");
scanf("%d", &numeric_grade);
}

while (numeric_grade >= 0) {

if (numeric_grade > 100) {
printf("Grade entered must be less than 101. Try again: ");
scanf("%d", &numeric_grade);
continue;
}

if (numeric_grade <= 60)
letter_grade = "F";
if (numeric_grade > 60 && numeric_grade < 64)
letter_grade = "D-";
if (numeric_grade > 63 && numeric_grade < 67)
letter_grade = "D";
if (numeric_grade > 66 && numeric_grade <= 70)
letter_grade = "D+";
if (numeric_grade > 70 && numeric_grade < 74)
letter_grade = "C-";
if (numeric_grade > 73 && numeric_grade < 77)
letter_grade = "C";
if (numeric_grade > 76 && numeric_grade <= 80)
letter_grade = "C+";
if (numeric_grade > 80 && numeric_grade < 84)
letter_grade = "B-";
if (numeric_grade > 83 && numeric_grade < 87)
letter_grade = "B";
if (numeric_grade > 86 && numeric_grade <= 90)
letter_grade = "B+";
if (numeric_grade > 90 && numeric_grade < 94)
letter_grade = "A-";
if (numeric_grade > 93 && numeric_grade < 97)
letter_grade = "A";
if (numeric_grade > 96 && numeric_grade <= 100)
letter_grade = "A+";

printf("The letter grade is: %s\n", letter_grade);

printf("Enter the numeric grade, (or negative number to quit): ");
scanf("%d", &numeric_grade);
}

return 0;
}
 
R

Richard Heathfield

Steve Zimmerman wrote:

Here
is a program that works, except when you enter non-numeric input.
Maybe someone else can fix that part.

--Steve

#include <stdio.h>

int main()
{
char *letter_grade; /* Use the asterisk when you want to hold */
/* more than one character (i.e., */
/* char *letter_grade; not */
/* char letter_grade; */

int numeric_grade;
int grade[100];

printf("Enter the numeric grade (or negative number to quit): ");
scanf("%d", &numeric_grade);

As you have pointed out, this fails for non-numeric input. Please don't
forget that scanf returns a useful value, a value that should not be
discarded lightly. But there is another issue here. It is entirely possible
that the program will block for input before the prompt appears on the
standard output device. To ensure that this does not happen, either end
your output line with a newline character, or fflush(stdout).

<snip>

Similar comments apply to the snipped section.

Lots of ifs coming up...
if (numeric_grade <= 60)
letter_grade = "F";
if (numeric_grade > 60 && numeric_grade < 64)
letter_grade = "D-";
if (numeric_grade > 63 && numeric_grade < 67)
letter_grade = "D";
if (numeric_grade > 66 && numeric_grade <= 70)
letter_grade = "D+";
if (numeric_grade > 70 && numeric_grade < 74)
letter_grade = "C-";
if (numeric_grade > 73 && numeric_grade < 77)
letter_grade = "C";
if (numeric_grade > 76 && numeric_grade <= 80)
letter_grade = "C+";
if (numeric_grade > 80 && numeric_grade < 84)
letter_grade = "B-";
if (numeric_grade > 83 && numeric_grade < 87)
letter_grade = "B";
if (numeric_grade > 86 && numeric_grade <= 90)
letter_grade = "B+";
if (numeric_grade > 90 && numeric_grade < 94)
letter_grade = "A-";
if (numeric_grade > 93 && numeric_grade < 97)
letter_grade = "A";
if (numeric_grade > 96 && numeric_grade <= 100)
letter_grade = "A+";

This is rather inelegant, and there are several possible approaches that
would make it quicker, less code, etc. I nearly illustrated one such method
here. But the code as you have written it here has the advantage of
simplicity, as befits early teaching code, so I've left it alone. Let the
OP understand, however, that more powerful techniques exist.
 
R

Richard Bos

Jeff said:
It should be " int main() ". If you C book write "main()", it is wrong and
it does not follow the ANSI standard.

This is true in C99, but in C89, which most people, probably including
the OP, are still using, unadorned main() is still valid and equivalent
to int main().

Richard
 
D

Default User

pete said:
While definitely clueful, K&R2 is not the last word on C.
In a showdown, the C standard beats K&R2.


K&R2, in concert with its errata list, pretty faithfully reflects the
standard C language as of the first standard. It is not and is not
intended to be reflective of the latest standard. As a learning guide,
it is still one of the premier textbooks on the subjects.




Brian Rodenborn
 
P

pete

Default said:
K&R2, in concert with its errata list, pretty faithfully reflects the
standard C language as of the first standard. It is not and is not
intended to be reflective of the latest standard. As a learning guide,
it is still one of the premier textbooks on the subjects.

Do you think it should be "main()" :-( ?
 
D

Default User

pete said:
Default User wrote:

Do you think it should be "main()" :-( ?


I think all new code should avoid implicit int, to make it more easily
portable to compilers that do implement the new standard. It hurts
nothing, and gains much in clarity and portability.

If your goal is to find reasons not to use K&R2, feel free. No reference
work stands by itself, you should K&R2, the Standard, the comp.lang.c
FAQ, any other well-regarded reference you can lay your hands on. This
is part of being a professional programmer.




Brian Rodenborn
 
T

The Real OS/2 Guy

/*
** change the above to:
*/
#include <assert.h>

#define STRINGLENGTH 3

/***************************/

/*
** And insert the assertion line, here:
*/

but only when you things that the user will never made a mistype or
like to see an unwanted demolition of the program.

asser is to test the program - not the data a user puts in. A C
compiler will ignore assert() anyway when it compiles without debug
option.
 
P

pete

The said:
but only when you things that the user will never made a mistype or
like to see an unwanted demolition of the program.

asser is to test the program - not the data a user puts in. A C
compiler will ignore assert() anyway when it compiles without debug
option.

/* BEGIN grade.c */

#include <stdio.h>
#include <stdlib.h>

#define STRINGLENGTH 3
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
char string[STRINGLENGTH + 1] = {'\0'};
int rc;

fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
getchar();
while (rc > 0) {
char letter[] = {'D','C','B','A'};
int number;

number = atoi(string);
if (number > 60) {
if (number > 99) {
number = 99;
}
string[0] = letter[(number - 60) / 10];
switch (number % 10) {
case 0:
case 1:
case 2:
case 3:
string[1] = '-';
string[2] = '\0';
break;
case 7:
case 8:
case 9:
string[1] = '+';
string[2] = '\0';
break;
default:
string[1] = '\0';
break;
}
} else {
string[0] = 'F';
string[1] = '\0';
}
printf("The Letter grade is: %s\n", string);
fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
getchar();
}
return 0;
}

/* END grade.c */
 
S

Steve Zimmerman

pete wrote:

[snip]

/* BEGIN grade.c */

#include <stdio.h>
#include <stdlib.h>

#define STRINGLENGTH 3
#define str(x) # x
#define xstr(x) str(x)

int main(void)
{
char string[STRINGLENGTH + 1] = {'\0'};
int rc;

fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
getchar();
while (rc > 0) {
char letter[] = {'D','C','B','A'};
int number;

number = atoi(string);
if (number > 60) {
if (number > 99) {
number = 99;
}
string[0] = letter[(number - 60) / 10];
switch (number % 10) {
case 0:
case 1:
case 2:
case 3:
string[1] = '-';
string[2] = '\0';
break;
case 7:
case 8:
case 9:
string[1] = '+';
string[2] = '\0';
break;
default:
string[1] = '\0';
break;
}
} else {
string[0] = 'F';
string[1] = '\0';
}
printf("The Letter grade is: %s\n", string);
fputs("Enter the Numeric grade: ", stdout);
fflush(stdout);
rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
getchar();
}
return 0;
}

/* END grade.c */

Pete,


This is a fascinating and beautifully written program.
Thank you for sharing it.

I have two questions concerning the following expression:

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
/^^^^^^^^^^^^^^^^^^\
/ \
1. Does this preprocess to this: # 3 [end of question].

2. If so, what does the # do?


--Steve
 
K

Kevin Easton

Steve Zimmerman said:
I have two questions concerning the following expression:

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
/^^^^^^^^^^^^^^^^^^\
/ \
1. Does this preprocess to this: # 3 [end of question].

No (but see the answer to the next question).
2. If so, what does the # do?

The # is a preprocessing operator that converts the following token to a
string.

xstr(STRINGLENGTH) expands to str(3), which expands to # 3, which
expands to "3".

- Kevin.
 
S

Steve Zimmerman

Kevin said:
I have two questions concerning the following expression:

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
/^^^^^^^^^^^^^^^^^^\
/ \
1. Does this preprocess to this: # 3 [end of question].

No (but see the answer to the next question).

2. If so, what does the # do?

The # is a preprocessing operator that converts the following token to a
string.

xstr(STRINGLENGTH) expands to str(3), which expands to # 3, which
expands to "3".

- Kevin.

Thank you, Kevin.

Some more questions:

1. Is the following an accurate representation of

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);

after preprocessing: rc = scanf("%3[^\n]%*[^\n]", string);

2. Is the 3 what the standard calls a "length modifier"?

3. Does

[^\n]%*[^\n]

assign a newline character if two digits are entered (say, 98),
and suppress assignment of a newline character
if three digits are entered (say, 100)?

4. If not, what does

[^\n]%*[^\n]

do?


--Steve
 
P

pete

Steve said:
Kevin said:
I have two questions concerning the following expression:

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);
/^^^^^^^^^^^^^^^^^^\
/ \
1. Does this preprocess to this: # 3 [end of question].

No (but see the answer to the next question).

2. If so, what does the # do?

The # is a preprocessing operator that converts the following token to a
string.

xstr(STRINGLENGTH) expands to str(3), which expands to # 3, which
expands to "3".

- Kevin.

Thank you, Kevin.

Some more questions:

1. Is the following an accurate representation of

rc = scanf("%" xstr(STRINGLENGTH) "[^\n]%*[^\n]", string);

after preprocessing: rc = scanf("%3[^\n]%*[^\n]", string);

2. Is the 3 what the standard calls a "length modifier"?

It's this part of the description of scanf():

N869
" -- An optional nonzero decimal integer that specifies the
maximum field width (in characters)."

3. Does

[^\n]%*[^\n]

assign a newline character if two digits are entered (say, 98),
and suppress assignment of a newline character
if three digits are entered (say, 100)?

4. If not, what does

[^\n]%*[^\n]

do?

It's two parts.
scanf(%3[^\n]%*[^\n]);
is the same as:
scanf(%3[^\n]);
scanf(%*[^\n]);

The asterisk is this part of the description of scanf():
"-- An optional assignment-suppressing character *."

The first part, gets all the characters up to the newline.
The second part throws away anything left over,
followed by getchar, which cleans up the last byte.

You can follow the evolution of the idiom in this newsgroup
by googling on the words 'Dan Pop scanf getchar'.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top