Problems in C code - c

I am trying to make a simple calculator in Turbo C(I have my own reasons to why I use Turbo C now)
#include <stdio.h>
#define P printf
int loop[] = {1, 1, 1, 1};
int num;
char input[64];
void main()
{
int num1, num2;
char x, y;
while(loop[0] == 1)
{
clrscr();
P("Hello!, This simple calculator will help you compute 2 numbers.");
P("\nPress the corresponding key to choose the operation you will use.");
P("\n\nA - (A)ddition");
P("\nS - (S)ubtraction");
P("\nM - (M)ultiplication");
P("\nD - (D)ivision");
P("\n\nAnswer: ");
while(loop[1] == 1)
{
x = getchar();
if(tolower(x) == 'a')
{
P("\nYou have chosen addition.");
num1 = askForNumber("\n\nEnter 1st number: ");
num2 = askForNumber("\nEnter 2nd number: ");
P("\n\n%d + %d = %d", num1, num2, num1+num2);
}
else if(tolower(x) == 's')
{
P("\nYou have chosen subtraction.");
num1 = askForNumber("\n\nEnter 1st number: ");
num2 = askForNumber("\nEnter 2nd number: ");
P("\n\n%d - %d = %d", num1, num2, num1-num2);
}
else if(tolower(x) == 'm')
{
P("\nYou have chosen multiplication.");
num1 = askForNumber("\n\nEnter 1st number: ");
num2 = askForNumber("\nEnter 2nd number: ");
P("\n\n%d * %d = %d", num1, num2, num1*num2);
}
else if(tolower(x) == 'd')
{
P("\nYou have chosen division.");
num1 = askForNumber("\n\nEnter 1st number: ");
num2 = askForNumber("\nEnter 2nd number: ");
P("\n\n%g* %g = %.2f", (float)num1, (float)num2, (float)(num1/num2));
}
else
{
P("\nYou have entered an invalid character!");
P("\n\nAnswer: ");
continue;
}
while(loop[2] == 1)
{
P("\n\nDo you want to do another calculation? Y/N: ");
y = getchar();
if(tolower(y) == 'y' || tolower(y) == 'n')
{
loop[2] = 0;
}
else
{
P("\nYou have entered an invalid character.");
continue;
}
}
loop[1] = 0;
}
if(tolower(y) == 'y')
{
continue;
}
if(tolower(y) == 'n')
{
loop[0] = 0;
}
}
}
int askForNumber(const char *string)
{
P("%s", string);
while(loop[3] == 1)
{
fgets(input, (sizeof(input)/sizeof(input[0]))-1, stdin);
if(sscanf(input, "%d", &num) != 1)
{
num = 0;
P("Invalid number!");
continue;
}
return num;
}
}
I have these bugs:
After I finish a calculation, and press 'Y', it clears the screen non-stop.
After "Enter 1st number: ", the "Invalid number" shows up once even though I haven't typed anything yet(but i can still input a number and it will be saved to 'num1', "Invalid number just bugs me".
At the top where I am to input 'a' or 's' or 'm' or 'd' to choose an operation, if I put some letter except for that above, i get this
OUTPUT:
Answer: o
You have entered an invalid character!
Answer:
You have entered an invalid character!
Answer:
the error shows up twice, but i only typed once.

When there are no characters in the input buffer, the getchar function blocks until the return key is pressed. All keys, including return, are stored in the input buffer, then getchar returns the first character in the buffer. The next call to getchar will immediately return the next character in the buffer.
So if you press 'y' then return, the first call to getchar returns the 'y' character, and the next returns a newline character, i.e. the return key.
You need to flush the input buffer each time you use getchar to skip over the newline:
do {
c = getchar();
} while (c == '\n');

You nedd #include ctype.h to lower is part of that library tolower uses this library and its nowhere in your code

Related

while loop not breaking even with break C programming

Trying to make a GPA calculator.
Here is my code:
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main()
{
float fgpa, grade, n;
char reply;
n = 1;
grade = 1;
printf("--- GPA Calculator ---");
while(fgpa < 1 || fgpa > 4)
{
printf("\n\nEnter your current GPA: ");
scanf("%f", &fgpa);
if(fgpa < 1 || fgpa > 4)
printf("Invalid Input! Please re-enter value.");
}
printf("\nUsing the following table to convert grade to points\n\nA+ = 4.0\nA = 4.0\nB+ = 3.5\nB = 3\nC+ = 2.5\nC = 2.0\nD+ = 1.5\nD = 1\nF = 0\n");
while(grade > 0, n++)
{
printf("\nEnter points for module %.0f, enter \"0\" if there are no more additional modules: ", n);
scanf("%f", &grade);
printf("%f", grade);
fgpa = (fgpa + grade) / n;
}
fgpa = fgpa* n / (n-1);
n--;
printf("\n\nNumber of modules taken: %.0f\nFinal GPA: %.1f", n, fgpa);
return 0;
}
I've tried using if(grade = 0) break; but its still not breaking the loop even when the grade is correctly read 0.
picture of 0 being read correctly but loop still continuing
There are multiple problems in the code:
fgpa is uninitialized so the first test in the loop has undefined behavior.
you should also test the return value of scanf() to detect invalid or missing input.
while (grade > 0, n++) is incorrect too: you should instead always read the next grade and test its value and break from the loop before incrementing n.
Your averaging method seems incorrect too: you do not give the same weight to every module.
It seems more appropriate for your purpose to use for ever loops (for (;;)), unconditionally read input, check for scanf() success and test the input values explicitly before proceeding with the computations.
Here is a modified version:
#include <stdio.h>
// flush the rest of the input line, return EOF at end of file
int flush(void) {
int c;
while ((c = getchar()) != EOF && c != \n')
continue;
return c;
}
int main() {
float fgpa;
float grade;
int n = 1;
char reply;
printf("--- GPA Calculator ---");
for (;;) {
printf("\n\nEnter your current GPA: ");
if (scanf("%f", &fgpa) == 1) {
if (fgpa >= 1 && fgpa <= 4)
break;
}
} else {
if (flush() == EOF) {
fprintf(stderr, "unexpected end of file\n");
return 1;
}
}
printf("Invalid Input! Please re-enter value.\n");
}
printf("\nUsing the following table to convert grade to points\n\n"
"A+ = 4.0\nA = 4.0\nB+ = 3.5\nB = 3\nC+ = 2.5\n"
"C = 2.0\nD+ = 1.5\nD = 1\nF = 0\n");
for (;;) {
printf("\nEnter points for module %d, enter \"0\" if there are no more additional modules: ", n);
if (scanf("%f", &grade) == 1) {
if (grade <= 0)
break;
printf("%f\n", grade);
fgpa = fgpa + grade;
n = n + 1;
} else {
if (flush() == EOF)
break;
printf("Invalid Input! Please re-enter value.\n");
}
}
fgpa = fgpa / n;
printf("\n\nNumber of modules taken: %d\nFinal GPA: %.3f\n", n, fgpa);
return 0;
}

Making a school management system and getting errors

