【问题标题】:C: gets() skips the first input [closed]C:gets()跳过第一个输入[关闭]
【发布时间】:2016-07-27 07:04:19
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>


typedef struct record
{   
    char name[20];
    char surname[20];
    char telephone[20];

}Record;

typedef struct node
{
    Record data;
    struct node *next;
}Node;

Node *head = NULL;

void addRecord(Record s)
{
    Node *newNode;
    Node *n;

    newNode = (Node*)malloc(sizeof(Node));
    newNode->data = s;
    newNode->next = NULL;

    if (head == NULL)
    {
        // The linked list is empty
        head = newNode;
    }
    else
    {
        // Traverse the whole list until we arrive at the last node
        n = head;
        while (n->next != NULL)
        {
            n = n->next;
    }
        n->next = newNode;
    }
}

Record enterRecordDetails()
{
    Record aRecord;
    int len;
    int valid = 0;
    int valid2 = 0;
    printf("ENTER THE FOLLOWING RECORD DETAILS:\n");

    printf("   NAME      : ");
    gets(aRecord.name);
    printf("   SURNAME   : ");
    gets(aRecord.surname);  
    do {
        valid = 0;
        valid2 = 0;
        printf("  TELEPHONE NO. (8 digits): ");
        gets(aRecord.telephone);
        len = strlen(aRecord.telephone);
        for (int i = 0; i < len; i++)
        {
            if (!isdigit(aRecord.telephone[i])) {
                printf("You enterred an invalid number\n");
                valid = 1; break;
            }
        }
        Node *p = head;         
            while (p != NULL)
            {
                Node *next = p->next;
                for (; next; p = next, next = next->next) {
                    if (strcmp(p->data.telephone, aRecord.telephone) == 0)
                    {
                        valid2 = 1; break;
                    }
                }
                if(p = NULL)break;
            }

    } while((valid == 1) || (len != 8) || (valid2 == 1));
    getchar();
    fflush(stdin);
    return aRecord;
}


int main(void)
{
    char menuOption;

    do
    {
        system("cls");
        printf("~~~ MAIN MENU ~~~\n");
        printf("1. Add Telephone Record\n");
        printf("2. Delete Telephone Record\n");
        printf("3. Search\n");
        printf("4. Display All Records\n");
        printf("5. Exit\n\n");
        menuOption = getchar();
        fflush(stdin);
        switch (menuOption)
     {
    case '1':
        addRecordToList();
        break;
    case '4':
        displayList();
        break;
    }

} while (menuOption != '5');

getchar();
return 0;

}

添加学生时,计算机会要求用户输入姓氏而不是姓名。为什么程序会跳过“名称”?会显示“姓名”,但用户应该改写姓氏。

【问题讨论】:

标签: c string input gets


【解决方案1】:

首先,不要使用gets,这是不安全的。请改用fgets

第一次调用gets 跳过一行的原因是在你调用enterRecordDetails() 时缓冲区中有一个'\n'。通常,'\n' 是早期输入操作的剩余部分,例如,使用 scanf 读取 int

解决此问题的一种方法是在读取int时将字符串读到末尾,这样fgets的连续调用就会得到实际数据。您可以在 enterRecordDetails() 函数中执行此操作:

Record enterRecordDetails()
{
    Record aRecord;
    printf("ENTER THE FOLLOWING RECORD DETAILS:\n");
    printf("   NAME      : ");
    fscanf(stdin, " "); // Skip whitespace, if any
    fgets(aRecord.name, 20, stdin);
    printf("   SURNAME   : ");
    fgets(aRecord.surname, 20, stdin);  
}

但是请注意,fgets'\n' 保留在字符串中,只要它适合缓冲区。更好的方法是使用scanf,并传递一个限制输入长度并在'\n'处停止的格式说明符:

scanf(" %19[^\n]", aRecord.name);
//     ^

【讨论】:

  • 如果第一个字符是'\n'scanf("%19[^\n]", aRecord.surname); 不会将任何内容读入aRecord.surname,使其未初始化,并且在stdin 中存在违规的'\n'。这肯定会发生,因为以前的scanf("%19[^\n]", aRecord.name); 不使用'\n'。最好使用fgets()
  • @chux 我对fgets 的唯一保留是将\n 保留在我的字符串中。当然,摆脱那个字符串很容易,但最好一开始就没有它。
  • 我不同意的是使用scanf() 更容易 而不是'\n' 而不是fgets()。 YMMV。
  • 基本上,在 C 中进行明智的基于行的输入的唯一方法是为其编写自己的函数,按照您想要的方式执行(使用 fgetsscanfgetchar或任何内部)。如果您直接使用scanffgets,您的代码会因错误、长行和缓冲区大小处理而变得混乱(或者,更常见的是,这些都没有真正处理,并且在意外输入时会出现问题)。或者,如果您正在为最近的 POSIX 或 GNU OS 编程,请使用 getline...
  • @chux 你是对的,这会弄乱提示。顺便说一句,我同意 hyde 的观点,如果一个人想要做对,他需要自己做,即使用fgets 逐行读取,然后手动解析数据。
猜你喜欢
  • 2013-04-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-17
  • 2016-08-30
  • 2023-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多