fgets() i gets() w programowaniu C

Wprowadzenie do odczytu danych w C

W standardowej bibliotece języka C, funkcje fgets() oraz gets() pełnią rolę narzędzi umożliwiających pobieranie sekwencji znaków z wejścia, jakim najczęściej jest klawiatura. Służą one do wprowadzania danych przez użytkownika lub odczytywania informacji z plików. Mimo podobnego przeznaczenia, funkcje te różnią się w istotny sposób, co ma kluczowe znaczenie dla bezpieczeństwa i poprawności działania programów.

Funkcja fgets() – bezpieczne wczytywanie tekstu

fgets() to funkcja, która pobiera linię tekstu z określonego źródła (np. wejścia standardowego) i umieszcza ją w podanym buforze znakowym. W przypadku powodzenia operacji, zwraca wskaźnik do tego bufora. Jeśli natomiast wystąpi błąd lub zostanie osiągnięty koniec pliku (EOF), zwracana jest wartość NULL.

Składnia funkcji fgets()


char *fgets(char *str, int size, FILE *stream);

Gdzie poszczególne parametry oznaczają:

  • str – adres w pamięci bufora, do którego ma być zapisana odczytana linia znaków,
  • size – maksymalną liczbę znaków, jaką funkcja może odczytać, uwzględniając znak końca linii (\n),
  • stream – wskaźnik na strumień wejściowy, z którego ma być pobierana linia.

Zasady działania funkcji fgets()

1. Proces odczytywania znaków:

  • fgets() przesyła znaki z wejścia do bufora aż do napotkania znaku nowej linii (\n) lub do wyczerpania limitu określonego przez parametr size.
  • Wczytany znak końca linii (\n) zostaje dołączony na końcu zapisanego tekstu w buforze.

2. Obsługa końca pliku (EOF):

  • Jeśli funkcja natrafi na koniec pliku (EOF), zwraca wartość NULL.
  • Bufor znakowy w takim przypadku pozostaje niezmodyfikowany.

3. Reakcja na błędy:

  • W przypadku jakichkolwiek problemów z odczytem danych, takich jak błędy wejścia/wyjścia, fgets() również zwraca NULL.

Przykład wykorzystania fgets()


#include <stdio.h>

int main() {
char bufor[100];
printf("Wprowadź tekst: ");
fgets(bufor, sizeof(bufor), stdin);
printf("Odczytano: %s", bufor);
return 0;
}

Funkcja gets() – mniej bezpieczna alternatywa

gets() to druga z omawianych funkcji, która ma za zadanie wczytać linię tekstu z wejścia standardowego do wskazanego bufora znakowego. Podobnie jak fgets(), zwraca wskaźnik do bufora lub NULL w przypadku błędu lub osiągnięcia końca pliku.

Składnia funkcji gets()


char *gets(char *str);

Gdzie:

  • str – wskaźnik na bufor znakowy, do którego zostanie zapisana wczytana linia tekstu.

Działanie funkcji gets()

1. Wczytywanie znaków:

  • Funkcja gets() przechwytuje znaki z wejścia do bufora, dopóki nie natrafi na znak nowej linii (\n).
  • Ważne jest, że znak końca linii nie jest umieszczany w buforze.

2. Sytuacja osiągnięcia końca pliku (EOF):

  • Jeżeli zostanie osiągnięty koniec pliku (EOF), funkcja gets() sygnalizuje to, zwracając NULL.
  • Bufor znakowy pozostaje wówczas pusty.

3. Obsługa błędów:

  • W przypadku wystąpienia problemów podczas odczytu danych (np. błędy wejścia-wyjścia), funkcja gets() również zwróci NULL.

Przykład użycia gets()


#include <stdio.h>

int main() {
char bufor[100];
printf("Wpisz linię tekstu: ");
gets(bufor);
printf("Wczytany tekst: %s", bufor);
return 0;
}

Porównanie fgets() i gets() – kluczowe różnice

Podstawowa różnica między fgets() a gets() tkwi w sposobie traktowania znaku końca linii oraz w bezpieczeństwie użycia. fgets(), w odróżnieniu od gets(), zachowuje w buforze znak nowej linii, a także umożliwia kontrolę nad ilością wczytywanych znaków. Funkcja gets() jest powszechnie uważana za niebezpieczną ze względu na brak mechanizmu sprawdzającego rozmiar bufora docelowego, co może skutkować przepełnieniem bufora i potencjalnymi problemami z bezpieczeństwem.

