简体   繁体   中英

how to use fgets and sscanf for integers in loop

Beginner with C here. I am trying to run a loop where strings and ints are entered into various fields of a struct . When prompted for a 'last name', the user can press enter with no other input and the loop should end.

The problem is that with this code, the loop doesnt end (last name and first name entry requests run together on the same line) and the value for salary always comes out wrong (0 or some large number)

while (employee_num <= 2)
{
    printf("Enter last name ");
    fgets(employee[employee_num].last_name, sizeof(employee[employee_num].last_name), stdin);                   

    if(strlen(employee[employee_num].last_name) == 0)
        break;

    printf("Enter first name ");
    fgets(employee[employee_num].first_name, sizeof(employee[employee_num].first_name), stdin);

    printf("Enter title ");
    fgets(employee[employee_num].title, sizeof(employee[employee_num].title), stdin);

    printf("Enter salary ");
    fgets(strng_buffer, 1, stdin);
    sscanf(strng_buffer, "%d", &employee[employee_num].salary);     
    ++employee_num;
    getchar();
}

If I try this code instead, I am able to exit the loop properly after the first run through it, but cannot exit after that (by pressing enter at the last name portion - perhaps a \\n I cant seem to clear?):

char strng_buffer[16];
while (employee_num <= 5)
{
    printf("Enter last name ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);                   
    sscanf(strng_buffer, "%s", employee[employee_num].last_name);       

    if(strlen(employee[employee_num].last_name) == 0)
        break;

    printf("Enter first name ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);
    sscanf(strng_buffer, "%s", employee[employee_num].first_name);


    printf("Enter title ");
    fgets(strng_buffer, sizeof(strng_buffer), stdin);
    sscanf(strng_buffer, "%s", employee[employee_num].title);

    printf("Enter salary ");
    scanf("%d", &employee[employee_num].salary);        
    ++employee_num;
    getchar();
}

I am curious as to how to make this work as intended and what best practice would be for entries like this (ie use of sscanf, fgets, etc)

Thanks in advance!

The Loop breaks prematurely when it encounters the break statement

if(strlen(strng_buffer) == 0)
        break;

The uninitialized character buffer strng_buffer , coincidently has null as the first character causing strlen to return 0

I believe you may have intended

if(strlen(employee[employee_num].last_name) == 0)
            break;

as the loop terminatorm, and it was a typo in your part causing premature loop exit.

The problem is that fgets returns the string with the line break ( \\n ) included. So, even the user presses return without entering info, the string won't be empty. Also, your buffer size for salary is too small.

So, either you strip out the \\n on every fgets or you change your check to:

if(strlen(employee[employee_num].last_name) == 1) break;

Also, when you're getting the buffer, change 1 to something bigger, like

fgets(strng_buffer, 10, stdin);

However, if you do want to strip out the \\n from each fgets, you can do something like:

employee[employee_num].last_name[strlen(employee[employee_num].last_name)-1] = 0;

You can do this for every string or, better yet, create a function that does it.

EDIT: if you can guarantee that the user will press enter after each input then you can safely assume this. However if it's not always the case it's possible that the last character is not \\n and just stripping this way might cause problems.

Assuming the fix mentioned by Abhijit, why transform the first into the second? Are you aware that the second behaves differently to the first, because of the addition of sscanf ? If your intention was to shorten the first, the second seems quite bulky. Rather than adding sscanf to the situation, why not shorten the first by declaring a struct employee *e = employee + employee_num; and using that repetitively, instead of employee[employee_num] ?

One "best practise" regarding fgets is to check it's return value. What do you suppose fgets might return, if it encounters EOF ? What do you suppose fgets would return if it's successful?

One "best practise" regarding scanf is to check it's return value. In regards to the return value of scanf , I suggest reading this scanf manual carefully and answering the following questions:

  1. int x = scanf("%d", &employee[employee_num].salary); What do you suppose x will be if I enter "fubar\\n" as input?
  2. Where do you suppose the 'f' from "fubar\\n" will go?
  3. If it's ungetc 'd back onto stdin , what would your next employee's last name be?
  4. int x = scanf("%d", &employee[employee_num].salary); What do you suppose x will be if I run this code on Windows and press CTRL+Z to send EOF to stdin ?
  5. int x = scanf("%d %d", &y, &z); What would you expect x to be, presuming scanf successfully puts values into the two variables y and z ?

PS EOF can be sent through stdin in Windows by CTRL+Z, and in Linux and friends by CTRL+D, in addition to using pipes and redirection to redirect input from other programs and files.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM