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 parametrsize
.- 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ż zwracaNULL
.
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ącNULL
. - 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óciNULL
.
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