How do i fix this error? Switch statement - c

#include <stdio.h>
#include <stdlib.h>
struct student
{
char name[30];
char dob[30];
int rollno;
float percent;
int sub[3];
int total;
};
int main(void)
{
int i, n,a,c,*ptr;
char ch;
struct student *st;
printf("Enter number of students data you want to enter:\n");
scanf("%d",&n);
st=(struct student*) malloc(n * sizeof(struct student));
if(st == NULL)
{
printf("Error! memory not allocated.");
exit(0);
}
for(i=1;i <= n;i++)
{
printf("Enter name of student %d\n",(i));
scanf("%s",&(st+i)->name);
printf("Enter Roll No of student %d\n",(i));
scanf("%d",&(st+i)->rollno);
printf("Enter Date Of Birth of student %d\n",(i));
scanf("%s",&(st+i)->dob);
printf("Enter marks for 3 subjects of student %d\n",(i));
scanf("%d %d %d",&(st+i)->sub[0],&(st+i)->sub[1],&(st+i)->sub[2]);
(st+i)->total = ((st+i)->sub[0]+(st+i)->sub[1]+(st+i)->sub[2]);
printf("Total Marks of student %d = %d\n\n",(i), (st+i)->total);
}
printf("\n");
printf("\n<1>To display details of students\n");
printf("\n<2>exit\n");
printf("Enter your choice:\n");
scanf("%c",&ch);
switch(ch)
{
case '1':
{
for(i=1; i <= n;i++)
{
printf("\n%d.%s",(st+i)->rollno,(st+i)->name);
}
printf("\n Enter Roll no to display info of student");
scanf("%d",&a);
{
c=a;
a=i;
i=c;
if((st+i)->sub[0]<33||(st+i)->sub[1]<33||(st+i)->sub[2]<33)
{
printf("\nName of student: %s",(st+i)->name);
printf("\nRoll No of student: %d",(st+i)->rollno);
printf("\nDate of Birth : %s",(st+i)->dob);
printf("\nTotal of student: %d",(st+i)->total);
printf("\nStudent Status fail");
return 0;
}
printf("\nName of student: %s",(st+i)->name);
printf("\nRoll No of student: %d",(st+i)->rollno);
printf("\nDate of Birth : %s",(st+i)->dob);
printf("\nTotal of student: %d",(st+i)->total);
(st+i)->percent=((st+i)->total)/3;
printf("\nPercent of Student = %f",(st+i)->percent);
if((st+i)->percent>=33)
{
printf("\nStudent status:- PASS\n");
}
else
printf("\nStudent status:-FAIL\n");
if((st+i)->percent>=90)
printf("Grade= A1\n");
else if (80<=(st+i)->percent)
printf("Grade= A2\n");
else if(70<=(st+i)->percent)
printf("Grade= B1\n");
else if(60<=(st+i)->percent)
printf("Grade= B2\n");
else if(50<=(st+i)->percent)
printf("Grade= C1\n");
else if(40<=(st+i)->percent)
printf("Grade= C2\n");
else if(33<=(st+i)->percent)
printf("Grade= D\n");
else if((st+i)->percent<33)
printf("Grade= F\n");
}
break;
}
case '2':
{
return 0;
}
default:
printf("Invalid! Try again...\n");
}
free(st);
return 0;
}
I want my program to take input of various details of students and display them when I enter the roll no. of student. However,
the switch statement is not executing; the program just exits after taking input.
I checked syntax, but it's correct I don't know what the issue is.
If I could get a hint about the issue it would be great.

