Changing an integer grade into a character grade using a switch statement - c

Using the switch statement, write a program that converts a numerical grade into a letter
grade:
Enter numerical grade: 84
Letter grade: B
Use the following grading scale:
A = 90-100, B = 80-89, C = 70-79, D = 60-69, F = 0-59.
Print an error message if the grade is larger than 100 or less than 0.
Hint: Break the grade into two digits, then use a switch statement to test the ten's digit.
How can I change the code to let 100 become A? I input 100 and the output was F.
#include <stdio.h>
int main(void)
{
int front_number, back_number;
printf("Enter numerical grade: ");
scanf("%1d%1d", &front_number, &back_number);
printf("Letter grade: ");
switch (front_number){
case 0: case 1: case 2: case 3: case 4: case 5:
printf("F");
break;
case 6:
printf("D");
break;
case 7:
printf("C");
break;
case 8:
printf("B");
break;
case 9:
printf("A");
break;
}
return 0;
}

In a real world program you would likely create a struct per grade, then search through a table of read-only elements. Example:
#include <stdio.h>
typedef struct
{
int low_limit;
int high_limit;
char grade;
} grade_t;
int main (void)
{
const grade_t grade[] =
{
{ 0, 59, 'F' },
{ 60, 69, 'D' },
{ 70, 79, 'C' },
{ 80, 89, 'B' },
{ 90, 100, 'A' },
};
int input = 82;
for(size_t i=0; i<sizeof grade/sizeof *grade; i++)
{
if(input <= grade[i].high_limit)
{
printf("%d gives %c", input, grade[i].grade);
break;
}
}
}
This is a naive linear search method but since the amount of items is so limited, it's likely quite efficient. Alternatively you could use standard C bsearch, in case you have a larger amount of sorted data.
Notably, we don't even need to know the lower limit since that's implicit by the previous item in the array.

