Why does my if statement create an infinite loop? - c

The code works for every if statement except for the first one where if the statement is true, it proceeds to create an infinite loop of "Enter a student mark [0.00, 100,00] : " and "No input accepted!".
#include <stdio.h>
#define MIN 0
#define MAX 100
int getMark(void) {
int mark;
char ch;
int repeat = 1;
printf("Enter a student mark [0, 100] : ");
int r = scanf("%i%c", &mark, &ch);
if (r == 0) {
printf("**No input accepted!**\n");
}
else if (ch != '\n') {
printf("**Trailing characters!**\n");
}
else if (mark < MIN || mark > MAX) {
printf("**Out of range!**\n");
}
return mark;
}
int main() {
int mark;
do {
mark = getMark();
} while (mark != 0);
}
What's causing it to loop and how do I fix it?

1) If you input a string or just a char value you must remove it from your input stream before using it.
#include <stdio.h>
#define MIN 0
#define MAX 100
int getMark(void) //Funtion for marks input
{
int mark;
char ch;
//int repeat = 1;
char c;
printf("Enter a student mark [0.00, 100,00] : ");
int r = scanf("%d %c", &mark, &ch);
if (r == 0) //Input begins with a letter
{
printf("**No input accepted!**\n");
}
else if(ch == '\n') //Input ends with a letter
{
printf("**Trailing characters!**\n");
}
else if( mark < MIN || mark > MAX) //Range
{
printf("**Out of range!**\n");
}
//Remove the previous string from the input stream
while ( (c = getchar()) != '\n' && c != EOF );
return mark;
}
int main()
{
int mark;
do
{
mark = getMark();
}while (mark != 0);
return 0;
}
Output
Enter a student mark [0.00, 100,00] : -10 c
**Out of range!**
Enter a student mark [0.00, 100,00] : 101 b
**Out of range!**
Enter a student mark [0.00, 100,00] : 50 a
Enter a student mark [0.00, 100,00] : abcd
**No input accepted!**
Enter a student mark [0.00, 100,00] : 0 q

The problem is that with no input accepted the variable mark will be uninitialized and might be something else that 0. Your while loop will then continue forever without updating mark.

Related

Input Validation in C When Calculating Grades

I have a problem that needs to calculate the grade needed on a final exam in order to get the letter grade that they desire. I have the code correct for the calculations but I need to account for all invalid user input. I have accounted for negative grades and letter grades that don't exist but I can't figure out how to make sure the percentages they are inputting don't contain letters or other characters. For example if I ask for their current grade in the class they cannot input something like 95.6asi!. This is the code I have right now but there are many errors.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
void calcGradeNeededOnFinal() {
double percentWanted = 0.0;
double currentGrade, finalWeight;
char gradeWanted;
printf("Enter the grade you want in the class: ");
scanf("%c", &gradeWanted);
if (gradeWanted == 'A' || gradeWanted == 'a'){
percentWanted = 90.0;
}
else if (gradeWanted == 'B' || gradeWanted == 'b'){
percentWanted = 80.0;
}
else if (gradeWanted == 'C' || gradeWanted == 'c'){
percentWanted = 70.0;
}
else if (gradeWanted == 'D' || gradeWanted == 'd'){
percentWanted = 60.0;
}
else if (gradeWanted == 'F' || gradeWanted == 'f'){
percentWanted = 0.0;
}
else {
printf("Unknown Grade Received: %c. Ending Program.\n", gradeWanted);
exit(0);
}
printf("Enter your current percent in the class: ");
scanf("%lf", &currentGrade);
if(currentGrade < 0) {
printf("The number you last entered should have been positive. Ending program.\n");
exit(0);
}
char gradeString = (char)currentGrade;
for(int i=0; i < strlen(gradeString); ++i) {
if(!(isdigit(gradeString[i])) && (strcmp(gradeString[i], '.') != 0))) {
printf("Invalid formatting. Ending program.\n");
exit(0);
}
}
printf("Enter the weight of the final: ");
scanf("%lf", &finalWeight);
if(finalWeight < 0) {
printf("The number you last entered should have been positive. Ending program.\n");
exit(0);
}
char weightString = (char)finalWeight;
for(int i=0; i < strlen(weightString); ++i) {
if(!(isdigit(weightString[i])) && (strcmp(weightString[i], '.') != 0))) {
printf("Invalid formatting. Ending program.\n");
exit(0);
}
}
// this calculates the grade need on the final test to get the desired grade of the user
double gradeNeededOnFinal = (percentWanted - (currentGrade * (1.0 - finalWeight/100.0))) / (finalWeight/100.0);
printf("You need to get at least %.2lf%% on the final to get a %c in the class.\n", gradeNeededOnFinal, gradeWanted);
}
int main() {
calcGradeNeededOnFinal();
return 0;
}
For example if I ask for their current grade in the class they cannot input something like 95.6asi!.
You have declared grade as char so there is no possibility that it can store 95.6asi!
char gradeWanted;
What you need is : isalpha or isupper and islower function(s) from ctype.h
isalpha() checks for an alphabetic character; in the standard "C" locale, it is equivalent to (isupper(c) || islower(c)). In some locales, there may be additional characters for which isalpha() is true-letters which are neither upper case nor lower case.
Just check if your gradeWanted is an alphabet or not.
Using
if (isalpha( gradeWanted ))
or
if (isupper( gradeWanted ) || islower( gradeWanted ))
is enough.
All ctype functions takes an int and returns an int, you can declare char gradeWanted; as int gradeWanted;
you could read the characters entered and, using the ascii encoding, check (perhaps with a switch) which character is inserted and manage it.
This way you have full control of the entries.
you can get char to ascii conversion with:
int a_as_int = (int)'a';