The problem has nothing to do with the switch statement, but with writing to and reading from to correct memory locations.
In C, arrays start at index 0. Therefore, the first for-loop tries to access memory outside of what is allocated. The idiomatic solution is to start i at 0 and loop while it is strictly less than the size of the array.
Pointer arithmetic not needed here for accessing the array members, and is better replaced by the index operators ([]). More importantly, please have careful look at the types scanf expects and the actual types of the parameters. The name and dob variables are already of the type char* (or char[30] with pointer decay), so they do not need an additional "address of" operator (&). Viewing the compiler warnings helps in catching these kind of errors.
Here is the code with the suggested improvements:
for(i=0;i < n;i++)
{
printf("Enter name of student %d\n",(i));
scanf("%s",st[i].name);
printf("Enter Roll No of student %d\n",(i));
scanf("%d",&st[i].rollno);
printf("Enter Date Of Birth of student %d\n",(i));
scanf("%s",st[i].dob);
// ...
With this resolved, the code now skips past the switch menu because there already is a newline character (\n) in the input which is read by scanf. To skip over leading whitespace (which includes newline characters), add a space character ( ) before the character conversion specifier:
scanf(" %c",&ch);
Inside the switch statement, apply the same fix as earlier to the for-loop:
for(i=0; i < n;i++)
What follows are more invalid reads, probably caused by c=a; a=i; i=c; and I am not sure what the idea behind this is.
Instead of fixing the entire program, I hope that the advice above will help you on your way to resolving the other issues yourself. It may help to write short isolated code snippets first and fully test these (e.g. by writing to certain memory and then reading from it) and afterwards incorporating these snippets into a larger program.
Also, compiling with debug info (the -g flag) and running the program with Valgrind may help you track down where the bugs come from.
Lastly, by careful of using scanf to read strings. Currently, it may cause buffer overflows if the input string is longer than the size of the array written to. Use, e.g., scanf("%29s",st[i].name); to limit the maximum number of characters scanf will read. There is more to reading input safely and predictably than I can write here, so I encourage you to look around on Stack Overflow or elsewhere yourself.

use getchar() instead of scanf(). This is because scanf leaves the newline you type in the input stream. Try
do
ch = getchar();
while (isspace(ch));

Related

Write a program in C to read and print the names of n students of a class

I know this seems a very easy problem but till I am not getting the required output. Please correct any mistakes on asking the question as i am posting question on this site for the first time.
The code I tried is as follows:
#include<stdio.h>
int main()
{
int i, n;
char name[20][80];
printf("\nEnter the number of students: ");
scanf("%d", &n);
printf("\nEnter the name of the students: ");
for(i=0; i<n; i++)
{
fgets(name[i], 80, stdin);
}
printf("\nThe name of the students are: \n");
for(i=0; i<n; i++)
{
puts(name[i]);
}
return 0;
}
But the output is like:
Enter the number of students: 3
Enter the name of students: Park Jimin
Jeon Jungkook
The name of the students are:
Park Jimin
Jeon Jungkook
I can't understand why the number of students became 2 though I mentioned 3.
Please help.
Don't use the scanf family of functions - in my experience they cause more problems than they solve. In this case the issue is that scanf leaves the newline (\n) character in the buffer after you entered the number of students, so a blank line was read the first time your program tried to get a student name. The following should solve your homework problem successfully:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
int i, n;
char buf[20];
char name[20][80];
printf("Enter the number of students: ");
fgets(buf, sizeof(buf), stdin);
n = atoi(buf);
for(i=0; i<n; i++)
{
printf("Enter student name #%d: ", i+1);
fgets(name[i], 80, stdin);
name[i][strlen(name[i])-1] = '\0'; /* overwrite the trailing \n */
}
printf("\nThe names of the students are:\n");
for(i=0; i<n; i++)
printf("name[%d] = \"%s\"\n", i, name[i]);
return 0;
}
OnlineGDB test here
Instead of using fgets and puts use scanf and printf as shown in below code. Below code is working I checked it. You can change it as you want show like with carriage return etc.
int i, n;
char name[20][80];
printf("\nEnter the number of students: ");
scanf("%d", &n);
printf("\nEnter the name of the students: ");
for(i=0; i<n; i++)
{
//fgets(name[i], 80, stdin);
scanf("%s",name[i]);
printf("%d",i);
}
printf("\nThe name of the students are: \n");
for(i=0; i<n; i++)
{
//puts(name[i]);
printf("%d%s",i,name[i]);
}
return 0;
From my pov, the issue here is an unexpected newline character in the input buffer. While this behaviour is known, there are two different approaches to resolve this.
1. Sanitize your inputs:
Simply reading data and working on this data is often a bad idea. Therefore you may want to check, if the data you just got makes sense and is within your expectation. In your example you should never accept an empty name, no matter if comes from buffer artifacts or real user input.
int j = 0;
while(j<n)
{
printf("Write to index: %d", j);
fgets(name[j], 80, stdin);
if (name[j][0] != '\n')
{
j++;
}
}
https://onlinegdb.com/Hy5ZDWq0U
Restructuring your input loop to something like this already gets rid of empty entries. Yet it is not even close to a fully sanitized input as there are numbers, printable and non-printable special characters and length limitations to consider.
The printf("Write to index: %d", j) easily shows you, that the evil newline is still there, but due to our input check it is overridden within the next loop execution. The output loop can remain unchanged and will not print any empty entries anymore.
2. Try to clear the buffer:
Another approach is to clear the buffer in order to get known preconditions before calling fgets or similar functions. Within Using fflush(stdin) you can find a nice discussion on how this can go wrong and why it is rather brittle to do so.
Personally I would always prefer the first over the second solution, as your code should be responsible to handle unexpected inputs according to its needs. Relying on others easily goes wrong, if they do not exactly know, what your expectations are.