It is better to not read two digits, because:
This tries to read the input and process this input in one step, while these are separate processes.
If the input is 100, it will leave the last 0 character in the input stream.
The cases 10 and 100 are indistinguishable.
The hint to "break the grade into two digits" is misleading for similar reasons.
The (probably) intended solution
Here is, what I assume to be, more or less the intended solution. It reads the entire (unsigned) integer, and uses a switch for its value divided by 10. The one not-so-elegant part is the default case (more of an "else" here) which has to distinguish between valid 3-digit input (i.e. 100 and invalid input.
Technically, part of the input is now being handled by an if-statement instead of a switch, but this is the most sensible solution given the problem statement. A bit better would be to catch the edge case grade == 100 at the top of function and leave the default case to only return an error value.
#include <stdio.h>
#include <stdlib.h>
char gradeUintToChar(unsigned int grade);
int main(void)
{
printf("Enter numerical grade: ");
fflush(stdout);
unsigned int gradeUint;
if (scanf("%u", &gradeUint) != 1)
{
fprintf(stderr, "Invalid input\n");
exit(EXIT_FAILURE);
}
char gradeChar = gradeUintToChar(gradeUint);
if (gradeChar == 0)
{
fprintf(stderr, "gradeUintToChar: Invalid parameter\n");
exit(EXIT_FAILURE);
}
printf("Letter grade: %c\n", gradeChar);
}
char gradeUintToChar(unsigned int grade)
{
switch (grade / 10U)
{
case 0: case 1: case 2: case 3: case 4: case 5:
return 'F';
case 6:
return 'D';
case 7:
return 'C';
case 8:
return 'B';
case 9:
return 'A';
default:
if (grade == 100U)
return 'A';
else
return (char) 0; // Indicates failure
}
}
The GNU case ranges solution
There is a GNU extension called case ranges which allows for this to be implemented rather directly using a switch. Since this is non-standard C, this is generally not a recommended method.
Code example:
#include <stdio.h>
#include <stdlib.h>
char gradeUintToChar(unsigned int grade);
int main(void)
{
printf("Enter numerical grade: ");
fflush(stdout);
unsigned int gradeUint;
if (scanf("%u", &gradeUint) != 1)
{
fprintf(stderr, "Invalid input\n");
exit(EXIT_FAILURE);
}
char gradeChar = gradeUintToChar(gradeUint);
if (gradeChar == 0)
{
fprintf(stderr, "gradeUintToChar: Invalid parameter\n");
exit(EXIT_FAILURE);
}
printf("Letter grade: %c\n", gradeChar);
}
char gradeUintToChar(unsigned int grade)
{
switch (grade)
{
case 0 ... 59:
return 'F';
case 60 ... 69:
return 'D';
case 70 ... 79:
return 'C';
case 80 ... 89:
return 'B';
case 90 ... 100:
return 'A';
default:
return (char) 0; // Indicates failure
}
}

Related

Why is there an infinite loop when I do not enter a number?

When I enter the letter 'q' as grade, it runs infinitely.
#include <stdio.h>
#include <stdbool.h>
int main(void) {
int grade;
bool flag = true;
while (flag) {
puts("-----------------------------"); // comment
printf("What's your grade out of 10? ");
scanf(" %d", &grade);
switch (grade) {
case 10:
case 9:
case 8:
case 7:
case 6:
printf("Pass\n");
break;
case 5:
printf("Fail\n");
break;
case 4:
printf("Fail\n");
break;
case 3:
printf("Fail\n");
break;
case 2:
printf("Fail\n");
break;
case 1:
printf("Fail\n");
break;
case 0:
printf("Fail\n");
break;
default:
printf("Illegal Grade\n");
flag = false;
break;
}
}
return 0;
}
scanf(" %d",&grade);
It scans int in string. "q" is not int. When you enter "q", value of the variable grade left unchanged. You must check returned value of scanf to validate number of filled placeholders.
if (scanf(" %d",&grade) != 1) {
printf("Illegal Grade\n");
exit(1); // or break
}
Other parts are ok.
scanf(" %d", &grade); fails when you type something that cannot be parsed as into an integer. grade is not modified, so it is uninitialized if the conversion error happens immediately and the behavior is undefined, otherwise you get the same value and behavior as the previous time.
The offending input stays in the input stream, so the same thing happens when the code executes again in the while loop, hence the infinite loop.
You want to test if the conversion was successful and discard the input if not:
#include <stdio.h>
#include <stdbool.h>
int main(void) {
int res, c, grade;
bool flag = true;
while (flag) {
puts("-----------------------------"); // comment
printf("What's your grade out of 10? ");
res = scanf("%d", &grade);
if (res == EOF)
break;
if (res == 0) {
printf("Invalid input\n");
/* discard the offending line of input */
while ((c = getchar()) != EOF && c != '\n')
continue;
/* try again */
continue;
}
switch (grade) {
case 10:
case 9:
case 8:
case 7:
case 6:
printf("Pass\n");
break;
case 5:
case 4:
case 3:
case 2:
case 1:
case 0:
printf("Fail\n");
break;
default:
printf("Illegal Grade\n");
flag = false;
break;
}
}
return 0;
}

print an int and char with the same identifier in C

I'm trying to do a simple code but I'm having hard time while trying to make it work.
I want to get an int from stdin between 1 and 50.
if the number is 1 then to print A
if the number is 11 then to print J
if the number is 12 then to print Q
if the number is 13 then to print K
Edit: If its none of them, then just return the number.
i tried to use %c but it wont work for numbers from 10 and above
then i managed to do it by using switch but the default part is not working for me. the only thing i managed to do is to make 50 case's for each number but that's just look horrible.
any help would be appreciated.
#include <stdio.h>
main() {
int number;
scanf("%d", &number);
char* card = NULL;
switch (number)
{
case 1:
card = "A";
break;
case 11:
card = "J";
break;
case 12:
card = "Q";
break;
case 13:
card = "K";
break;
default:
card = //Dont know what to write here//;
}
printf("%s\n", card);
return 0;
}
As far as I can see, this code should work:
#include <stdio.h>
#include <string.h>
#include <limits.h>
#define MAX_STRING_SIZE (sizeof(int)*CHAR_BIT/3 + 3)
int main(int argc, char **argv) {
int number = 0;
scanf("%d", &number);
char card[MAX_STRING_SIZE] = {0};
switch (number)
{
case 1:
strcpy(card, "A");
break;
case 11:
strcpy(card, "J");
break;
case 12:
strcpy(card, "Q");
break;
case 13:
strcpy(card, "K");
break;
default:
sprintf(card, "%d", number);
}
printf("%s\n", card);
return 0;
}
Note that you cannot assign strings with: card = "whatever", you must use strcpy() found in the string.h library. For the default part of your code, I assumed you were trying to convert the card input which was not 1, 11, 12, or 13. In which case, you can use sprintf() to convert the integer value to a string.
I hope this helps!
#define MINCARD 1
#define MAXCARD 50
const char *num2card(int n)
{
static char buf[3];
assert(n >= MINCARD && n <= MAXCARD && "Inval card no.");
switch (num) {
case 1:
return "A";
case 11:
return "J";
case 12:
return "Q";
case 13:
return "K";
default:
snprintf(buf, 3, "%d", num);
}
return buf;
}
Use an array of char. Each numerical "case" will correspond to an index in the array, and the element at that index will be the appropriate "card".
As for what the "default" value should be - that is a requirements question. What is the purpose of this application?
you can try sprintf, but you still have to add in logic for what happens if the number is larger than 50.
#include <stdio.h>
#include <stdlib.h>
int main() {
int number;
scanf("%d", &number);
char* card = malloc(8);
switch (number)
{
case 1:
card = "A";
break;
case 11:
card = "J";
break;
case 12:
card = "Q";
break;
case 13:
card = "K";
break;
default:
sprintf (card , "%i" , number );
}
printf("%s\n", card);
return 0;
}

Suprisingly small limits of the calculator written in C

My task is to write a calculator, which accepts only valid operands, that is, * / + - ^. The calculator has to evaluate (check the validity) of the line being entered. For example, it accepts only lines of the following form: 20 + 9, 8 ^ 2, etc. If someone entered 9y, 20+2 or exit, the expression would be evaluated to 0. Then the user has to have the possibility of displaying lines, which were entered, regardless of their validity. (Switch E for invalid lines, switch V for valid lines, if valid line is entered and V is chosen it also displays the value of an expression).
Let's now consider the example in order to see how it works.
Line: 20 + 20
Switch: E
Output: There's nothing wrong with the line 20 + 20.
Switch: V
Output: The result is 40.
Line: 20r
Switch: E:
Output: The line is 20r
Switch: V:
Output: The line 20r is invalid.
The problem:
Every time I enter a line, which would have the result of calculation more then, I guess 7000 (it doesn't work for 8 * 900), it doesn't even allow me to choose the char for the switch. It displays the line Choose E for... and then automatically You haven't chosen the valid option of the switch..
MAIN.C:
#include "stdio.h"
#include "evalexpression.h"
int main() {
char string[100];
int result;
result = InterCalc(string);
CalcFilter(result, string);
return 0;
}
EVALEXPRESSION.C
#include "stdio.h"
#include "string.h"
#include "evalexpression.h"
#include "math.h"
#include "float.h"
static float f1, f2;
static char op;
int isValidExpression(const char *str) {
int res;
char ops[10];
res=sscanf(str, "%f %s %f", &f1, ops, &f2);
if (res==3) {
if (ops[0]=='+' || ops[0]=='-' || ops[0]=='^' || ops[0]=='*' || ops[0]=='/') {
op=ops[0];
return 1;
}
else
return 0;
}
else
return 0;
}
int getOperator() {
if (op=='+')
return 1;
else if (op=='-')
return 2;
else if (op=='/')
return 3;
else if (op=='*')
return 4;
else if (op=='^')
return 5;
else return 0;
}
float getFstOperand() {
return(f1);
}
float getSecOperand() {
return(f2);
}
int InterCalc(char *my_string) {
fgets(my_string, sizeof(my_string), stdin);
if (strcmp(my_string, "exit\n")==0 ) {
printf("Program ended\n");
return 0;
}
else if ( isValidExpression(my_string) == 0 ) {
printf("Expression error\n");
return 0;
}
else
return 1;
}
float getExprValue() {
int operation;
operation = getOperator();
switch (operation) {
case 1:
return (getFstOperand() + getSecOperand());
break;
case 2:
return (getFstOperand() - getSecOperand());
break;
case 3:
return (getFstOperand() / getSecOperand());
break;
case 4:
return (getFstOperand() * getSecOperand());
break;
case 5:
return ( pow(getFstOperand(), getSecOperand()) );
break;
default:
return 0;
}
}
void CalcFilter(int a, char *str) {
float calculation_value;
printf("Press 'E' to display the invalid line or press 'V' to display the valid line\n");
int choice;
choice = getchar();
switch (choice) {
case 'E':
case 'e':
if (a==0)
printf("The line %s is invalid.\n", str);
else if (a==1)
printf("There's nothing wrong with the line %s\n", str);
break;
case 'V':
case 'v':
if (a==1) {
calculation_value = getExprValue();
//if (calculation_value > FLT_MAX || calculation_value < FLT_MIN)
// printf("The value of expression is beyond limits\n");
//else
printf("The result of %s is %f.\n", str, calculation_value); }
if (a==0)
printf("The line %s is invalid\n", str);
break;
default:
printf("You haven't chosen the valid option of the switch\n");
break;
}
}
Look at the first lines of your InterCalc() function
int InterCalc(char *my_string) {
fgets(my_string, sizeof(my_string), stdin);
sizeof is a compile-time operator. sizeof(my_string) is the size of a pointer to char which for a 32 bit system is typically 4 bytes.
sizeof does not give the length of whatever string my_string points at. It will not give 100 (the length of the array in main()).
You will need to pass the value 100 (or whatever the size is in main() if you change it) by some other means, such as an extra function parameter.

C - Issue converting a user generated number into words

So I've been working my way through Kochan's Programming in C and I've hit a snag on one of the questions which reads as follows:
"Write a program that takes an integer keyed in from the terminal and extracts and displays each digit of the integer in English. So if the user types in 932, the program should display the following: nine three two (Remember to display zero if the user types in just 0.)"
I had managed to get the program to print out the digits as words but unfortunately in reverse order. From there I thought it might be a good idea to reverse the number so to speak, but now when I run that value through my program only prints out "one one one ...." for how ever many digits long the number I enter in.
In other words, originally I managed to display 932 as "two three nine", but when I tried to reverse the number and run 239 through my program I only get "one one one".
If any one has any hints that could point me in the right direction it would be very much appreciated! My code is below:
#include <stdio.h>
int digitCount (int);
int reverseNumber (int);
int main(void)
{
//Chapter 6 Problem 6
int x, numberValue;
printf("Enter the number you'd like converted to words\n");
scanf("%i", &x);
numberValue = reverseNumber(x);
printf("The reverse is %i\n", numberValue);
do {
numberValue = numberValue % 10;
switch (numberValue) {
case 0:
printf("zero\t");
break;
case 1:
printf("one\t");
break;
case 2:
printf("two\t");
break;
case 3:
printf("three\t");
break;
case 4:
printf("four\t");
break;
case 5:
printf("five\t");
break;
case 6:
printf("six\t");
break;
case 7:
printf("seven\t");
break;
case 8:
printf("eight\t");
break;
case 9:
printf("nine\t");
break;
default:
break;
}
x = x / 10;
} while (x != 0);
return 0;
}
int digitCount (int u)
{
int cnt = 0;
do {
u = u / 10;
cnt++;
} while (u != 0);
return cnt;
}
int reverseNumber (int y)
{
int cnt, Rev;
cnt = digitCount(y); //returns number of digits
while (cnt != 0) {
Rev = Rev * 10 + y % 10;
y = y / 10;
cnt--;
}
return Rev;
}
In your reverseNumber function you have not initialized Rev. Make Rev=0
int reverseNumber (int y)
{
int cnt, Rev=0;
cnt = digitCount(y); //returns number of digits
printf("Digit count %d\n", cnt);
while (cnt != 0) {
Rev = Rev * 10 + y % 10;
y = y / 10;
cnt--;
}
return Rev;
}
In main in the do while loop use a temporary variable since you are overwriting numberValue with numberValue % 10. But the most ironic part in your program (where you complicated everything for yourself) is that there is no need to reverse the number at all. See the code here
In the way user entered - http://ideone.com/pORaP2
In reverse order - http://ideone.com/5GS8al
When you find modulo you get the number in the reverse order itself. Suppose you entered 234
First step 234%10 gives 4 prints four. And then makes 234 to 23
Second step 23%10 gives 3 prints three. And then makes 23 to 2
and then finally prints two.
Consider what the primary problem is you are dealing with, you need to process the left most digit first, then the next to the right, then the next. But the math of using modulus and division goes from right to left. So what you need is some way to either save the math processing and reverse, or have the output be delayed. Two options are available.
For an iterative approach you could utilize a FIFO queue type approach that holds the results of each digit and then prints out the queue. Could be as simple as an array with indexing:
int main(void) {
int x, i;
int result[32]; //arbitrary size
int index = 0;
printf("Enter the number you'd like converted to words\n");
scanf("%i", &x);
do {
results[index++] = x % 10;
x = x / 10;
} while( index < 32 && x != 0 );
//now print in reverse order
for(i = index-1; i >= 0; i--) {
switch (results[i]) {
case 0:
printf("zero\t");
break;
case 1:
printf("one\t");
break;
case 2:
printf("two\t");
break;
case 3:
printf("three\t");
break;
case 4:
printf("four\t");
break;
case 5:
printf("five\t");
break;
case 6:
printf("six\t");
break;
case 7:
printf("seven\t");
break;
case 8:
printf("eight\t");
break;
case 9:
printf("nine\t");
break;
default:
break;
}
}
}
There is second approach that works which is recursive. Here you delay the printing of the output until you reach the left most digit. The built in stack is used for by the recursive calls.
void printNumbers(int x);
int main(void) {
int x;
printf("Enter the number you'd like converted to words\n");
scanf("%i", &x);
printNumbers(x);
}
void printNumbers(int v) {
if( v > 9 ) {
printNumbers( v / 10 );
}
switch (v%10) {
case 0:
printf("zero\t");
break;
case 1:
printf("one\t");
break;
case 2:
printf("two\t");
break;
case 3:
printf("three\t");
break;
case 4:
printf("four\t");
break;
case 5:
printf("five\t");
break;
case 6:
printf("six\t");
break;
case 7:
printf("seven\t");
break;
case 8:
printf("eight\t");
break;
case 9:
printf("nine\t");
break;
default:
break;
}
}
Both approaches will solve the problem, but not if the input is a negative number.
My simple answer:
void printNum(int x)
{
static const char * const num[] = {
"zero ", "one ", "two " , "three ", "four ",
"five ", "six ", "seven ", "eight ", "nine "
};
if (x < 10) {
printf(num[x]);
return;
}
printNum(x / 10);
printNum(x % 10);
}

Initializing Switch Case

I'm building a program using a grade report and I'm having trouble calculating my GPA using a switch case. I'm unsure why it isn't assigning the correct values. I would also like if there is a way to ask for the number of classes taken and then get the loop to perform that said number of times.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Grades
{
char Name[20];
int Hrs;
int ID;
char ClassName[20];
char Grade;
char ClassID[6];
};
int main ()
{
struct Grades Transcript[6];
int classCnt = 0;
int vHrs=0, vGPA=0, totalHours=0, totalPoints = 0;
char vGrade;
char vName[20], vCID[6], vClassName[20];
printf("Enter Students Name: ");
fgets(vName, 20, stdin);
do
{ printf("\nEnter Class ID: ");
fgets(vCID, 6, stdin);
fflush(stdin);
strcpy_s(Transcript[classCnt].ClassID, vCID);
printf("Enter Class Name: ");
fgets(vClassName, 20, stdin);
strcpy_s(Transcript[classCnt].ClassName, vClassName);
printf("Enter Class Hours: ");
fflush(stdin);
scanf("%d", &vHrs);
Transcript[classCnt].Hrs = vHrs;
printf("Enter Class Grade: ");
fflush(stdin);
scanf("%c", &vGrade);
Transcript[classCnt].Grade = vGrade;
classCnt++;
fflush(stdin);
totalHours+=vHrs;
switch (vGrade) {
case 'A':
case 'a': 4*vHrs;
break;
case 'B':
case 'b': 3*vHrs;
break;
case 'C':
case 'c': 2*vHrs;
break;
case 'D':
case 'd': 1*vHrs;
break;
case 'F':
case 'f': 0;
break;
default: printf("Invalid Grade");}
totalPoints += vGrade;
vGPA = (totalPoints/totalHours);
}while(classCnt<=5);
printf("********************************** Grade Report: *************************************");
printf("\n%d\n", totalHours);
printf("%d\n", vGPA);
system("Pause");
return 0;
The expression statement:
4*vHrs;
is certainly valid in C but it doesn't actually do anything (a).
Perhaps you may want to assign it to something, such as with:
addPoints = 4 * vHrs;
(declaring addPoints beforehand, of course) and then use that to affect totalPoints later:
totalPoints += addPoints;
In terms of asking for a class count, you can use scanf("%d",...) to get an integer from the user and then just use that integer in a loop:
#include <stdio.h>
int main (void) {
int num, count;
printf ("Enter countdown value: ");
scanf ("%d", &count);
for (num = count; num > 0; num--)
printf ("%d ", num);
puts ("BLAST OFF");
return 0;
}
A sample run being:
Enter countdown value: 10
10 9 8 7 6 5 4 3 2 1 BLAST OFF
(a) Even a statement like 42; is valid, though useless. The reason this is allowed is because you can have side effects in expressions. The classic case, though not many learners immediately see this, is the venerable i++;.
This is an expression which gives you the current value of i (which you throw away unless you're using it somehow), then increments i as a side effect.
case 'A':
case 'a': 4*vHrs;
break;
case 'B':
case 'b': 3*vHrs;
break;
case 'C':
case 'c': 2*vHrs;
break;
case 'D':
case 'd': 1*vHrs;
break;
case 'F':
case 'f': 0;
None of these lines have any effect on the program you've written. You might want to assign 3*vHrs, 4*vHrs etc to a variable and then do the calculations below. You probably meant vHrs *= 3 or vHrs *=4 or something like that?

Resources