Home > Software design >  printing out user's input and next-line is included in the input
printing out user's input and next-line is included in the input

Time:05-11

struct{
  int year;
  int unit;
  int NumberOfSubject;
  float gpa;
  char semester[5];
  char NameOfSubject[60][50];
  char grade;
  char name[40];
}student;

char CreatAccount(void)
{
    int i;
    char ans;
    database= fopen("database.rtf", "w");
    printf("\tThis is registration page\n");
    printf("Please enter your name\n");
    fgets(student.name,40,stdin);
    printf("Is your name %s?, Y/N\n", student.name);
    scanf("%c", &ans);
    if (ans == 'y' || ans == 'Y')
    {
        printf("Registration is successfully completed!. Name on your account is %s",student.name);
        fopen("database.txt", "w");
        for (i=0; student.name[i] != '\n'; i  )
        {
            fputc(student.name[i], database);
        }
        fclose(database);
            
        int i;
        int j;
        printf("Please enter year\n");
        scanf("%d",&(student.year));
        fflush(stdin);
        printf("Please enter semester\n");
        fgets(student.semester,10,stdin);
        printf("Please enter units you have taken\n");
        scanf("%d",&(student.unit));
        printf("Please enter number of subjects you are taking at this moment\n");
        scanf("%d",&(student.NumberOfSubject));
        fflush(stdin);
        for (i=0; i<student.NumberOfSubject; i  )
        {
            printf("Please enter the name of subjects you are taking\n");
            fgets(student.NameOfSubject[i],50,stdin);
            printf("Your %dth Subject is %s\n",i 1,student.NameOfSubject[i]);
        }
        printf("Registration is completed! Here is your information\n\n");
        printf("Your year:%d\n",student.year);
        printf("Semester:%s\n",student.semester);
        printf("Units:%d\n",student.unit);
        for (j=0; j<student.NumberOfSubject; j  )
        {
            printf("Name of subjects:%s",student.NameOfSubject[j]);
        }
        printf("Number of subjects:%d\n",student.NumberOfSubject);
    }

I just can't find the cause of this problem. When the output is printed out, there are things that shouldn't be there. I want to spot what the cause is for this matter. Thanks returnFor instance, if I enter following input

2022 -year

fall-semester

12-units

3-number of subjects

math,english,physics

the output will be this,

Your year:2022

Semester:fall

english // shouldn't be printed

    //shouldn't be next-line space here

Units:12

Name of subjects:english

Name of subjects:math

Name of subjects:physics

Number of subjects:3

CodePudding user response:

fflush(stdin); is undefined behavior.

In fgets() newline character is present at length - 1 position.

Also, never ever mix scanf() with fgets().

size_t len = strlen(str); // str is your string
if(str[len - 1] == '\n')
    str[len - 1] = 0;

Edit: better one

str[strcspn(str, "\n")] = '\0'

CodePudding user response:

There are a couple of issues in your code:

  • You are mixing scanf with fget. They don't work the same way, so you shouldn't use them altogether (unless you are very careful).
  • fflush(stdin) is undefined behaviour. The only way to flush stdin is by reading what's in it.
  • scanf can be a dangerous function if you misuse it (and you clearly are). You need to check its return value and, in case it fails, perform some actions.
  • fgets reads also the newline (the character when you press Enter). You have to replace it with a null-terminator.

I just can't find the cause of this problem.

The last point above explains why.


scanf does not read user input. It parses it. That's what its name says: scan formatted. And scanning may fail, and when it does, it leaves the input buffer intact. So it's up to you to "flush" (i.e. clear, or read-and-discard everything in) it.

void fflush_stdin(void)
{
    scanf("%*[^\n]");
}

Addressing scanf failure is done by checking its return value. From cppreference:

Return value

Number of receiving arguments successfully assigned (which may be zero in case a matching failure occurred before the first receiving argument was assigned), or EOF if input failure occurs before the first receiving argument was assigned.

bool read_char(const char *msg, char *c)
{
    do {
        printf("%s", msg);
        int ret = scanf(" %c", c); // Note the extra space before %c. It means match all space characters before a given character is met.
        switch (ret) {
        case EOF: return false;
        case 1:   return true;
        default:
            flush_stdin();
            printf("Input error.\n");
            break;
        }
    } while (true);
    
    return true; // This won't run.
}

The same thing goes for ints, floats, etc. For scanning strings, you have to provide the length of the char buffer:

char buffer[100];
scanf("           
  •  Tags:  
  • c
  • Related