Array: issues declaring

I've been trying to convert my python to C code and it's my first time using C.
Basically I want it to ask how many grades I will input and then put them in an array. The problem is that the amount keeps putting in the array. I thought that I could declare the size of the array after asking how many grades I was inputting but I think that's the problem. I am not sure how else to do it. I have a lot of printfs I was using for debugging.
Any Suggestions?
double enter_quiz_grades()
{
int quiz_amount,loop,i;
printf("Enter number of quiz grades to enter:");
scanf(" %d \n", &quiz_amount);
printf("You typed %d students\n",quiz_amount);
double temp=0;
double grades[quiz_amount];
for (loop = 0; loop<quiz_amount;loop++)
{
printf("loop is %d", loop);
i = loop+1;
printf("Enter grade for quiz %d: ",i);
scanf("%lf\n", &temp);
grades[loop] = temp;
printf("%lf",grades[loop]);
}
return 0.0;
}
The problem is you are using '\n' inside scanf. Also you can get rid of additional variables.
Here is the modified code:
double enter_quiz_grades() {
int quiz_amount, i;
printf("Enter number of quiz grades to enter:");
scanf("%d", &quiz_amount);
printf("You typed %d students\n",quiz_amount);
double temp = 0;
double grades[quiz_amount];
for (i = 0; i < quiz_amount; i++)
{
printf("loop is %d\n", i);
printf("Enter grade for quiz %d: ", i + 1);
scanf("%lf", &grades[i]);
printf("%lf\n",grades[i]);
}
return 0.0;
}
Just a small detail, not strictly related to the original question:
double grades[quiz_amount];
This creates an array, sized at runtime, from a variable. If this variable is read from somewhere, this can lead to a malicious user giving it a very high (or ngative!) value, and you are in big problems. The linux kernel is removing them from the source for this exact reason (as this syntax creates the array in the stack - attacker can modify the return address). Make this a dynamic array allocated on the heap (malloc()).
https://www.phoronix.com/scan.php?page=news_item&px=Linux-Kills-The-VLA

how can i impliment a #define statement into my code?

