0

I have an exercise that I need to create a program to input all information of students as a student report as the source code below. I have a problem that I can't get a full stream input. It stepped over grade input and jumped to another student to input the next student's ID. I have put getchar() to get \n but it does not help. My problem is in the case 1 of the switch, so you just need to care only about it, the other cases do not make any sense in my question.

#include <stdio.h>
#include <string.h>

#define MAX 1000
typedef struct 
{
    char id[10];
    char name[50];
    float grade;
    char assess;
}student;
char assess(int a)
{
    if(a<4.00)
    return 'F';
    if(4.00<=a<6.00)
    return 'D';
    if(6.00<=a<7.00)
    return 'C';
    if(7.00<=a<8.50)
    return 'B';
    if(8.50<=a<10.00)
    return 'A';
}
int main()
{
    int choice;
    int i=0, num=0; 
    int a=0, j=0;
    student std[MAX], temp;
    char search[50];
    do
    {
        printf("Student Report\n");
        printf("1.Input data\n2.Append data\n3.Sort data and print\n4.Search by names5.Quit\n");
        printf("Your choice is: ");
        scanf("%d", &choice);
        switch(choice)
      {
            case 1:
            {
                do{
                printf("How many students you want to add?\n");
                scanf("%d", &num);
                if(num<0 || num>50)
                printf("Your number must be positive or smaller than or equal to 50!\n");
                }while(num<0||num>50);
                for(i=a; i<num; i++)
                {
                    printf("Student's id No.%d:", i);
                    fgets(std[i].id, 10, stdin);
                    getchar();
                    printf("Student's name No.%d:", i);
                    fgets(std[i].name, 50, stdin);
                    getchar();
                    printf("Student's grade No.%d:", i);
                    scanf("%f", &std[i].grade);
                    std[i].assess=assess(std[i].grade);
                }
                a=num;
            }
            case 2:
            {
                do
        {
          printf("How many students you want to append?[0; %d]\n", MAX-num);
          scanf("%d", &num);
                }while(num<0||num>50-a);
                for(i=a; i<num+a; i++)
                {
                    printf("Student's id No.%d:", i);
                    fgets(std[i].id, MAX, stdin);
                    getchar();
                    printf("Student's name No.%d:", i);
                    fgets(std[i].name, MAX, stdin);
                    getchar();
                    printf("Student's grade No.%d:", i);
                    do
            {
              scanf("%f", &std[i].grade);
              if(std[i].grade<0||std[i].grade>10)
            printf("Please re-input grade, it must be between 0 and 10\n");
                    }while(std[i].grade<0||std[i].grade>10);
                    std[i].assess=assess(std[i].grade);
                }
                a=num+a;
            }
            case 3: 
            {
                for(i=0; i<a; i++)
                for(j=0; j<a; j++)
                {
                    if(std[i].grade<std[j].grade)
                    {
                        temp=std[i];
                        std[i]=std[j];
                        std[j]=temp;
                    }
                }
                printf("ID\tName\t\t\tGrade\t\tAssessment\n");
                for(i=0; i<a; i++)
                printf("%-10s%-50s%-10.2f%-10c\n", std[i].id, std[i].name, std[i].grade, std[i].assess);
            }
            case 4:
            {
                printf("Student's name who you want to search: ");
                fgets(search, MAX, stdin);
                getchar();
                for(i=0; i<a; i++)
                if(strcasecmp(search, std[i].name)==0)
                printf("%-10s%-50s%-10.2f%-10c\n", std[i].id, std[i].name, std[i].grade, std[i].assess);
            }
            case 5:
            break;
            default:
            {
                printf("Please reinsert your choice again\n");
                break;
        }
      }
    }while(choice!=5);
    return 0;
}
Hoang Nam
  • 548
  • 3
  • 18

2 Answers2

0

The issue stems from \n not being consumed by scanf at first. To overcome the case I have added while ((c = getchar()) != '\n' && c != EOF);.

To get rid of \n character after fgets's usages, I'd prefer to use strcspn.

case 1:
{
    do{
    printf("How many students you want to add?\n");
    scanf("%d", &num);
    int c;
    while ((c = getchar()) != '\n' && c != EOF);
    if(num<0 || num>50)
    printf("Your number must be positive or smaller than or equal to 50!\n");
    }while(num<0||num>50);

    for(i=a; i<num; i++)
    {
        printf("Student's id No.%d:", i);
        fgets(std[i].id, 10, stdin);
        std[i].id[strcspn(std[i].id, "\n")] = 0;
        printf("Student's name No.%d:", i);
        fgets(std[i].name, 50, stdin);
        std[i].name[strcspn(std[i].name, "\n")] = 0;
        printf("Student's grade No.%d:", i);
        scanf("%f", &std[i].grade);
        std[i].assess=assess(std[i].grade);
    }
    a=num;
    break;
}

