A (z) stdin felhasználó bemenetét sima C. A probléma az, hogy olyan épelméjű megvalósítást szeretnék, amely robusztus a hibákra, és korlátozza a felhasználót egy bizonyos bemenetre, és nem bonyolult. A get_strings() függvény beolvassa a bemeneti karaktert char, amíg nincs új sor (\n), nincs EOF, és minden karakter áthalad a isalpha() teszt. De szeretnék helyet hagyni. 
Néhány olyan pont, amelyre (szerintem) külön figyelmet érdemel a felülvizsgálat:
-  – Szeretnék megszabadulni a A külső while hurok, amely alapvetően azt teszteli, hogy a felhasználó csak nyomja meg az Enter billentyűt érdemi bevitel nélkül. 
-  – Szükségem van-e még a ferror () használatára? Az fgetc már visszaadja az EOF-et, ha valami nem stimmelt, de én csak hagyja abba az olvasást a folyamról, ahelyett, hogy közölné a felhasználóval, hogy valami rosszul esett. 
-  – Ez nem történik meg mindig, de megtörténik: A \ n a stdin adatfolyamban marad, és amikor legközelebb értelmes információt szeretnék kapni Az fgetc () csak kihagyásra kerül. Itt nincs jelentősége, de igen, ha egyetlen karakterre teszek fel Igen / Nem kérdéseket. Csak egy konstrukcióval tudok megszabadulni ettől a problémától, amely kitisztítja az összes korábbi dolgot, ami maradt a stdin-ben. Lásd erről a második kódblokkot. . 
Szóval, ezt teljesen rosszul kezelem? Vannak-e jobb gyakorlatok, amelyeket befogadhatok? Számomra ez nagyon ügyetlen, és mindig rossz.
/** @brief Contains the dictionary */ static char **strings = NULL; /** @brief Helps with containing the dicionary */ static char *string; /* Reads input char by char with fgetc() */ static char *get_strings() { char *string = NULL; char ch; size_t len = 0; while (string == NULL && ch != EOF) { while (EOF != (ch = fgetc(in_stream)) && ch != "\n") { if (ch != " " && isalpha((int)ch) == 0) { fprintf(stderr, "Only [a-z] is a valid input. | \t" "| Input another or end with CTRL+D: "); continue; } string = (char*) realloc(string, len+2); if (string == NULL) { bail_out(EXIT_FAILURE, "realloc(3) failed"); } string[len++] = toupper(ch); if (len >= MAX_DATA) { bail_out(EXIT_FAILURE, "Input too long\n"); } } if (ferror(in_stream)) { bail_out(EXIT_FAILURE, "Error while reading from stream"); } } if(string) { string[len] = "\0"; } else { printf("\nFinished dictionary...\n"); } printf("Added string: %s | Input another or end with CTRL+D: ", string); return string; } /* Saves the returned strings from get_strings() in a linked list */ static void read_dict() { int index; for (index = 0; (string = get_strings()); ++index) { if (string[0] == "\0") continue; strings = (char**) realloc(strings, (index+1)*sizeof(*strings)); if (strings == NULL) { bail_out(EXIT_FAILURE, "realloc(3) failed"); } strings[index] = string; } /* Take a note of how many entries we have yet. */ dict_size = index; } Második kódblokk egyszerűbb esettel:
while(1) { char tmp; printf("Please enter your guess [a-z]: "); guess = fgetc(stdin); /* Jump back to start of loop */ if (guess == "\n") { continue; } /* HERE IS THE CLEAR FOR STDIN This part really just eats all remaining \ns from the user, so that later inputs can start uninterrupted. Can I get rid of it in some better way? */ while((tmp = getchar()) != "\n" && tmp != EOF); if(!isalpha(guess)) { fprintf(stderr, "Enter a valid letter [a-z]!\n"); continue; } } Megjegyzések
Válasz
Építészet
 stdin általában  sor pufferelt . Tehát semmit nem kap a fgetc(), amíg a felhasználó el nem nyomja az  Enter  gombot. Az OP kód több hibaüzenetet fog megadni, például “Hello 123” bemenettel. Jobb elkülöníteni a felhasználói bemenetet a bemeneti hitelesítéstől. Olvassa el a fgets() vagy a saját verziójának felhasználói beviteli sorát, mivel a fgets() tartalmaz néhány gyengeséget.  Ezután  ellenőrizze a bemenetet. 
