7 WEJŚCIE I WYJŚCIE______
tabulacji, znak nowego wiersza, znak powrotu karetki, znak tabulacji pionowej i znak nowej strony.)
Znak przekształcenia określa sposób interpretacji pola wejściowego. Odpowiadający temu polu argument musi być wskaźnikiem, jak tego wymaga obowiązujący w języku C mechanizm przekazywania argumentów funkcji przez wartość. Znaki przekształcenia pokazano w tabl. 7.2.
Znaki przekształceń d, i, o, u i X można poprzedzić literą h informującą, że odpowiedni argument nie jest wskaźnikiem do obiektu typu int, tylko typu short, oraz literą I, która mówi, że na liście argumentów powinien wystąpić wskaźnik do obiektu typu long. Podobnie znaki przekształcenia e, f i g można poprzedzić literą I dla argumentów wskaźnikowych do obiektów typu double, a nie float.
Pierwszym z przykładów niech będzie program prymitywnego kalkulatora z rozdz. 4; możemy go napisać inaczej, korzystając z funkcji scanf do przekształcania danych wejściowych:
#include <stdio.h>
main() /* prymitywny kalkulator */
double sum, v; sum = 0;
while (scanf(’’%lf’, &v) == 1) printf(”\t%.2f\n”, sum += v); return 0;
Przypuśćmy, że chcemy wprowadzać wiersze zawierające daty w postaci 25 Grudnia 1988
W tym celu można użyć funkcji scanf:
int day, year; /* dzień, rok */
char monthname[20]; /* nazwa miesiąca */
scanf(”%d %s %d”, &day, monthname, &year);
Argument monthname występuje bez operatora adresu &, ponieważ jako nazwa ta^ licy jest wskaźnikiem.
7.4 FORMATOWANE WEJŚCIE - FUNKCJA SCANF
W formacie mogą występować zwykłe znaki; wówczas muszą literalnie pasowa takich samych znaków z wejścia. Dzięki temu za pomocą wywołania scanf możemy wczytywać daty w postaci mm/dd/yy:
int day, month, year;
scanf(”%d/%d/%d”, &month, &day, &year);
W formacie funkcja scanf ignoruje odstępy i znaki tabulacji. Co więcej, poszukując danych w strumieniu znaków wejściowych, pomija białe plamy (odstępy, znaki tabulacji, znaki nowego wiersza itp.). Często lepiej jest - dla danych o nie ustalonym formacie - najpierw wczytać cały kolejny wiersz, a następnie „wydłubywać” z niego poszczególne kawałki używając funkcji sscanf. Dla przykładu przypuśćmy, że chcemy czytać wiersze, w których data może wystąpić w jednej z obu wyżej podanych postaci. W takim razie możemy napisać
while (getline(line, sizeof(line)) > 0 {
if (sscanf(line, "%d %s %d'\ &day, monthname, &year) == 3) printf(”poprawna: %s\n”, linę); /*format: 25 Grudnia 1988*/ else if (sscanf(line, ”%d/%d/%d”, &month, &day, &year) == 3) printf(”poprawna: %s\n", linę); /*format: mm/dd/yy */ else
printffniepoprawna: %s\n”, linę); /*błędny format*/
Wywołania scanf mogą się przeplatać z wywołaniami innych funkcji wejściowych. Przy kolejnym wywołaniu dowolnej funkcji wejściowej czytanie rozpocznie się od pierwszego znaku, którego scanf jeszcze nie przeczytała.
I końcowe ostrzeżenie: argumenty funkcji scanf i sscanf muszę być wskaźnikami. Zbyt często pojawiającym się błędem jest wywołanie
scanf(”%d'\ n);
zamiast poprawnego scanf(”%d”, &n);
Taki błąd zazwyczaj nie jest wykrywany przez kompilator.
Ćwiczenie 7.4. Napisz prywatną wersję funkcji scanf, analogiczną do minprintf z poprzedniego punktu.
213