Moreover, asses function can be simplified as the following.

char assess(double a)
{
    if(a < 4.00)
        return 'F';
    if(a < 6.00)
        return 'D';
    if(a < 7.00)
        return 'C';
    if(a < 8.50)
        return 'B';
    if(a < 10.00)
        return 'A';
    else
        return -1; // the error indicator to be handled.
}

Further, after each case, you should put break statements. Glance at switch usage.

  • I've edited my program according to your description but my gcc declared error. Is there anything wrong with your program and do you have another way? – Hoang Nam Jan 07 '20 at 05:51
  • You are using `a` as a `float` but declare it as an `int`. (You also have a no-return-value error, so need to add an `else` or other error-handling return value.) – Adrian Mole Jan 07 '20 at 05:53
  • @AdrianMole I didn't give attention, but if-elses. Fixed. Thanks. – Soner from The Ottoman Empire Jan 07 '20 at 05:54
  • My gcc show that: input.c: In function ‘main’: input.c:52:18: warning: passing argument 1 of ‘strcspn’ from incompatible pointer type [-Wincompatible-pointer-types] std[strcspn(std, "\n")] = 0; ^~~ In file included from input.c:2:0: /usr/include/string.h:272:15: note: expected ‘const char *’ but argument is of type ‘student * {aka struct *}’ extern size_t strcspn (const char *__s, const char *__reject) ^~~~~~~ (continue) – Hoang Nam Jan 07 '20 at 05:57
  • error: incompatible types when assigning to type ‘student {aka struct }’ from type ‘int’ std[strcspn(std, "\n")] = 0; ^ warning: passing argument 1 of ‘strcspn’ from incompatible pointer type [-Wincompatible-pointer-types] std[strcspn(std, "\n")] = 0; ^~~ In file included from input.c:2:0: /usr/include/string.h:272:15: note: expected ‘const char *’ but argument is of type ‘student * {aka struct *}’ extern size_t strcspn (const char *__s, const char *__reject) ^~~~~~~ (continue) – Hoang Nam Jan 07 '20 at 05:59
  • input.c:55:30: error: incompatible types when assigning to type ‘student {aka struct }’ from type ‘int’ std[strcspn(std, "\n")] = 0; – Hoang Nam Jan 07 '20 at 05:59
  • Actually @snr you should check your source first, this is very long error – Hoang Nam Jan 07 '20 at 06:00
  • @HoangNam fixed. Did you check? – Soner from The Ottoman Empire Jan 07 '20 at 06:03
  • @snr ok I've checked it and corrected my source code according to your description but I still get that error. I don't know why. Have you ever made an attempt to run this source code? – Hoang Nam Jan 07 '20 at 06:05
  • @HoangNam yes, I run. Check the new version. – Soner from The Ottoman Empire Jan 07 '20 at 06:23
  • @snr I corrected my source code like your newest update. It's ok in the first loop to enter the information of the first student but it's still wrong for the next student – Hoang Nam Jan 07 '20 at 06:32
  • @HoangNam you can find the solution of the issue from now on. I think you should get what is going on. – Soner from The Ottoman Empire Jan 07 '20 at 06:44
0

Based on the recommendation I found here - I am not able to flush stdin

We can use the below snippet to get rid of the junk in the buffer.

int c;
while ((c = getchar()) != '\n' && c != EOF);

Now the question is - where to put it in your program?

Well, I put it in the for loop and got the program to run and read all the three params - viz. ID, name, grade; for several entries of students.

Please check the below modified snippet from your program.

                for(i=a; i<num; i++)
                {
                    int c; // line 1 added
                    while ((c = getchar()) != '\n' && c != EOF); // line 2 added
                    printf("Student's id No.%d:", i);
                    fgets(std[i].id, 10, stdin);
                    printf("Student's name No.%d:", i);
                    fgets(std[i].name, 50, stdin);
                    printf("Student's grade No.%d:", i);
                    scanf("%f", &std[i].grade);
                    std[i].assess=assess(std[i].grade);
                }
Siddharth
  • 321
  • 1
  • 5