fgets from stdin problems [C]

19,856

Solution 1

I tried your code and can't reproduce the problem. The following code works just the way you would expect, it prompts for the name, wait for you to type the name, then prompts for the address, etc.

I'm wondering if you don't need to read stdin and empty it before you prompt for more input?

typedef struct {
    char* name;
    char* address;
}employeeRecord;

int readrecord(employeeRecord &record)
{
   char name[50];
   char address[100];

   printf("\nenter the name:");
   fgets(name, sizeof(name), stdin);
   record.nameLength = strlen(name) + 1;
   record.name = malloc(sizeof(char)*record.nameLength);
   strcpy(record.name,name);

   printf("\nenter the address:");
   fgets(address, sizeof(address), stdin);

   ...    
}

Incidently, you want to add 1 to strlen(name), not subtract 1. or, if you want name stored in your record without a terminating null, then you need to use memcpy to copy the string into your record, not strcpy.

Edit:

I see from comments that you are using scanf to read the choice value, this is leaving a \n in the input buffer which is then picked up by your first fgets call. What you should do instead is to use fgets to read in the choice line, and then sscanf to parse the value out of the input. like this

int choice;
char temp[50];
fgets(temp, sizeof(temp), stdin);
sscanf(temp, "%d", &choice);

that should make the whole issue of flushing stdin moot.

Solution 2

The newline is still in stdin from a prior call to a function that didn't read a newline from input. Clear stdin by reading until you've read out the newline -- not by flushing stdin as others have suggested.

EDIT: Thanks Alok, for the correction!

Solution 3

You probably used scanf to read choice before calling fgets to read the name. scanf may have left a newline in stdin which your code mistakes for an empty name input. If that is indeed the case, try not to use scanf (use fgets to retrieve choice and use atoi to conver to int or strcmp to compare against "1\n" etc.). The code should otherwise work, with the below modifications to account for the fact that fgets also reads the terminating newline into the buffer (which you probably want stripped):

  #define MY_LENOF(x) (sizeof(x)/sizeof((x)[0])) 

  char choice[3] = { 0 }; /* example of how to initialize to all NULs */
  if (!fgets(choice, MY_LENOF(choice), stdin)) {
    fprintf(stderr, "Premature end of input\n");
    exit(1);
  }

  if (strcmp(choice, "1\n") == 0) {  
    /*Name*/
    printf("\nEnter the name:");
    if (!fgets(name, MY_LENOF(name), stdin)) {
      /* if fgets fails it leaves name unchanged, so we reset it to "" */
      name[0] = '\0';
    }
    /* good practice to use srtnlen in order not to overrun fixed buffer */
    /*  not necessarily a problem with fgets which guarantees the trailing NUL */
    size_t nameLength = strnlen(name, MY_LENOF(name));
    assert(name[nameLength] == '\0');
    if (nameLength - 1 > 0 && name[nameLength - 1] == '\n') {
      /* strip trailing newline */
      name[--nameLength] = '\0';
    } else if (nameLength >= MY_LENOF(name) - 1) {
      fprintf(stderr, "Name is too long\n");
      exit(1);
    } else {
      fprintf(stderr, "Premature end of input\n");
      exit(1);
    }

    record.nameLength = nameLength;
    record.name = malloc(sizeof(char)*(record.nameLength + 1));
    strcpy(record.name, name);
Share:
19,856
Blackbinary
Author by

Blackbinary

CIS Major 1st Year

Updated on June 16, 2022

Comments

  • Blackbinary
    Blackbinary almost 2 years

    I'm writing a program that works with files. I need to be able to input data as structures, and eventually read it out. The problem i have at the moment is with this code:

    typedef struct {
        char* name;
        .....
    }employeeRecord;
    employeeRecord record;
    
    char name[50];
    
    if(choice == 1)
        {
            /*Name*/
            printf("\nEnter the name:");
            fgets(name,50,stdin);
            record.nameLength = strlen(name) -1;
            record.name = malloc(sizeof(char)*record.nameLength);
            strcpy(record.name,name);
            /*Other data, similar format...*/
    

    If i want for example, name address and phone number, and ask for each in a row (so address is pretty much identical to above except replacing 'name' with address), i find it skips the input. What i mean is, I am given no chance to input it. The output is actually Enter the name: Enter the address: (and here is where it prompts me for input)