7 WEJŚCIE I WYJŚCIE_______
Ćwiczenie 7.5. Napisz na nowo program kalkulatora przyrostkowego z rozdz. 4, stosując funkcję scanf i być może funkcję sscanf do wczytywania i przekształcania liczb.
W napisanych dotychczas programach dane czytaliśmy wyłącznie ze standardowego wejścia, a wyniki wysyłaliśmy do standardowego wyjścia, przy czym wejście i wyjście były automatycznie udostępniane każdemu programowi przez lokalny system operacyjny.
Następnym krokiem będzie napisanie programu obsługującego plik, który nie został wcześniej dołączony do programu. Jednym z przykładów ilustrujących potrzebę takiej obsługi jest program cat, który do standardowego wyjścia wysyła dane pochodzące z kilku wskazanych, sklejonych ze sobą plików. Program służy do wypisywania zawartości plików na ekranie, a także jako kolektor danych (ogólnego zastosowania) dla programów, które nie potrafią obsługiwać plików wskazanych przez nazwy. Na przykład polecenie
cat x.c y.c
wypisuje do standardowego wyjścia zawartość plików x.C i y.c (i nic więcej).
Nasuwa się pytanie, jak zorganizować czytanie nazwanych plików - to znaczy jak powiązać zewnętrzne nazwy, o które chodzi użytkownikowi, z instrukcjami służącymi do czytania danych.
Sposób jest prosty. Przed czytaniem z pliku lub pisaniem do pliku należy go otworzyć za pomocą bibliotecznej funkcji fopen. Funkcja ta bierze zewnętrzną nazwę (jak x.c lub y.c), robi z nią jakieś sztuczki, następnie przeprowadza jakieś negocjacje z systemem operacyjnym (szczegóły nas nie interesują), a w końcu udostępnia wskaźnik, którego używa się w programie przy późniejszych operacjach czytania z pliku i pisania do pliku.
Ten wskaźnik, nazywany wskaźnikiem pliku, pokazuje na pewną strukturę zawierającą następujące informacje o pliku: położenie bufora, bieżąca pozycja znaku w buforze, rodzaj dostępu do pliku (czytanie, pisanie itp.), sygnały o wystąpieniu błędów lub o napotkaniu końca pliku itd. Użytkownik nie musi znać tych szczegółów, znajdują się one bowiem w strukturze o nazwie FILE, zadeklarowanej w nagłówku <stdio.h>. Niezbędne deklaracje dla wskaźnika pliku demonstruje przykład
FILE *fp;
FILE *fopen(char *name, char *mode);
Mówią one, że fp jest wskaźnikiem do struktury typu FILE i że funkcja fopen zwraca taki wskaźnik. Zauważ, że FILE jest nazwą typu, jak int, a nie etykietką struktur)
7.5 OBSŁUGA PLIKÓW____-
I-by
nlJaPfc§eii O j
- jest zatem zdefiniowana za pomocą typedef. (Szczegóły o tym, jak f można zrealizować w systemie Unix, znajdziesz w p. 8.5.)
W programie wywołanie funkcji fopen ma postać fp = fopen(name, modę);
Pierwszym argumentem fopen jest nazwa pliku. Drugi argument informuje o rodzaju dostępu do pliku, tzn. jak zamierza się korzystać z tego pliku. Wśród dozwolonych rodzajów są: czytanie (”r”), pisanie (”w”) i dopisywanie (”a”). W pewnych systemach rozróżnia się pliki tekstowe i binarne; dla tych ostatnich do rodzaju dostępu należy dołączyć ”b”.
Jeżeli otworzysz do pisania lub dopisywania plik, który nie istnieje, to zostanie on utworzony (o ile będzie to możliwe). Otwarcie istniejącego pliku do pisania powoduje zamazanie jego poprzedniej zawartości, podczas gdy otwarcie do dopisywania chroni ją. Próba czytania z pliku, który nie istnieje, jest błędem. Oczywiście jest wiele innych błędnych sytuacji, choćby próba czytania z pliku bez odpowiednich uprawnień. W przypadku błędu funkcja fopen zwraca NULL. (Błąd ten można zidentyfikować bardziej precyzyjnie - przeczytaj omówienie funkcji obsługi błędów na końcu p. 1 w dodatku B.)
Teraz, gdy plik jest już otwarty, musimy poznać sposoby czytania i pisania. Wyróżnia się ich kilka, z których najprostszym jest użycie funkcji getc i putc. Funkcja getc zwraca kolejny znak wczytany z pliku; w tym celu wymaga wskaźnika mówiącego o jaki plik chodzi.
int getc(FILE *fp)
Zatem getc zwraca kolejny znak ze strumienia znaków wskazanego przez fp, a jako sygnał końca pliku lub wystąpienia błędu zwraca EOF.
Funkcja putc jest funkcją wyjściową:
int putc(int c, FILE *fp)
Funkcja putc zapisuje znak c do pliku wskazanego przez fp i zwraca wartość tego znaku lub EOF jako sygnał wystąpienia błędu. Podobnie jak getchar i putchar, procedury getc i putc mogą nie być funkcjami, lecz makrami.
Przy uruchamianiu programu napisanego w języku C środowisko systemu operacyjnego jest odpowiedzialne za otwarcie trzech plików i udostępnienie programowi ich wskaźników. Plikami tymi są: standardowe wejście, standardowe wyjście oraz standardowe wyjście błędów. Wskaźniki tych plików nazywają się odpowiednio: Stdin, stdout i stderr; są one zadeklarowane w nagłówku <stdio.h>. Normalnie stdin jest związany z klawiaturą, a stdout i stderr z ekranem, ale wskaźniki stdin oraz stdout można przyłączyć do innych plików lub potoków, jak to opisano w p. 7.1.
215