How to read string in structure with space? [duplicate]

This question already has answers here:
Reading string from input with space character? [duplicate]
(13 answers)
Closed 5 years ago.
Our corporation office requires an application which will maintain all registered Universities in Chennai and that application should be user friendly in terms of searching a University. Create a structure called “University” with the following attributes: name, license number and area code.
Requirement: License number for a university should be 6 digits and the first 2 digits must be alphabets of Upper case letters and last 4 digits must be number.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct University
{
char name[100];
char license[10];
int area;
}u[10];
void main()
{
int i, n, r, k = 0, flag = 1, f2 = 1, j, search = 0;
char s[100];
printf("Enter the number of records\n");
scanf("%d", &n);
printf("Enter the details of %d universities\n", n);
for (i = 0; i<n; i++)
{
printf("Name of the University\n");
getchar();
scanf("%s", u[i].name);
j = strlen(u[i].name);
if (j <= 1)
{
f2 = 0;
break;
}
printf("License Number\n");
scanf("%s", u[i].license);
k = strlen(u[i].license);
if (k<1)
{
f2 = 0;
break;
}
if (k<6)
{
flag = 0;
}
else if ((u[i].license[0] >= 'A' && u[i].license[0] <= 'Z') && (u[i].license[1] >= 'A' && u[i].license[1] <= 'Z') && (u[i].license[2] >= '0' && u[i].license[2] <= '9') && (u[i].license[3] >= '0' && u[i].license[3] <= '9') && (u[i].license[4] >= '0' && u[i].license[4] <= '9') && (u[i].license[5] >= '0' && u[i].license[5] <= '9') && k == 6)
{
flag = 1;
}
else
{
flag = 0;
}
printf("Area Code\n");
scanf("%d", &u[i].area);
//printf("%d",u[i].area);
if (u[i].area <= 0)
{
f2 = 0;
}
}
if (flag == 0)
{
printf("Sorry! You have entered incorrect license number.");
}
else if (f2 == 0)
{
printf("Unable to continue");
}
else
{
printf("Enter the name of the University to be searched\n");
scanf("%s", s);
for (i = 0; i<n; i++)
{
if ((strcmp(u[i].name, s)) == 0)
{
search = 1;
}
}
if (search == 1)
{
printf("University is licensed one.");
}
else
{
printf("University is not found.");
}
}
}
when I give number of university as 3, then it did not take input for the 3rd university.
Test Case
Input 1
Enter the number of records
3
Enter the details of 3 universities
Name of the University
SRM
License Number
SR1234
Area Code
28
Name of the University
University of Madras
License Number
SP0904
Area Code
18
Name of the University
Bharath University
License Number
BU0101
Area Code
35
Enter the name of the University to be searched
SRM
Output 1
University is licensed one.
Seems like you are interested in just reading a c-string containing a space. To do that you can use fgets. Here is a toy program:
#include <stdio.h>
#include <string.h>
struct s {
char name[100];
int something;
};
int main(void)
{
struct s myStruct;
printf("%s", "Enter name: ");
fgets(myStruct.name, 100, stdin);
myStruct.name[strlen(myStruct.name) - 1] = '\0'; //This should remove the newline char at the end
printf("Name is: %s", myStruct.name);
}

