Jaki jest najlepszy sposób na uzyskanie informacji od użytkownika w C?
Wiele osób mówiło, że scanf
nie powinno być używane w "poważniejszym programie", tak samo jak w getline
.
Zacząłem się gubić: jeśli każda funkcja wejściowa, którą napotkałem, mówi, że nie powinienem używać żadnej z nich, to czego powinienem użyć? Czy istnieje bardziej "standardowy" sposób uzyskania danych wejściowych, którego nie jestem świadomy?
4 answers
Ogólnie rzecz biorąc, fgets()
jest uważany za dobrą opcję. Czyta całe linie do bufora, a stamtąd możesz zrobić to, czego potrzebujesz. Jeśli chcesz zachowywać się jak scanf()
, możesz przekazać ciągi, które czytasz do sscanf()
.
Główną zaletą tego jest to, że jeśli łańcuch nie zostanie przekonwertowany, łatwo go odzyskać, podczas gdy z scanf()
zostaje Ci wejście na stdin
, które musisz opróżnić. Dodatkowo nie znajdziesz się w pułapce mieszania danych wejściowych zorientowanych liniowo z scanf()
, co powoduje bóle głowy kiedy rzeczy takie jak \n
zostają włączone stdin
, co powoduje, że nowi koderzy sądzą, że wywołania wejściowe zostały całkowicie zignorowane.
Coś takiego może Ci się spodobać:
char line[256];
int i;
if (fgets(line, sizeof(line), stdin)) {
if (1 == sscanf(line, "%d", &i)) {
/* i can be safely used */
}
}
Powyżej należy zauważyć, że fgets()
zwraca NULL
na EOF lub error, dlatego zawinąłem go w if
. Wywołanie sscanf()
Zwraca liczbę pól, które zostały pomyślnie przekonwertowane.
Należy pamiętać, że fgets()
może nie odczytać całej linii, jeśli linia jest większa niż bufor, który w "poważny" program jest z pewnością coś, co należy rozważyć.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 14:11:06
Dla prostego wejścia, gdzie można ustawić stałe ograniczenie długości wejścia, polecam odczyt danych z terminala za pomocą fgets()
.
Dzieje się tak dlatego, że fgets()
pozwala określić rozmiar bufora (w przeciwieństwie do gets()
, który z tego właśnie powodu powinien w zasadzie nigdy {[9] } być używany do odczytu danych od ludzi):
char line[256];
if(fgets(line, sizeof line, stdin) != NULL)
{
/* Now inspect and further parse the string in line. */
}
Pamiętaj, że zachowa np. znak (- y) liniowy (- e), co może być zaskakujące.
UPDATE: jak zaznaczono w komentarzu, jest lepsza alternatywa, jeśli nie masz nic przeciwko odpowiedzialności za śledzenie pamięci: getline()
. Jest to prawdopodobnie najlepsze rozwiązanie ogólnego przeznaczenia dla kodu POSIX, ponieważ nie ma statycznego limitu długości linii do odczytu.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 14:29:48
Istnieje kilka problemów z użyciem scanf
:
-
Odczyt tekstu za pomocą zwykłego specyfikatora Konwersji
%s
wiąże się z takim samym ryzykiem jak użyciegets()
; jeśli użytkownik wpisuje ciąg znaków, który jest dłuższy niż rozmiar przechowywanego bufora docelowego, zostanie przekroczony bufor; -
Jeśli używasz
%d
lub%f
do odczytu danych liczbowych, pewne złe wzorce nie mogą zostać przechwycone i odrzucone całkowicie -- jeśli czytasz liczbę całkowitą z%d
i typami użytkowników"12r4
",scanf
przekonwertuje i przypisze12
pozostawiającr4
w strumieniu wejściowym do następnego odczytu; -
Niektóre specyfikatory konwersji pomijają wiodące białe znaki, inne nie, a nieprzestrzeganie tego może prowadzić do problemów, w których niektóre dane wejściowe są pomijane całkowicie;
W Zasadzie, to wymaga dużo wysiłku , aby kuloodporne odczyty za pomocą scanf
.
Dobrą alternatywą jest odczytanie wszystkich danych wejściowych jako tekstu za pomocą fgets()
, a następnie tokenizowanie i przekonwertować dane wejściowe za pomocą sscanf
lub kombinacji strtok
, strtol
, strtod
, itd.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 14:19:00
Użyj fgets
, aby uzyskać Dane i użyj sscanf
(lub innej metody), aby je zinterpretować.
Zobacz tę stronę, aby dowiedzieć się, dlaczego lepiej jest używać fgets
+ sscanf
zamiast scanf
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-02-14 14:12:58