First off, how can I implement a #define in this code? I'm fairly lost when it comes to defining and calling of that #define. Also, if there are any ways to make this code look better it would be greatly appreciated! I'm new to coding so any help would be awsome. This is technically homework but I met all the requirements for the assignment so now this is simply exploratory.
#include <stdio.h>
#include <math.h>
int main() {
int studentID;
int count= 0;
char course1[10]={};//issue with storing user input, used an array
char course2[10]={};
float coursecost1;
float coursecost2;
float credithour = 120.25;
float healthID=35.00;
float totalcost;
// Asks for student ID
printf("Enter the Students Id: \n");
scanf("%d",&studentID);
// Enter CRN/Credit hrs for first course
printf("Enter crn/credit hours for the first course: \n");
scanf("%s", &course1);
// Enter CRN/Credit hrs for Second Course
printf("Enter crn/credit hours for the second course: \n");
scanf("%s", &course2);
// Closing statement
printf("\nThank you!\nPRESS ANY KEY TO CONTINUE...\n\n");
// Calculates Cost of Class
int i = course1[5]-'0'; // Bad version of type casting from char to int.
int k = course2[5]-'0'; // Bad version of type casting from char to int.
coursecost1 = i*credithour;
coursecost2 = k*credithour;
totalcost= healthID+coursecost1+coursecost2;
// Printout
printf("\t\tVALENCE COMMUNITY COLLEGE\n\t\tORLANDO FL 10101\n\t\t");
do{
count++;
printf("*");
}while(count<26);
printf("\n\t\tFee Invoice Prepared for Student V%d\n",studentID);
printf("\t\t1 Credit Hour = %.2f\n",credithour);
printf("\t\tCRN\t CREDIT HOURS\n");
printf("\t\t%c%c%c%c\t %c\t\t $
%.2f\n",course1[0],course1[1],course1[2],course1[3],course1[5],coursecost1);
printf("\t\t%c%c%c%c\t %c\t\t $
%.2f\n",course2[0],course2[1],course2[2],course2[3],course2[5],coursecost2);
printf("\t\t\t Health & id fees $ %.2f\n",healthID);
printf("\t\t");
count=0;
do{ //could define a function to clean up code
count++;
printf("-");
}while (count < 39);
printf("\n\t\t\t Total Payments $ %.2f",totalcost);
return 0;
"define" is basically creating a shortcut for stuff you write often in your code, or stuff you want to change often in order to test your code.
An example:
#define fail printf("You did something wrong")
int main (void)
{
int number;
printf("Insert a number between 1 and 3");
scanf("%d", &number);
if (number>3||number<1)
{
fail;
return -1
}
else
{
printf("Insert a number between 4 and 6");
scanf("%d", &number);
if (number<4||number>6)
{
fail;
return -1;
}
else return 0;
}
}
When this program is read by the compiler, every "fail" gets substituted by "printf("you did something wrong").
This is the main use of define, and if you are beginning now, that's what I'd consider important.
About your code, when you do scanf for strings, don't use "&", or use the "gets" function. I could try to explain why to you, but I'm not the best person for this job. My tip is, keep studying and when you start seeing pointers, you'll understand better why this happens.
Also, when you use arrays without a starting value, you don't need to do the "={ }" thing, just call them without "=".
Now, as you asked, this is how I'd write your code, with the corrections done:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
int studentID, intcount = 0; // Count is a function, better not mix things up, that's why I called it "intcount"
char course1[10], course2[10];
float coursecost1, coursecost2, totalcost;
float credithour = 120.25;
float healthID=35.00;
// Asks for student ID
printf("Enter the Students Id: \n");
scanf("%d",&studentID);
// Enter CRN/Credit hrs for first course
printf("Enter crn/credit hours for the first course: \n");
scanf("%s", course1);
// Enter CRN/Credit hrs for Second Course
printf("Enter crn/credit hours for the second course: \n");
scanf("%s", course2);
// Closing statement
// printf("\nThank you!\nPRESS ANY KEY TO CONTINUE...\n\n");
/* Decided not to delete this one, so you can
compare this printf with the new one and the system pause */
printf("\nThank you!\n");
system("pause");
// Calculates Cost of Class
// I'm not sure what you were trying to do in these lines, so I won't touch them
int i = course1[5]-'0';
int k = course2[5]-'0';
coursecost1 = i*credithour;
coursecost2 = k*credithour;
totalcost= healthID+coursecost1+coursecost2;
// Printout
printf("\t\tVALENCE COMMUNITY COLLEGE\n\t\tORLANDO FL 10101\n\t\t");
do
{
intcount++;
printf("*");
}
while(intcount<26);
printf("\n\t\tFee Invoice Prepared for Student V%d\n",studentID);
printf("\t\t1 Credit Hour = %.2f\n",credithour);
printf("\t\tCRN\t CREDIT HOURS\n");
printf("\t\t%c%c%c%c\t %c\t\t $%.2f\n",course1[0],course1[1],course1[2],course1[3],course1[5],coursecost1);
printf("\t\t%c%c%c%c\t %c\t\t $%.2f\n",course2[0],course2[1],course2[2],course2[3],course2[5],coursecost2);
printf("\t\t\t Health & id fees $ %.2f\n",healthID);
printf("\t\t");
intcount=0;
do
{ //could define a function to clean up code
intcount++;
printf("-");
}
while (intcount < 39);
printf("\n\t\t\t Total Payments $ %.2f",totalcost);
}
Basically just try to avoid placing too much information on the same line, even split single printfs into multiple ones if neccessary.
Hope I could be of some use!

array of struct C scanf with float

hello im trying to work with a struct of students but everytime i ask the input of grade the program stop running and i dont know why. im using Turbo C++ 4.0. if i use grades as int the program doesnt stop but when i use them as float the program stop running. please any help heres the code:
#include<conio.h>
#include<stdio.h>
#define num 2
struct student {
char name[50];
float cal1;
float cal2;
float prom;
} est[num];
int main () {
int i=0;
clrscr();
for(i=0;i<=num;i++) {
printf("\nName of student[%d]:",i);
scanf("%s",&est[i].name);
printf("\nGrade #1 [%d]:",i);
scanf("%f",&est[i].cal1);
printf("\nGrade #2 [%d]:",i);
scanf("%f",&est[i].cal2);
}
for(i=0;i<=num;i++) {
printf("\nStudent [%d]:",i);
printf("\nName: ");
printf("%s",est[i].name);
printf("\nGrade #1: ");
printf("%f",est[i].cal1);
printf("\nGrade #2: ");
printf("%f",est[i].cal2);
}
getch();
return 0;
}
You define:
#define num 2
struct student { … } est[num];
and you loop on:
for (i = 0; i <= num; i++)
{
…scanning code…
}
This is a buffer overflow. It attempts to read 3 students worth of data, with the third student's data going into the space after the space allocated for est. This is a buffer overflow and leads to undefined behaviour; anything can happen and it is OK.
In C, get used to using the idiomatic for loop:
for (i = 0; i < limit; i++)
In the code that reads data, you need to check that the scanf() calls succeed:
printf("\nName of student[%d]:",i);
if (scanf("%s", est[i].name) != 1) // Note no & for strings
…handle error…
printf("\nGrade #1 [%d]:",i);
if (scanf("%f", &est[i].cal1) != 1)
…handle error…
printf("\nGrade #2 [%d]:",i);
if (scanf("%f", &est[i].cal2) != 1)
…handle error…
The printing loop should not attempt to print more entries than were actually read, which might be less than num if there was an error. Obviously, it needs to be in the idiomatic form too, but you should really be using:
int j;
for (j = 0; j < i; j++)
or something similar so if only 1 entry was read, you only print that one entry.
here is an example of the code that
cleanly compiles, links, runs
I did not use conio.h as it is non-standard
(and not available on my machine)
this code still needs the error checking for returned value from scanf added
#include <stdio.h>
//#include <conio.h>
#include <stdlib.h> // system()
#define num (2)
struct student
{
char name[50];
float cal1;
float cal2;
float prom; // only one ';'
};
// separated definition, above, from declaration, below
struct student est[num];
int main ()
{
int i=0;
system( "cls" );
//clrscr();
for(i=0;i<num;i++) // note correction to for statement
{
printf("\nName of student[%d]:",i);
scanf(" %49s", est[i].name); // note correction to format string
// and using array
// as degraded into pointer
// otherwise
// unknown where trying to place data
// added vertical spacing for readability
printf("\nGrade #1 [%d]:",i);
scanf("%f", &est[i].cal1);
// added vertical spacing for readability
printf("\nGrade #2 [%d]:",i);
scanf("%f", &est[i].cal2);
}
for(i=0;i<num;i++) // note correction to 'for' statement
{
printf("\nStudent [%d]:",i);
printf("\nName: ");
printf("%s",est[i].name);
printf("\nGrade #1: ");
printf("%f",est[i].cal1);
printf("\nGrade #2: ");
printf("%f",est[i].cal2);
}
getchar(); // this will input the final newline, so will exit immediately
//getch();
return 0;
} // end function: main

while loop asks user input one time only

#include <stdio.h>
#include <stdlib.h>
struct the_struct
{
char FirstName[20];
char LastName[32];
int Score[20];
};
int main ()
{
int i,n;
struct the_struct *ptr[100];
printf("how many students?\n");
scanf("%d",&n);
while (i<=n);
{
i==0;
ptr[i] = malloc(sizeof(struct the_struct));
printf("Enter First Name \n");
scanf("%s",ptr[i]->FirstName);
printf("Enter Last Name \n");
scanf("%s",ptr[i]->LastName);
printf("Enter Score? \n");
scanf("%s",ptr[i]->Score);
printf("%s %s %s\n",ptr[i]->FirstName,ptr[i]->LastName,ptr[i]->Score);
i++;
}
}
hey guys, so when i enter the first input, it goes only once without going on for the number the user inputs, i tried the for loop but same result.
still learning C so my apology if i misunderstood something.
Thanks in advance.
Your while loop is problematic. You could rewrite it as:
for (i = 0; i < n; ++i)
{
ptr[i] = malloc(sizeof(struct the_struct));
printf("Enter First Name \n");
scanf("%s",ptr[i]->FirstName);
printf("Enter Last Name \n");
scanf("%s",ptr[i]->LastName);
printf("Enter Score? \n");
scanf("%s",ptr[i]->Score);
printf("%s %s %s\n",ptr[i]->FirstName,ptr[i]->LastName,ptr[i]->Score);
}
And since you use %s to read and print Score, you should declare it as char Score[20]; instead of int.
The problem is that i is uninitialized. Therefore, the loop while (i <= n) has undefined behavior, and can end at any time.
Add int i = 0 initializer to fix this problem.
Notes:
i == 0 expression at the beginning of the loop has no effect
Since i starts at zero, your while loop should be while (i < n), not <=.
You should check the results of scanf to see if the user entered something meaningful
You should specify the size of the array into which you read a string, e.g. scanf("%31s",ptr[i]->LastName); This prevents buffer overruns.

Resources