0

这里是 C 初学者。我正在尝试运行一个循环,将字符串和ints输入到struct. 当提示输入“姓氏”时,用户可以在没有其他输入的情况下按回车键,循环应该结束。

问题是,使用此代码,循环不会结束(姓和名输入请求一起在同一行上运行)并且薪水的值总是错误的(0 或某个大数字)

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

如果我改为尝试此代码,我可以在第一次运行后正确退出循环,但之后无法退出(通过在姓氏部分按 enter - 也许是 \n 我似乎无法清除?):

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

我很好奇如何使这项工作按预期进行,以及此类条目的最佳实践是什么(即使用 sscanf、fgets 等)

提前致谢!

4

3 回答 3

2

循环在遇到 break 语句时过早中断

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

未初始化的字符缓冲区strng_buffer,恰好有 null 作为导致strlen返回的第一个字符0

我相信你可能有意

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

作为循环终止符,这是您的拼写错误,导致循环过早退出。

于 2013-01-23T03:35:09.687 回答
1

问题是fgets返回包含换行符(\n)的字符串。因此,即使用户在没有输入信息的情况下按下回车,字符串也不会为空。此外,您的缓冲区大小salary太小。

因此,要么去掉\n每一个,要么fgets将支票更改为:

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

此外,当您获得缓冲区时,将 1 更改为更大的值,例如

fgets(strng_buffer, 10, stdin);

但是,如果您确实想\n从每个 fget 中删除,您可以执行以下操作:

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

您可以为每个字符串执行此操作,或者更好的是,创建一个执行此操作的函数。

编辑:如果您可以保证用户在每次输入后都会按回车键,那么您可以放心地假设这一点。但是,如果并非总是如此,则最后一个字符可能不是\n,仅以这种方式剥离可能会导致问题。

于 2013-01-23T04:27:25.060 回答
1

假设 Abhijit 提到的修复,为什么将第一个转换为第二个?您是否知道第二个的行为与第一个不同,因为添加了sscanf? 如果您的意图是缩短第一个,那么第二个似乎相当庞大。与其增加情况,为什么不通过声明 a并重复使用它来sscanf缩短第一个,而不是?struct employee *e = employee + employee_num;employee[employee_num]

一个“最佳实践”fgets是检查它的返回值。fgets如果遇到 ,您认为可能会返回什么EOFfgets如果成功,您认为会返回什么?

一个“最佳实践”scanf是检查它的返回值。关于 的返回值scanf,我建议仔细阅读scanf手册并回答以下问题:

  1. int x = scanf("%d", &employee[employee_num].salary);如果我作为输入输入,你认为x会是"fubar\n"什么?
  2. 你认为'f'from"fubar\n"会去哪里?
  3. 如果它ungetc'd back to stdin,你的下一个员工的姓是什么?
  4. int x = scanf("%d", &employee[employee_num].salary);x如果我在 Windows 上运行此代码并按 CTRL+Z 发送EOF到,您认为会是什么stdin
  5. int x = scanf("%d %d", &y, &z);x假设scanf成功地将值放入两个变量y和中,您期望是什么z

PSEOF可以stdin通过 CTRL+Z 在 Windows 中发送,在 Linux 和朋友中可以通过 CTRL+D 发送,此外还可以使用管道和重定向来重定向来自其他程序和文件的输入。

于 2013-01-23T04:27:27.190 回答