2013-01-23 18 views
0

初学C这里。我试图运行一个循环,其中字符串和ints被输入到struct的各个字段中。当提示输入“姓氏”时,用户可以不输入其他输入而按回车,循环应该结束。如何在循环中使用fgets和sscanf进行整数

的问题是,这种代码,循环不结束(姓和名条目请求在同一行上同时运行)和工资的价值永远是错的(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等)最佳实践将是什么样的。

在此先感谢!

回答

1

假设Abhijit提到的修复,为什么将第一个转化为第二个?你知道第二个行为与第一个行为不同,因为增加了sscanf?如果你的意图是缩短第一个,那么第二个看起来很庞大。为什么不通过声明struct employee *e = employee + employee_num;并重复使用而不是employee[employee_num]来缩短第一个呢?

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

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

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

P.S. EOF可以通过CTRL + Z在Windows中通过stdin发送,在Linux和朋友中通过CTRL + D发送,除了使用管道和重定向来重定向来自其他程序和文件的输入。

+0

谢谢!通过解决这些问题,使我更好地理解使用scanf()时会发生什么。纠正我,如果我错了,但然后我可以写入标准输入数组并读取int值返回到变量使用sscanf()? – Gitarooman

+0

是的,fgets和sscanf会以这种方式工作。请注意,%s格式说明符告诉sscanf复制* word *(例如,零个或多个非空白字符到第一个空白字符)。剩下的fgets'd行会发生什么?这是你的第二篇文章与第一篇文章不同的一种方式。 – Sebivor

2

的环打破过早当它遇到break语句

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

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

我相信你可能打算

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

作为循环终止符,它在在你的部分ypo导致过早的循环退出。

+0

你是对的(我有点累)。我做了一个编辑,显示了我的两次尝试中的更多代码。尽管如此,我仍然无法让任何一个人正常工作。有人提到使用fgets(),然后sscanf()读取薪水的int部分,但我一直无法找到任何明确的方式在我的搜索中这样做 - 它实际上是一个可行的选择吗? – Gitarooman

1

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

所以,要么你在每一个fgets剥离出\n或者你改变你的支票:

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

而且,当你得到缓冲,更改为1〜更大的东西,像

fgets(strng_buffer, 10, stdin); 

但是,如果你想从每个与fgets剥离出\n,你可以这样做:

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

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

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

+0

fgets并不总是以换行符返回字符串。我建议e-> last_name [strcspn(e-> last_name,“\ n”)] ='\ 0';当'\ n'不存在时处理这些情况,因为你的建议会丢弃一个有用的角色,引入一个错误。 – Sebivor

+0

是的,但我专注于他的用户需要按下输入的情况(并假设不会有EOF)。只需减去1是危险的,因为'strlen'可以返回0.我会更新评论以记录所有这些。 – pldoverflow

+0

char strng_buffer [10]; fgets(strng_buffer,10,stdin);那么当fgets在达到'\ n'之前读取9个字节时呢? – Sebivor