2016-01-23 76 views
-1

gets在函数neuePerson, 中不起作用当它在for循环中时,但后来我改变了它,现在编译器说没有定义。c gets/fgets不能正常工作

我试了fgets,现在没有任何警告,但它仍然忽略fgets,所以我不能在控制台中写任何东西。

main函数的gets工作。我是一个有点困惑...:○

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include "readline.h" 

//typedef struct Person { 
// char name[50]; 
// char unit; 
// int number; 
//} Person; 

typedef struct person { 
    char name[50]; 
    char unit; 
    int number; 
    struct person *next; 
} Person; 

void neuePerson(Person *firstPerson) { 
    time_t t; 
    time(&t); 
    srand((unsigned int)t); 
    while (firstPerson->next != 0) 
     firstPerson = firstPerson->next; 
    printf("Gib einen Namen ein \n"); 
    fgets(firstPerson->name, 50, stdin);       
    firstPerson->number = rand() % 99 + 1; 
    firstPerson->unit = rand() % 3 + 65; 
    firstPerson->next = (Person*)malloc(sizeof(Person)); 
    firstPerson = firstPerson->next; 
    firstPerson->next = 0; 
} 

void ausgabe(Person *anfang) { 
    while (anfang->next != 0) { 
     printf("Name: %s", anfang->name); 
     printf(" Abteilung: %c", anfang->unit); 
     printf(" Tel.Nummer: %i\n", anfang->number); 
     anfang = anfang->next; 
    } 
} 

int main() { 
    Person* pers1 = (Person*)malloc(sizeof(Person)); 
    //Person* test = (Person*)malloc(sizeof(Person)); 
    //gets(test->name, 50); 
    //printf("%s", test->name); 
    pers1->next = 0; 
    char z = 'n'; 
    while (z != 'e') { 
     printf("[n]eue Person, [a]usgabe, [e]nde"); 
     z = getchar(); 
     if (z == 'n') neuePerson(pers1); 
     else if (z == 'a') ausgabe(pers1); 
    } 
} 
+3

千万不要使用gets。它的危险功能http://stackoverflow.com/q/1694036/5339899 – JackVanier

+1

请更具体。 “不起作用”从来不是足够的描述。你是如何得出结论认为它“不起作用”的?它会崩溃吗?错误的输出是否发生?可以 ..?准确描述预期行为和实际行为,包括您已经完成的任何调试结果。 – kaylum

+0

不要用'/ * * /'评论代码,要么在每一行使用'//注释',要么使用#if 0' /'#endif' – chqrlie

回答

2

问题来自标准输入的行缓冲:

您阅读maingetchar()的选项,但返回的字节在您输入回车键之后,您的程序将会显示只有该行的初始字符被返回,剩下的字符保留在流中。

当您随后通过fgets()读取此人的姓名时,它将返回一个空行,因为它获取仍在流中的\n。与流行的看法相反,fflush(stdin)而不是的解决方案,因为它具有未定义的行为。更好的方法是阅读的选项是这样的:

int main() { 
    Person *pers1 = (Person*)malloc(sizeof(Person)); 
    pers1->next = NULL; 
    pers1->unit = 0; 
    pers1->name[0] = '\0'; 
    for (;;) { 
     int z, c; 
     printf("[n]eue Person, [a]usgabe, [e]nde "); 
     z = c = getchar(); 
     while (c != EOF && c != '\n') 
      c = getchar(); 
     if (z == EOF || z == 'e') 
      break; 
     else 
     if (z == 'n') 
      neuePerson(pers1); 
     else 
     if (z == 'a') 
      ausgabe(pers1); 
    } 
} 

你应该提高你的列表操作:空单应该只是NULL,这是不正确的保持一个虚拟初始化结构在列表的末尾待定。您可以通过将头指针传递给neuePerson来处理列表头的更新。

1

我同意chqrlie的回答;此外,不要忘了在你退出while循环主后释放你的列表:

int main() 
{ 
    /** your While loop */ 

    Person *nextp = pers1; 
    do { 
     free(nextp); 
     nextp = nextp->next; 
    } while (nextp != NULL); 
} 

这将是从其他一切分离链表的逻辑是个好主意。你会很高兴你现在做,当你的程序变得更大。

此外,请与valgrind成为好友。

0

首先,既然你问都变得和与fgets,使我从男人页面引用:

不要使用gets()函数。因为事先不知道数据是不可能知道get()将读取多少个字符的,并且因为gets()会继续存储超过缓冲区末尾的字符,所以使用它非常危险。它已被用来破坏计算机安全。使用fgets()代替。

在我回答你的问题之前,我将冒昧地将你的代码重新写入最小集合。您正在测试get,所以我可以在之后删除所有内容,并且之前未调用的代码中的所有内容都会得到。我也会把你的电话从neuePerson移到main。我也会避免堆内存进一步,我相信你会弄清楚如何正确使用堆。最后,我真的不喜欢使用没有退出代码的未初始化的结构或主例程,所以我也会这样做。这看起来是这样的:

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include "readline.h" 

typedef struct person{ 
    char name[50]; 
    char unit; 
    int number; 
    struct person* next; 
} Person; 

int main() { 
    Person _pers1, *pers1 = &_pers1; 
    char z = 'n'; 

    memset(pers1, 0, sizeof(Person)); 

    while (z != 'e') { 
     z = getchar(); 
     pers1->name = fgets(pers1->name, 50, stdin); 
    } 

    return 0; 
} 

在较高的水平,问题是,你有两个方法来处理以不同的方式串。您已经看到了一个解决方案,它采用其中一种方法 - getchar - 并使其像另一种方法一样工作 - 在这种情况下,fgets的缓冲区大小为1。但是,在许多情况下,您没有足够的信息来介绍这两种方法。例如,在这种情况下,如果您根本不知道换行符是否在输入Feed中,或者您正在使用fgets具有可编程停止的语言进行编程,而不是停止换行符,那么您的原始方法可能有更明智。

所以在这种情况下,当两种方法不合作时,通常使用相同的方法是个好主意。这看起来是这样的:

#include <stdio.h> 
#include <stdlib.h> 
#include <time.h> 
#include "readline.h" 

typedef struct person{ 
    char name[50]; 
    char unit; 
    int number; 
    struct person* next; 
} Person; 

int main() { 
    Person _pers1, *pers1 = &_pers1; 
    char z[50]; 

    memset(pers1, 0, sizeof(Person)); 
    memset(z, 0, sizeof(char) * 50); 

    while (z[0] != 'e') { 
     fgets(z, 50, stdin); 
     fgets(pers1->name, 50, stdin); 
    } 

    return 0; 
} 

使Z^50个字节大当然是矫枉过正。我这样做是为了说明一个原则。如果您在任何地方都以相同的方式使用相同的方法,则不会遇到问题。你不需要提问像“等待z需要1或2个字节吗?我应该用2还是1来调用fgets?”。你已经知道“50是我允许输入的最多”。如果最终出现优化原因,您可以稍后再回来优化。

我也想提一提,这是真的,这条线,

while (z[0] != 'e') { 

有一些缺陷。查看“e”以外的值将会更加正确。我建议使用0,EOF,'\ n'和'\ r'。但是你可以预先知道的唯一一个是0,因为你设置了这个。在我看来,最好的做法是发现其他人需要通过测试和使用代码来添加,而不是在代码中“厨房”沉没,以避免问题发生。