来自 stdin 的 fgets 问题 [C]

发布于 2024-08-24 05:02:44 字数 594 浏览 5 评论 0原文

我正在编写一个处理文件的程序。 我需要能够将数据作为结构输入,并最终将其读出。 我目前遇到的问题是这段代码:

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...*/

例如,如果我想要姓名地址和电话号码,并连续询问每个号码(因此地址与上面几乎相同,除了用地址替换“姓名”),我发现它跳过了输入。我的意思是,我没有机会输入它。输出实际上是 输入姓名: 输入地址:(这里是提示我输入的地方)

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)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陌伤浅笑 2024-08-31 05:02:44

换行符仍在 stdin 中,来自之前对未从输入读取换行符的函数的调用。通过读取直到读出换行符来清除 stdin - 而不是像其他人建议的那样通过刷新 stdin 来清除。

编辑:谢谢 Alok 的更正!

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!

╄→承喏 2024-08-31 05:02:44

我尝试了您的代码,但无法重现该问题。下面的代码按照您期望的方式工作,它提示输入名称,等待您输入名称,然后提示输入地址,等等。

我想知道您是否不需要读取 stdin 并将其清空您提示需要更多输入吗?

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);

   ...    
}

顺便说一句,您想将 strlen(name) 加 1,而不是减 1。或者,如果您希望将 name 存储在记录中而不以空终止,则需要使用 memcpy 将字符串复制到记录中,而不是 strcpy。

编辑:

我从评论中看到您正在使用 scanf 读取选择值,这会在输入缓冲区中留下一个 \n ,然后由您的第一个 fgets 拾取该值称呼。您应该做的是使用 fgets 读取选择行,然后使用 sscanf 解析输入中的值。像这样

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

,应该使刷新标准输入的整个问题变得毫无意义。

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.

故乡的云 2024-08-31 05:02:44

在调用 fgets 读取名称之前,您可能使用 scanf 读取 choicescanf 可能在 stdin 中留下了换行符,您的代码将其误认为是空名称输入。如果确实如此,请尽量不要使用 scanf (使用 fgets 检索 choice 并使用 atoi 来检索转换为 intstrcmp 以与“1\n”等进行比较)。否则,代码应该可以工作,并进行以下修改,以考虑到 fgets 还将终止换行符读入缓冲区(您可能希望将其删除)的事实:

  #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);

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);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文