Zalecenia – kiedy stosować fgets(), a kiedy gets()?

Zasadniczo, preferowanym rozwiązaniem jest używanie fgets() zamiast gets(). fgets() gwarantuje większe bezpieczeństwo i elastyczność, umożliwiając ustawienie maksymalnej liczby odczytywanych znaków oraz dodając znak końca linii do bufora. gets() może znaleźć zastosowanie jedynie w sytuacjach, gdy wiadomo, że dane wejściowe nie spowodują przekroczenia rozmiaru bufora lub gdy celowo nie chcemy przechowywać znaku końca linii.

Przykłady praktyczne użycia fgets() i gets()

Przykład 1: Wczytanie linii tekstu z fgets()


#include <stdio.h>

int main() {
char bufor[100];
printf("Wprowadź tekst (z dołączonym znakiem nowej linii): ");
fgets(bufor, sizeof(bufor), stdin);
printf("Tekst odczytany przez fgets(): %s", bufor);
return 0;
}

Powyższy kod demonstruje wykorzystanie funkcji fgets() do przechwycenia linii tekstu z wejścia standardowego. Ze względu na ograniczenie rozmiaru bufora do 100 znaków, funkcja odczyta maksymalnie 99 znaków oraz znak końca linii (jeżeli wystąpi).

Przykład 2: Wczytanie linii tekstu z gets()


#include <stdio.h>

int main() {
char bufor[100];
printf("Wprowadź tekst (bez znaku nowej linii): ");
gets(bufor);
printf("Tekst odczytany przez gets(): %s", bufor);
return 0;
}

W tym przypadku, funkcja gets() wczytuje linię tekstu z wejścia standardowego, ale bez limitu liczby znaków. Odczytywanie jest kontynuowane, aż do napotkania znaku końca linii, który nie jest zapisywany w buforze. Z uwagi na brak limitu, wykorzystanie gets() niesie ze sobą ryzyko przepełnienia bufora.

Podsumowanie – wybór właściwej funkcji

Zarówno fgets(), jak i gets(), służą do wczytywania danych z wejścia standardowego w języku C. fgets() jest jednak znacznie bezpieczniejsza i oferuje większą elastyczność, co czyni ją preferowanym wyborem w większości sytuacji. Zrozumienie różnic między tymi funkcjami i stosowanie ich w odpowiedni sposób ma fundamentalne znaczenie dla tworzenia bezpiecznego i niezawodnego kodu.

Najczęściej zadawane pytania (FAQ)

1. Co w przypadku, gdy bufor przekazany do fgets() jest za mały? fgets() pobierze jedynie tyle znaków, ile zmieści się w buforze, i doda znak końca linii. Pozostałe znaki zostaną pominięte.
2. Czy fgets() pobiera białe znaki? Tak, funkcja fgets() wczytuje wszystkie znaki, w tym spacje, tabulatory oraz inne znaki białe.
3. Co oznacza znak końca pliku (EOF)? EOF to specjalny znak, który sygnalizuje koniec strumienia danych, na przykład koniec pliku.
4. Dlaczego fgets() jest uważana za bezpieczniejszą niż gets()? fgets() pozwala na określenie maksymalnej liczby znaków do odczytania, co eliminuje ryzyko przepełnienia bufora, w przeciwieństwie do gets().
5. Kiedy używać fgets(), a kiedy gets()? W większości przypadków, ze względu na bezpieczeństwo i elastyczność, zalecane jest stosowanie fgets(). gets() należy używać z dużą ostrożnością i tylko gdy nie ma obawy o przepełnienie bufora.
6. Czy fgets() może odczytywać linie z pliku? Tak, fgets() jest w stanie czytać dane z pliku, pod warunkiem że plik jest otwarty w trybie odczytu.
7. Czy gets() może pobierać wielowierszowy tekst? Nie, gets() czyta jedynie pojedynczą linię. W przypadku wielowierszowego tekstu należy zastosować pętlę lub funkcję taką jak getline().
8. Czy fgets() dodaje znak końca linii? Tak, fgets() automatycznie dołącza znak nowej linii (\n) na końcu wczytanej linii, chyba że osiągnięto EOF.

newsblog.pl