I am new to programming and learning the C language and was practising structures and was trying to make basic school management system by using structures, but I am getting
too many errors (by using pointers in structures). So, can you please tell me what are the errors and how can I avoid these types of mistakes. Because, according to my understanding this should have been working.
Here is my code:
#include <stdio.h>
struct student {
int rollno;
char name[20];
float marks;
};
int main() {
again:;
while (1 == 1) {
struct student array[60];
char input;
int roll;
printf("What you would like to do:\n");
printf("Enter 'R' to fill the details again of all the student\n Enter 'U' to edit the
details of a single student\n");
printf("Enter 'S' to see the details of a particular student\n Enter 'A' to see the
details of every student\n");
scanf("%c", &input);
if (input == 'A' || 'a') {
for (int i = 0; i < 60; i++) {
printf("Roll no. : %d\n Name : %s\n Marks : %f\n", array[i].rollno, array[i].name,
array[i].marks);
}
}
else if (input == 'R' || 'r') {
for (int i = 0; i < 60; i++) {
printf("Roll no. os student is : %d\n", (i + 1));
printf("Enter students name :\n");
gets(array[i].name);
printf("Enter students marks :\n");
scanf("%f", &array[i].marks);
}
}
else if (input == 'S' || 's') {
printf("Enter the roll no. of the student of whom you want to see the details :\n");
scanf("%d", &roll);
printf("Roll no. :\n %d\n", roll);
printf("Name : \n");
puts(array[(roll - 1)].name);
printf("Marks : \n %f \n", (*(array + (roll - 1))->marks));
}
else if (input == 'U' || 'u') {
printf("Enter the roll no. of the student of whom you want to see the details :\n");
scanf("%d", &roll);
printf("Enter the name :\n");
gets((*(array + (roll - 1))->name));
printf("Enter the marks :\n");
scanf("%f", &(*(array + (roll + 1))->marks));
} else {
printf("Error Occured!!! \n");
printf("Re-enter your input\n");
goto again;
}
}
return 0;
}
There are many problems in your code:
there is no need for a goto again;, you already have an infinite loop while (1 == 1), which is usually written for (;;) in C. Don't use goto.
the definition struct student array[60]; should be moved outside the scope of the loop body. As posted, the array is discarded after each iteration and its contents become indeterminate.
array should be initialized to avoid undefined behavior when printing the contents before reading it from the user.
string literals cannot span multiple lines in a C source file. You can split them this way for readability:
printf("What you would like to do:\n"
"Enter 'R' to fill the details again of all the student\n"
"Enter 'U' to edit the details of a single student\n"
"Enter 'S' to see the details of a particular student\n"
"Enter 'A' to see the details of every student\n");
you should have a menu option to quit the program
reading a single character with scanf("%c", &input) is tricky: scanf() will read the pending newline from a previous call. You should use scanf(" %c", &input) where the space will cause pending whitespace to be read and discarded.
if (input == 'A' || 'a') does not test for A or a, it compares input to 'A' and if different compares 'a' to zero, hence the test is always true. You should write:
if (input == 'A' || input == 'a')
gets(array[i].name); is a NO NO. Don't use gets(), throw away the book that tells you to use it. For consistency with the other inputs, you can use
scanf("%19[^\n]", array[i].name);
Note that 19 tells scanf() the maximum number of characters to store into array[i].name before the null terminator, preventing undefined behavior for longer user input, and [^\n] causes scanf() to read and store characters up to and not including the newline character. %19s would stop at any white space, preventing the input of multiple words such as James Bond.
scanf("%f", &(*(array + (roll + 1))->marks)); is a very contorted way to write:
scanf("%f", &array[roll + 1].marks);
you should check the return value of scanf() to detect invalid input and flush the pending input on error.
Here is a modified version:
#include <stdio.h>
struct student {
int rollno;
char name[20];
float marks;
};
int main() {
struct student array[60] = { 0 };
int len = sizeof(array) / sizeof(*array);
int c, i, roll;
char input;
for (;;) {
printf("What you would like to do:\n"
"Enter 'R' to fill the details of all the student\n"
"Enter 'U' to edit the details of a single student\n"
"Enter 'S' to see the details of a particular student\n"
"Enter 'A' to see the details of every student\n"
"Enter 'Q' to quit the program\n");
if (scanf(" %c", &input) != 1)
break;
if (input == 'A' || input == 'a') {
for (i = 0; i < len; i++) {
printf("Roll no.: %d\nName: %s\nMarks: %f\n",
array[i].rollno, array[i].name, array[i].marks);
}
} else
if (input == 'R' || input == 'r') {
for (i = 0; i < len; i++) {
printf("Roll no. os student is: %d\n", i + 1);
printf("Enter student's name:\n");
if (scanf("%19[^\n]", array[i].name) != 1)
break;
printf("Enter students marks:\n");
if (scanf("%f", &array[i].marks) != 1)
break;
}
if (i < len) {
printf("Invalid input\n");
}
} else
if (input == 'S' || input == 's') {
printf("Enter the roll no. of the student of whom you want to see the details:\n");
if (scanf("%d", &roll) == 1 && roll >= 1 && roll <= len) {
printf("Roll no.: %d\nName: %s\nMarks: %f\n",
roll, array[roll - 1].name, array[roll - 1].marks);
} else {
printf("Invalid Roll no\n");
}
} else
if (input == 'U' || input == 'u') {
printf("Enter the roll no. of the student of whom you want to see the details:\n");
if (scanf("%d", &roll) == 1 && roll >= 1 && roll <= len) {
printf("Enter the name:\n");
scanf("%19[^\n]", array[roll - 1].name);
printf("Enter the marks:\n");
scanf("%f", &array[roll - 1].marks);
} else {
printf("Invalid Roll no\n");
}
} else
if (input == 'Q' || input == 'q') {
return 0;
} else {
printf("Invalid entry\n");
printf("Re-enter your input\n");
}
/* read and discard the rest of the input line */
while ((c = getchar()) != EOF && c != '\n')
continue;
}
printf("Premature end of file\n");
return 0;
}

How can I modify program to set array range from 0 to 100 in program below

I need the code below to recognize if the grades entered is below 1 or greater than 100. If it is not within the parameters, I want to let the user know and allow them to enter another grade without exiting the program or losing grades they have already entered. I don't want the program to quit until the user enters q and I want to ensure all of the valid grades entered print at that time. I have tried numerous methods and am not getting the right results. I think I probably need some other else if statement, but I haven't been able to find the right one to work. Any information you can share to get me on the right track would be greatly appreciated.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char choice;
int gradeArray[100];
int grades;
int gCount=0,i;
for(gCount=0; gCount<100; gCount++)
{
//for loop to read the grades till array size
printf("******Enter Choice Selection in Parenthesis******\n Add grades(a)\n Quit(q) \n");
scanf("%c",&choice);
if(choice == 'a' || 'A')
{
//if user choice is a, then read the grade
printf( "Enter grade: ");
scanf("%d", &grades);
getchar();
gradeArray[gCount] = grades; //add the grade to array
}
if(choice == 'q') //if the user choice is q, then exit the loop
{
break;
}
}
printf("Grades are:\n");
for(i=0; i<gCount; i++)
{
printf(" %d%%\n", gradeArray[i]); //print grades
}
return 0;
}
You can do a while loop to verify the user input. With a while you'll be able to force the user to enter the right grade.
if(choice == 'A' || choice == 'a'){
printf("Enter grade:");
scanf("%d", &grades);
getchar();
while(grade < 1 || grade > 100){
printf("You entered a wrong number\n");
printf("Enter a grade between 1 and 100: ");
scanf("%d", &grades);
getchar();
}
gradeArray[gCount] = grades;
}
your solution is almost aligned with what you had in mind. Here is how you can do it differently.
#include <stdio.h>
int main()
{
char choice;
int arraySize = 100; //change this to any number you wish
int gradeScore = 0;
int gradeArray[arraySize];
int gCount = 0;
int showCount = 0;
while(choice != 'q')
{
//to ask for user's input every time
printf("What do you want to do? Enter\n");
printf("'a' to add grades\n");
printf("'q' to quit\n");
scanf(" %c", &choice); //space is entered to ensure the compiler does not read whitespaces
//your implementation should check for user input before proceeding
if(choice != 'a')
{
//in this condition, 'q' is technically an incorrect input but your design states that 'q' is for quitting
//thus, do not alert the user here if 'q' is entered
if(choice != 'q')
{
//a condition to warn the user for incorrect input
printf("Incorrect input. Please enter only 'a' or 'q'\n");
}
}
else if(choice == 'a')
{
printf("Enter grade: \n");
scanf(" %d", &gradeScore);
//to check for user input if the grades entered are less than 1 or more than 100
if(gradeScore < 1 || gradeScore >100)
{
//print a warning message
printf("The grade you entered is invalid. Please enter a grade from 1 - 100\n");
}
//for all correct inputs, store them in an array
else
{
printf("Grade entered\n");
gradeArray[gCount] = gradeScore;
gCount++;
}
}
}
//prints grade when 'q' is entered
if(choice == 'q')
{
printf("Grades are: \n");
for(showCount = 0; showCount < gCount ; showCount++)
{
printf("%d\n", gradeArray[showCount]);
}
}
}
To sum up the important parts, be sure to check for the user grade input to be in range of 1 - 100. Store the grade in the array if it is within range and be sure to increase the array counter, otherwise it will always store it in gradeArray[0] for the subsequent grades. Hope this helps
Use a do-while loop to keep the program looping back to get another choice unless a valid choice has been entered. Use fgetc to read a single character - fewer problems. Only print grades if at least one grade has been entered.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char choice;
int gradeArray[100];
int grades;
int gCount=0,i;
for(gCount=0; gCount<100; gCount++)
{
//for loop to read the grades till array size
printf("******Enter Choice Selection******\n Add grades(a)\n Quit(q) \n");
do
{
choice = fgetc(stdin);
if(choice == 'a' || choice == 'A')
{
//if user choice is a, then read the grade
printf( "Enter grade: ");
scanf("%d", &grades);
getchar();
gradeArray[gCount] = grades; //add the grade to array
}
else if(choice != 'q')
printf("Invalid choice - try again\n");
} while (choice != 'a' && choice != 'A' && choice != 'q');
if(choice == 'q') //if the user choice is q, then exit the loop
break;
}
if(gCount > 0)
{
printf("Grades are:\n");
for(i=0; i<gCount; i++)
printf(" %d%%\n", gradeArray[i]); //print grades
}
return 0;
}

