Acesta este un frecvent subiect discutat, plin de opinie, dar interesant, nici unul mai puțin. Am observat că o mare parte dintre cei care deja au răspuns la întrebări similare de pe acest site se încadrează pe partea de fgets()
. Eu sunt unul dintre ei. Am găsit fgets()
pentru a fi mult mai bine să utilizați pentru introduse de utilizator decât scanf()
cu câteva excepții. scanf()
este considerat de mulți ca sub-optimă metodă de manipulare de intrare de utilizator. De exemplu
"...vă va spune dacă a reușit sau nu a reușit, dar pot să vă spun doar aproximativ în cazul în care acesta nu a reușit, și nu la toate cum sau de ce. Ai
au foarte puține șanse de a face orice eroare de recuperare."
(jamesdlin). Dar în interesul încercarea de echilibru, va începe citând această discuție.
Pentru o intrare de utilizator, care vine de la stdin
, adică intrare de la tastatură, fgets()
va fi o alegere mai bună. Este mult mai iertator, în care șirul se citește pot fi pe deplin validate înainte de conversie este de încercat
Una dintre cele câteva ori, folosind o formă de scanf(): fscanf() ar fi bine să utilizați ar putea fi atunci când conversia de intrare de la o sursă controlată, adică la o lectură strict fișier formatat cu repetarea previzibil domenii.
Pentru mai multe discutii, această comparație dintre cele două repere suplimentare avantaje și dezavantaje de ambele.
Edit: la adresa OP întrebare suplimentară despre overflow:
"Un singur lucru mai vreau sa va intreb este: chiar și atunci când folosim fgets ce se întâmplă dacă utilizatorul introduce caractere mai mult decât limita (adică o mulțime de
caractere), nu-l duce la buffer overflow? Atunci cum să se ocupe cu
ea?"
[fgets()](https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm este frumos proiectat pentru a preveni buffer overflow, pur și simplu prin utilizarea parametrilor săi în mod corespunzător, de exemplu:
char buffer[100] = {0};
...
while fgets(buffer, sizeof buffer, stdin);
Acest lucru previne de intrare mai mare decât dimensiunea buffer-ului de a fi prelucrate, prevenind astfel preaplin.
chiar folosind scanf()
prevenirea buffer overflow este destul de drept înainte: Utilizați o lățime specificator în șir format. Dacă doriți să citiți de intrare, de exemplu, și o limită de mărime de intrare de la utilizator la 100 de caractere, codul ar include următoarele:
char buffer[101] = {0};// includes space for 100 + 1 for NULL termination
scanf("%100s", buffer);
^^^ width specifier
Cu toate acestea, cu numere, de preaplin nu este atât de frumos, folosind scanf()
. Pentru a demonstra, utilizați acest cod simplu, doar introduceți cele două valori indicate în comentariu pe run:
int main(void)
{
int val = 0;
// test with 2147483647 & 2147483648
scanf("%d", &val);
printf("%d\n", val);
return 0;
}
Pentru cea de-a doua valoare, sistemul meu aruncă următoarele:
NON-FATAL RUN-TIME ERROR: "test.c", line 11, col 5, thread id 22832: Function scanf: (errno == 34 [0x22]). Range error
`
Aici aveți nevoie pentru a citi într-un șir, apoi urmați cu o coardă la numărul de conversie, folosind unul dintre strto_()
funcții: strtol(), strtod(), ...). Ambele includ capacitatea de a testa pentru preaplin înainte provocând un run-time de avertizare sau de eroare. Rețineți că utilizarea atoi()
, atod()
nu va proteja de preaplin fie.