2016-01-23 70 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,因爲你設置了這個。在我看來,最好的做法是發現其他人需要通過測試和使用代碼來添加,而不是在代碼中「廚房」沉沒,以避免問題發生。