my do-while is terminating instead of continuing my C program

When I'm trying to run without debugging the code everything runs smooth but as soon as I press Y so I can continue inputting numbers it terminates (gotta say I need help)
int main() {
int a;
char c;
do {
puts("dwse mou enan arithmo: ");
scanf_s("%d", &a);
if (a > 0) {
if (a % 2 == 0)
printf("the number %d is even \n", a);
else
printf("the number %d is odd \n", a);
} else {
printf("the program won't run with negative numbers \n");
}
printf("if you want to proceed press y or Y :");
c = getchar();
getchar();
} while (c == 'y' || c == 'Y');
return 0;
}
The character read by getchar() is the pending newline that was typed after the number but was not consumed by scanf_s.
You should consume this pending newline before reading the next character for the continuation test, which can be done easily in scanf with a space before the %c conversion specification:
#include <stdio.h>
int main() {
int a;
char c;
for (;;) {
printf("dwse mou enan arithmo: ");
if (scanf_s("%d", &a) != 1)
break;
if (a >= 0) {
if (a % 2 == 0)
printf("the number %d is even\n", a);
else
printf("the number %d is odd\n", a);
} else {
printf("the program does not accept negative numbers\n");
}
printf("if you want to proceed press y or Y: ");
if (scanf_s(" %c", &c) != 1 || (c != 'y' && c != 'Y'))
break;
}
return 0;
}

How do I make my if statement ask the user to try again if the input is a negative number or a letter?

How do I make my if statement ask the user to try again if the input is a negative number or a letter?
struct foodstuff {
float amount;
};
void add(struct foodstuff *tmpAdd) {
printf("Write amount: ");
scanf("%f", &tmpAdd->amount);
while (tmpAdd->amount != 0) {
if (tmpAdd->amount < -1 || isalpha(tmpAdd->amount)) {
printf("Type in a valid number!\n");
printf("Write amount: ");
getchar();
scanf("%f", &tmpAdd->amount);
getchar();
}
else {
scanf("%f", &tmpAdd->amount);
getchar();
}
}
};
I think you can rephrase your code to use a do loop instead:
do {
printf("Enter a positive number with no characters:\n");
int result = scanf("%f", &tmpAdd->amount);
while (tmpAdd->amount <= 0 || result != 1);
Note that I have removed the call to isalpha(), which acts only a single character at a time. Instead, I propose just checking that the entered number is a valid float and that it is greater than zero. If scanf does not succeed to read in a valid float, then its return value would be not be 1 and the loop would repeat. And the same is the case for entering a valid float which is a negative number.
As chux said, you could first read the input with fgets() and then parse it.
Like
char buff[100], *ptr;
float f;
while(fgets(buff, sizeof(buff), stdin)!=NULL)
{
buff[strlen(buff)-1]='\0';
f=strtof(buff, &ptr);
if(errno==ERANGE)
{
printf("\nPossible overflow.");
errno=0;
continue;
}
if(f<0 || *ptr!='\0')
{
printf("Type in a valid number!\n");
continue;
}
tmpAdd->amount=f;
printf("\n%f", f);
}
Here, fgets() is used to read the input on each iteration. fgets() will return NULL upon error.
The
buff[strlen(buff)-1]='\0';
is done because fgets() will read in the trailing \n into buff as well. We modify that \n to be the \0 character denoting the end of string with buff[strlen(buff)-1]='\0';.
strtof() is used to extract the value from buff.
It is in stdlib.h.
In case buff has something other than numbers, the number part would be converted and returned by strtof() and the ptr pointer would be made to point to the first non-numeric part of buff.
So if the first character in the string pointed to by ptr is the \0 character, there were no non-numeric parts in buff.
If the input value was too large or too small to be accommodated in a float, errno would be set to ERANGE. You need to include errno.h for that.
If overflow (or underflow) occurred, we set errno to 0 and continue.
And (tmpAdd->amount<-1) would be false even if tmpAdd->amount were -1 and -1 is negative. You need (tmpAdd->amount<0) instead.
Also, your loop would exit only when tmpAdd->amount becomes 0. You could simply do
tmpAdd->amount=0;
if that would do.
Otherwise, you can add a
if(f==0)
{
break;
}
at the end of the while loop.
I did some changes to my code, it looks like this now:
printf("Write amount: ");
scanf("%f", &(tmpAdd + index)->amount);
getchar();
do {
if (tmpAdd->amount <= -1 || isalpha(tmpAdd->amount != 0)) {
printf("Type in a valid number!\n");
printf("Write amount: ");
scanf("%f", &(tmpAdd + index)->amount);
getchar();
}
else if (isdigit(tmpAdd->amount >= 0)) {
scanf("%f", &(tmpAdd + index)->amount);
//getchar();
}
} while (tmpAdd->amount <= -1 || isalpha(tmpAdd->amount != 0));
};
Main looks like this:
int main (void) {
int input, noFood = 0;
int flag = 1;
printf("Welcome to the shopping list manager. \n\n");
struct foodstuff food1;
while (flag == 1) {
printf("1 - add food\n");
printf("2 - print shopping list\n");
printf("3 - end\n\n");
printf("What do you want to do? ");
scanf("%d", &input);
clear();
switch (input) {
case 1: add(&food1, noFood); noFood++; break;
case 2: print(&food1, noFood); break;
case 3: printf("\nExiting program\n"); flag = 0; break;
default: printf("Please enter a valid choice\n");
}
}
return 0;
}
And the output like this:
Output
The only problem remaining is that when I want to add another item (add food) for the second time and I type a letter or a negative number, it doesn't run through the if statements.

Resources