C Program Looping Incorrectly

I'm just a beginner and I'm trying to use whatever I know to make a simple program that:
Asks the user to input the letter 'S' or 's'. The program loops if 's' is not input. If the user does input 's', the program then
Asks the user to input a number, 1 or 2. The program loops if the incorrect number is input.
The problem I'm having is that after 's' is successfully input and the user is asked to enter a number, if an incorrect number is input (not 1 or 2) the program asks the user to input a letter again from the beginning which is incorrect. The program loops from the very beginning and doesn't work anymore. Can anyone help me fix this please?
#include <stdio.h>
#include <ctype.h>
int function(int num);
int main()
{
char input,ch,temp,c[64],exit;
int i,invalid,num,index,flag,day;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
do
{
puts("Enter the letter S to start the program:");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
Make the scanf into like this.
scanf(" %c",&input);
Then While getting the input from the user using fgets It will place the new line character into that buffer. So this will lead to fails this condition.
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
So make the this condition into like this.
length=strlen(c)-1;// to skip the new line character
Or else to like this.
length=strlen(c);
if ( c[length] == '\n' )
c[length]='\0';
Output After placing this,
Enter the letter S to start the program:
S
Program start.
Enter 1 for Module A. Enter 2 for Module B. Enter here: 1
Module A Selected.
Make this in you code.
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
Note that the loop:
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
is limited to the one line by the semicolon at the end. The following code is not the body of the loop, despite indentation trying to pretend that it is.
Also note that getchar() returns an int, not a char; you cannot reliably assign the result to a char and then test it for EOF. Depending on the platform, you will either never detect EOF at all or you will misdetect EOF when some other character (often ÿ, y-umlaut, U+00FF, LATIN SMALL LETTER Y WITH DIAERESIS) is typed. You must use int ch;.
Here. I fixed the problem using the following code. This way the code does the following:
Scans letters 'S' or 's'. Keeps looping if these are not entered.
Scans either number 1 or 2. Keeps looping until either number is entered and then exits.
The program does not loop from the very beginning (by outputting "Enter 'S' to start program), if any number other than 1 or 2 in entered in part 2 of the program. This was the problem originally.
The following is the correct code:
#include <stdio.h>
#include <ctype.h>
int function();
char input,temp,c[64],ch,exit;
int i,invalid,num,index,flag,start;
start = 0;
invalid = 0;
num = 0;
size_t length = 0;
index = 0;
flag = 0;
int main()
{
do
{
puts("Enter the letter S to start the program: ");
scanf("%c", &input);
while( input!='\n' && (ch=getchar())!='\n' && ch!= EOF);
{
if(isalpha(input)==0)
{
printf("Invalid input. Please input something.\n");
continue;
}
if(input == 'S' || input == 's')
{
printf("\nProgram start.");
start = 1;
if(start == 1)
{
function();
return(0);
}
}
else
{
printf("\nInvalid input.");
continue;
}
}
}
while(1);
}
int function()
{
while( sscanf(c, "%d", &num) != 1)
{
length = 0;
flag = 0;
num = 0;
printf("\nEnter 1 for Module A. Enter 2 for Module B. Enter here: ");
fgets(c, 63, stdin);
length = strlen(c);
length --;
for(index = 0; index < length; ++index)
{
if(c[index] < '0' || c[index] > '9')
{
flag = 1;
break;
}
}
if( flag)
{
printf("\nInvalid character\n");
continue;
}
if( sscanf(c, "%d", &num) != 1)
{
printf("\nNo input detected.");
continue;
}
if(num == 1)
{
printf("\nModule A Selected.\n");
return(0);
}
else if(num == 2)
{
printf("\nModule B Selected.\n");
return(0);
}
else
{
printf("\nInvalid option\n");
c[0]='\0'; // It is for satisfy the second while loop condition.
continue;
}
}
}

Logic in detecting int in C

I would appreciate some help with this. I'm trying to create this simple program that repeatedly loops asking for the user to enter in an int. If he enters an int, it exits but if he enters something else or bigger than int (ex.4gs4r33) it will loop again asking to enter an int. This is what I have tried, and it's not working. It says it's an int even if it's not.
#include<stdio.h>
unsigned int findInt();
int main() {
printf("Please input an int.\n");
findInt();
}
unsigned int findInt() {
char input;
long num = 0;
int b = 0;
do {
scanf("%c", &input);
if (isdigit(input)){
num = num*10+input+'0';
b = 1;
}
else if (input == '\n')
b = 1;
else
b = 0;
} while(input != '\n');
if (b == 1)
printf("Great!\n");
else{
printf("Not an int \n");
findInt();
}
return 0;
}
Two possible approaches. One would be to modify your code:
b = 1; // start off with good intentions…
do {
scanf("%c", &input);
if (isdigit(input)){
num = num*10+input -'0'; // *** SUBTRACT '0', don't add it!
}
else if (input != '\n') {
b = 0;
break; // *** break when you find non-digit
}
} while (input != '\n');
Two changes: getting the math right as you compute the integer, and fixing the logic (so you break out of your loop when you find a non digit character)
Second approach:
char buf[100];
char intAsString[100];
fgets(buf, 100, stdin);
sscanf(buf, "%d", num);
sprintf(intAsString, "%d\n", num);;
if(strcmp(buf, intAsString) == 0 ) {
printf("yay - you entered an integer!\n");
}
I'm sure you can figure out how that works.
update a complete code snippet that solves the issue of "loop logic" as well: you call the findInt function once from the top level, and it keeps going until you get the int. Note - in order for this to work properly, I read the entire input at once (rather than one at a time), then pick off the characters one by one using sscanf (and updating the pointer manually). It has a number of advantages - not least of which is that you start with a fresh input every time you call findInt, instead of having the rest of the input buffer that still needs reading (and which was giving rise to "no,no,no,great!" - as you would keep reading the bad input until you got to the newline, and accept that...)
#include<stdio.h>
#include <ctype.h>
unsigned int findInt();
int main() {
findInt();
}
unsigned int findInt() {
char input;
char buf[100];
char *temp;
long num = 0;
int b = 0;
printf("please enter an int:\n");
fgets(buf, 100, stdin);
temp = buf;
do {
sscanf(temp++, "%c", &input);
if (isdigit(input)){
num = num*10+input-'0';
b = 1;
}
else if (input == '\n')
{
b = 1;
break;
}
else {
b = 0;
break;
}
} while(input != '\n');
if (b == 1)
printf("Great! %d is an integer!\n", num);
else{
printf("Not an int \n");
findInt();
}
return 0;
}
In the else branch - i.e. not a digit or a newline - you set b to 0. Now if a digit DOES follow you reset that to 1.
You'll probably want to break or somehow record the permanent failure instead of just continuing.
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
void findInt(){
int x;
bool ok;
do{
char buff[32], *endp;
long long num;
ok = true;//start true(OK)
printf("Enter a number: ");
fgets(buff, sizeof(buff), stdin);
//strtoll : C99
x=(int)(num=strtoll(buff, &endp, 0));//0: number literal of C. 10 : decimal number.
if(*endp != '\n'){
if(*endp == '\0'){
printf("Too large!\n");//buffer over
while('\n'!=getchar());
} else {
printf("Character that can't be interpreted as a number has been entered.\n");
printf("%s", buff);
printf("%*s^\n", (int)(endp - buff), "");
}
ok = false;
} else if(num > INT_MAX){
printf("Too large!\n");
ok = false;
} else if(num < INT_MIN){
printf("Too small!\n");
ok = false;
}
}while(!ok);
}
,

How can you get characters without the \n?

In my code below I am trying to ignore new lines. Is there a better way of doing this?
do
{
scanf("%c",&wouldCount);
} while(wouldCount == '\n');
original code
#include <stdio.h>
int main()
{
char Yes = 'Y';
char wouldCount;
int counter;
int start;
int end;
int increment;
const END_DEFAULT = 1;
const INCREMENT_DEFAULT = 1;
printf("Would you like to count?");
scanf("%c",&wouldCount);
while(wouldCount == 'Y' || wouldCount == 'y')
{
printf("Please enter start number.");
scanf("%d",&start);
printf("Please enter a number you would like to stop at?");
scanf("%d",&end);
printf("Please enter a number to increment by.");
scanf("%d",&increment);
if(end < start)
{
end = start + END_DEFAULT;
}
if(increment <= 0)
{
increment = INCREMENT_DEFAULT;
}
for(counter = start; counter < end; counter += increment)
{
printf("%d\n",counter);
}
printf("Would you like to count?");
do
{
scanf("%c",&wouldCount);
} while(wouldCount == '\n');
}
return 0;
}
you could change scanf("%c",&wouldCount); to scanf("\n%c",&wouldCount); as well as forgo the do/while loop. This will tell scanf to ignore an enter with no character entered.
see scanf c++ reference

Resources