0
votes

I'm trying to learn structs and I'm using this code

#include <stdio.h>

struct elements
{
    char name[50];
    int semester;
    char  am[15];
}student[100];

void read_struct(struct elements p[]);
int i=0;

main()
{

    for (i=0;i<2;i++)
    {
        read_struct(student);

    }
    for (i=0;i<2;i++)
    {   printf("%d\n",i);
        printf("%s\n",student[i].name);
        printf("%s\n",student[i].am);
        printf("%d\n",student[i].semester);
    }

    system("pause");
}
void read_struct(struct elements p[])
{

    gets(student[i].name);
    gets(student[i].am);
    scanf("%d\n",&student[i].semester);
}

and I face the following problem: during the second iteration when I enter the value for the variable student[1].semester the program doesn't print what I've entered but it waits for me to enter another number,press enter and then it prints. I tried fflush(stdin) after every gets and scanf, and I got the same problem.

2
Indentation fixed. Now why isn't p used into read_struct, and where does student even exist in any of this code. Post real code.WhozCraig

2 Answers

4
votes

Try replacing

scanf("%d\n", &student[i].semester);

with

scanf("%d", &student[i].semester);

In addition to that, fflush(stdin) invokes undefined behaviour, so don't use it.

1
votes

Your code is wrong on so many levels. Instead of just adding a comment pointing them out I will show you a "more correct" way:

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

struct elements
{
    char name[50];
    int semester;
    char  am[15];
};

#define MAX_STUDENTS 2

void read_struct(struct elements *p);

int main(void)
{
    struct elements students[MAX_STUDENTS];  /* No longer global */

    for (size_t i = 0;i < MAX_STUDENTS; ++i)
        read_struct(&students[i]);  /* Pass pointer to single structure */

    for (size_t i = 0;i < MAX_STUDENTS; ++i)
    {
        printf("%ld\n", i);
        printf("%s\n", students[i].name);
        printf("%s\n", students[i].am);
        printf("%d\n", students[i].semester);
    }
}

void read_struct(struct elements *p)
{
    /* fgets is safe, in that it will not overwrite your buffer */
    fgets(p->name, sizeof(p->name), stdin);
    fgets(p->am, sizeof(p->am), stdin);
    scanf("%d", &p->semester);

    /* Skip trailing whitespace (like the newline) in the input buffer
     * left after the `scanf` call above.
     * Do it by reading one character and see if it's a newline. If it's
     * not a newline, then read next character, and so on until we get
     * the newline. It's safe because we *know* there is a newline in the
     * input buffer after the `scanf` call above.
     */
    int c;
    while ((c = fgetc(stdin)) != EOF && c != '\n')
        ;

    /* The `fgets function leaves the newline in the buffer so we
     * have to remove it, if it's there.
     * This is done by first checking if the last character (strlen(...) - 1)
     * is a newline, and if it is then we change that newline to the string
     * terminator character so the string is terminated there.
     */
    if (p->name[strlen(p->name) - 1] == '\n')
        p->name[strlen(p->name) - 1] = '\0';
    if (p->am[strlen(p->am) - 1] == '\n')
        p->am[strlen(p->am) - 1] = '\0';
}

The reason the trailing whitespace doesn't really work is because then the scanf function will continue to read input until it sees something non-whitespace. In this case after you entered the last data, the scanf still wants to read and discard all whitespace, it doesn't know that the user isn't supposed to enter any more input.

You really have to manually read and skip trailing whitespace as done in my program above.