How to implement gets() or fgets() while using str

2019-06-01 03:05发布

The below code runs perfectly with scanf(), but i want to input characters along with white space. I have tried gets() and fgets() (commented below), but its not working (its skipping to next iteration in the loop & displaying blank(NULL) during output for Name input used by fgets()). Any idea how to do it?

PS: I've tried fputs() with sample programs, its working fine. But i am little confused while using structure pointer.

#include <stdio.h>
#include <stdlib.h>
struct details {
    uint Id;
    char Name[20];
};

int main() {
    int tot, i;
    struct details *info;
    printf("Enter no. of details to be stored = ");
    scanf("%d", &tot);
    info = (struct details *)malloc(tot*sizeof(struct details));

    for(i=0; i<tot; i++) {
        printf("%d)Id = ", i+1);
        scanf("%d", &info->Id);
        printf("%d)Name = ", i+1);
        fgets(info->Name, 20, stdin); //How to make fgets() work??
        //scanf("%s", &info->Name); //works fine with scanf() 
        info++;
    }

    for(i=0; i<tot; i++) {
    --info;
    }

    printf("\nDisplaying details:\n");
    for(i=0; i<tot; i++) {
        printf("%d)Id = %d\n%d)Name = %s\n", i+1, info->Id, i+1, info->Name);
    info++;
    }

return 0;
}

output:

[xyz@xyz:Temp] $ ./fgets_Struct
Enter no. of details to be stored = 2
1)Id = 111
1)Name = 2)Id = 222
2)Name =
Displaying details:
1)Id = 111
1)Name =

2)Id = 222
2)Name =
[xyz@xyz:Temp] $

标签: c struct fgets
4条回答
我命由我不由天
2楼-- · 2019-06-01 03:23

The problem comes from the "%d" scanf. It does not consume the line terminator, so the next read will interpret it as an empty line.

Your info allocation is wrong too. What you should use to allocate the size is not the size of info, but the size of an element pointed to by info.

printf("Enter no. of details to be stored = ");
scanf("%d\n", &tot); // <-- must consume end of line here
info = (struct details *)malloc(tot*
   sizeof(*info)); // <-- use size of the pointed object, not the pointer

Also, tinkering with your info pointer is unnecessary and dangerous.
Something like that would be simpler and safer

for(i=0; i<tot; i++) {
    printf("%d)Id = ", i+1);
    scanf("%d\n", &info[i].Id)); // <-- store input in current info record
                                 // and eat up the line terminator
    printf("%d)Name = ", i+1);
    fgets(info[i].Name,          // <-- idem
          sizeof(info[i].Name),  // fgets will guarantee no buffer overflow
          stdin);
}

printf("\nDisplaying details:\n");
for(i=0; i<tot; i++) {
    printf("%d)Id = %d\n%d)Name = %s\n", i+1, info[i].Id, i+1, info[i].Name);

As for scanf / fgets, in your case (with "%s" format given to scanf), they should both read the input until a new line is entered, spaces included.

EDIT: I said something wrong here, sorry and thanks to chux for correcting me.

scanf ("%s") will indeed stop at the first white space. If you want the whole line, the easiest way is to use fgets. If you really want to use scanf, you'll need a syntax like "%[^\n]%*c".

To make sure your buffer does not overflow if the user types more than 20 characters, you can either

  • use "%19[^\n]%*c" as scanf format (20th character is needed for the '\0' terminator), or
  • use fgets with 20 passed as buffer size (fgets takes care of the terminator, it will read at most 19 characters to be able to add the '\0' without overflowing).

Of course you should use sizeof to compute max buffer size, like for instance:

fgets(info[i].Name, sizeof(info[i].Name), stdin);

Thus you won't have to modify the value if you decide, for instance, to have your buffer size changed to 50 characters.

查看更多
时光不老,我们不散
3楼-- · 2019-06-01 03:23

First, you have a serious bug in your code.

info = (struct details *)malloc(tot*sizeof(info));

sizeof(info) returns either 4 or 8 (depending on the platform, 32 or 64 bit), but has nothing to do with your struct size. So you are allocating memory for pointers, but are using that space for your struct. Writing your data into this will overwrite other data in memory (although probably not in that simple example), because you allocate way too few bytes. What you want to use is sizeof(struct details) which would return 24.

Now to your input problem. Basically, scanf and gets should not be used together like that. The problem is that scanf reads what you type until you press return, which is not included. When you call gets after that, it sees this return and returns immediately with an empty string. If you change all your input calls to gets, it works perfectly. Example:

char test[256];
printf("Enter no. of details to be stored = ");
gets(test);
tot = atoi(test);
查看更多
神经病院院长
4楼-- · 2019-06-01 03:32

I had the same problem! Actually, I came to this page to get the solution and then I remembered the buffer!! So this is the way I solved it:

[...]

cout << "\nType the name: " ;
fflush(stdin); (you always have to clean the buffer before saving chars to a variable)
gets(pers.nom);

[...]

Cheers!! P.S. cin and cout are from C++ but work like scanf and printf

查看更多
Bombasti
5楼-- · 2019-06-01 03:37

between the line scanf() for ID and fgets() put the line getchar() like this

scanf("%d",&(info->Id));
getchar();
查看更多
登录 后发表回答