char *input; while ((input = my_gets()) != NULL) { if (valid_phrase(input)) { foo(input); } else { fprintf(stderr, "Invalid input\n"); } free(input); }  A “Szeretnék megszabadulni a külső while ciklustól”. Ez a hurok azért létezik, hogy némán elfogyassza a "\n" -t. Ha azt szeretné, hogy egy hurok ezt megtegye, akkor csak a belső hurkot előzte meg a következővel: 
int ch; while ((ch = fgetc()) == "\n") ; ungetc(ch, stdin);   char ch  
 A ch nem a legjobb típus. A fgetc() általában 257 különböző értéket ad vissza [0-255] és EOF. A megfelelő megkülönböztetés érdekében mentse az eredményt egy int fájlba. 
// bad char ch; .. while (string == NULL && ch != EOF) { while (EOF != (ch = fgetc(in_stream)) && ch != "\n") { // better int ch; .. while (string == NULL && ch != EOF) { while (EOF != (ch = fgetc(in_stream)) && ch != "\n") {  Ugyanaz a char tmp; 
  realloc()  
 Az átküldésre nincs szükség. 
 A memória hiánya érdekében módosítsa, hogy szabaddá válhasson string – nem szükséges, ha a kód egyszerűen kilép, mégis jó gyakorlat a játékok (kód “s pointer” away. 
// string = (char*) realloc(string, len+2); char * new_string = realloc(string, len+2); if (new_string == NULL) { free(string); bail_out(EXIT_FAILURE, "Out of memory"); } string = new_string;  Az alábbi sizeof(*strings) megfelelő használata. Egyszerűsítés ajánlása. 
strings = (char**) realloc(strings, (index+1)*sizeof(*strings)); strings = realloc(strings, sizeof *strings * (index+1));   size_t len  
 A size_t megfelelő használata egy tömb méretének képviseletében. Érdekes módon a kód nem ugyanezt teszi a int index; -vel. size_t index; 
  is...()  
 A int ch használatával nincs szükség leadásra. Mivel th Ez egy logikai teszt, javasoljuk a ! használatát az aritmetikai helyett == 0. 
// if (ch != " " && isalpha((int)ch) == 0) { if (ch != " " && !isalpha(ch)) { A következők könnyebben érthetők – kevesebb tagadás. (Stílusprobléma)
if (!(ch == " " || isalpha(ch))) {   ferror()  
 A if (ferror(in_stream)) 
szép ellenőrzése A változónevek
 string, strings ugyanolyan hasznos, mint egy egész szám hívása integer. Talán phrase, dictionary. 
// OK /** @brief Contains the dictionary */ static char **strings = NULL; // Better // comment not truly needed static char **dictionary = NULL;  get_strings() elnevezése rossz. Úgy hangzik, hogy általános, de a kód betűkre és szóközre korlátozza a bevitelt.Lehet, hogy get_words()? 
Megjegyzések
- Úgy érzem, kétszer is ugyanazt a választ adta? Egyébként ez a válasz, amit kerestem! Teljesen az fgetc sind használatára összpontosítottam. A fgets ‘ nt az elején dolgozott (a stdinben lévő gazemberek miatt). Ez sokkal jobbnak tűnik, és ezt beépítem a kódomba. Köszönöm!
- @Haini tudod, hogy az elfogadás mellett válaszon felül is szavazhatsz, ha annyira tetszett 😉
Válasz
Rossz átcsoportosítási stratégia
 Jelenleg minden elolvasott karakternél felhívod az realloc() -t. Ez \ $ O (n ^ 2) \ $ időt eredményez egy karakterlánc elolvasásához, mert minden alkalommal, amikor az realloc() hívást kezdeményezi, előfordulhat, hogy az aktuális tartalmat át kell másolnia az új pufferbe . Vagy el kell osztania egy MAX_DATA méretű puffert, majd a realloc használatával csökkenteni kell a kiosztást a végén, vagy át kell állítani egy átcsoportosítási stratégiára ahol az átcsoportosítás méretét minden alkalommal multiplikatív tényező növeli (például 2x). 
Ez vonatkozik a karakterláncok tömbjére is, ahol ugyanazt csinálja.
Furcsa behúzás
 A behúzásod furcsa, mert a beágyazott while hurok ugyanazon a behúzási szinten van, mint a külső while hurok. 
Használja a fgets () alkalmazást?
 Személyesen használnám a fgets() -et (vagy valamilyen más könyvtárfunkciót, például readline()) karakterlánc elolvasásához. A fgets() nagyjából azt csinálja, amit a hurok minden kézzel kódolt logika nélkül végez. 
stdbool.hszót, de ne használd ‘ ne próbálja meggördíteni a saját booljait.