To często omawianym tematem, pełna opinii, ale tym nie mniej ciekawa. Zauważyłem, że zdecydowana większość tych, którzy już odpowiedział na podobne pytania na tej stronie, przylegają fgets()
. Jestem jednym z nich. Uważam, że fgets()
aby było o wiele lepiej jest użyć dla użytkownika, niż scanf()
z nielicznymi wyjątkami. scanf()
jest uważany przez wielu za неоптимальный metoda przetwarzania danych wejściowych użytkownika. Na przykład
"...on powie ci, czy udało mu się to czy nie, ale może ci mówić tylko w przybliżeniu, gdzie poniósł porażkę, a nie jak, ani dlaczego. Masz
bardzo mało możliwości do poprawki błędów".
(джеймсдлин). Ale w interesie osiągnięcia równowagi, zacznę od tej dyskusji.
Dla użytkownika, który pochodzi od stdin
, czyli wprowadzanie danych z klawiatury, fgets()
będzie najlepszym wyborem. Jest to o wiele bardziej usprawiedliwiony, ponieważ odczytu wiersz może być w pełni zweryfikowane przed próbą przekształcenia
Jeden z niewielu przypadków, kiedy można skorzystać z formularza scanf(): fscanf (), może być stosowany podczas konwersji danych wejściowych z bardzo kontrolowanego źródła, Czyli Podczas czytania ściśle sformatowanego pliku z powtarzających się przewidywalne polami.
Do dalszej dyskusji to porównywanie dwóch z nich podkreśla dodatkowe zalety i wady obu.
Zmiana: w celu rozwiązania dodatkowego pytania o błędzie przepełnienia:
"Jeszcze jedna rzecz, którą chcę zapytać: nawet gdy używamy fgets, co się stanie, jeśli użytkownik wprowadzi więcej znaków granicy (mam na myśli wiele
znaków), czy będzie to prowadzić do przepełnienia bufora? To jak z
tym walczyć?"
[fgets()](https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm dobrze zaprojektowany aby uniknąć przepełnienia bufora, po prostu poprawnie za pomocą jego parametry, np.:
char buffer[100] = {0};
...
while fgets(buffer, sizeof buffer, stdin);
To zapobiega traktowanie wprowadzania dłuższy niż rozmiar bufora, co zapobiega przepełnieniu.
nawet przy użyciu scanf()
zapobieganie przepełnienie buforu dość proste: użyj deskryptor szerokości w pasku formatu. Na przykład, jeśli chcesz przeczytać wprowadzone dane i ograniczyć rozmiar wprowadzania przez użytkownika nie więcej niż 100 znaków, kod będzie obejmować:
char buffer[101] = {0};// includes space for 100 + 1 for NULL termination
scanf("%100s", buffer);
^^^ width specifier
Jednak z numerami przepełnienie nie jest tak przyjemny w użyciu scanf()
. Aby wykazać, ten prosty kod, wprowadzając dwie wartości podane w komentarzu po jednym na start:
int main(void)
{
int val = 0;
// test with 2147483647 & 2147483648
scanf("%d", &val);
printf("%d\n", val);
return 0;
}
Do drugiego znaczenia mój system wydaje się następujący:
NON-FATAL RUN-TIME ERROR: "test.c", line 11, col 5, thread id 22832: Function scanf: (errno == 34 [0x22]). Range error
`
Tutaj trzeba przeczytać wiersz, a następnie przeprowadzić konwersję wiersze na liczbę za pomocą jednego z strto_()
funkcje: strtol(), strtod(), ...). Oba zawierają możliwość sprawdzenia na przepełnienie przed tym, jak spowodować ostrzeżenie lub błąd w czasie wykonywania. Należy pamiętać, że za pomocą atoi()
, atod()
również nie chroni przed zalaniem.