Strona główna » Kursy » Kurs C++ » Alternatywna Obsługa I/O
 

Alternatywna Obsługa I/O

Wstęp

Z pewnością wiele osób na początku patrzyło z przerażaniem na kod wypisujący i wczytujący dane z konsoli. Choć po pewnym czasie używanie cout i cin jest intuicyjne to nie jest to jedyne rozwiązanie na obsługę wypisywania i wczytywania danych. W bibliotece cstdio (lub starszą wersję stdio.h) można znaleźć funkcje scanf() i printf(), które w działaniu są odpowiednikami kolejno cout i cin. Jednak ze względu na ich budowę należało najpierw poznać typy zmiennych i nauczyć się obsługiwać funkcje, aby z nich skorzystać.

Zastosowanie

W celu skorzystania z wymienionych na początku funkcji printf() i scanf() należy pamiętać, aby dołączyć bibliotekę cstdio (lub starszą wersję stdio.h) poprzez odpowiednią dyrektywę preprocesora:

  1. #include <cstdio>

Wypisywanie danych

Tradycyjnie na początek można spróbować wypisać jakiś tekst. W tym celu należy funkcji printf() przekazać w argumencie tekst do wyświetlenia. Wtedy zamieszczony kod

  1.   printf("Witaj swiecie");

wypisze na ekran:

  1. Witaj swiecie

Przypuśćmy, że do wypisania jest wynik dodawania. Wyświetlenie na konsoli wyrażenia 2 + 3 = 5 wiązałoby się z bardzo dużą ilością znaków mniejszości w przypadku korzystania z cout. W przypadku funkcji printf() pierwszy argument to wzór, który jest później uzupełniany kolejnymi argumentami przekazanymi do funkcji. Niestety typ danych nie jest rozpoznawany automatycznie, dlatego należy wskazać jakiego typu jest ten argument. W przypadku liczb całkowitych będzie to %d.

Pisząc kod, który wyświetli podane wcześniej wyrażenie matematyczne należy wpisać następujący kod:

  1.   int a = 2;
  2.   int b = 3;
  3.   printf("%d + %d = %d", a, b, a + b);

Zasada działania programu jest następująca: program wczytuje wzór i natrafia na miejsce gdzie ma wstawić dane tj. pierwsze wystąpienie %d. W tym momencie pobiera pierwszy argument po wzorze i wstawia go zamiast %d. Następnie proces ten jest powtarzany do końca wzoru. W przypadku, gdy argumentów jest mniej niż wstawionych specyfikatorów %[] to program zgłosi wyjątek. Warto zauważyć, że jako argument można przekazywać nie tylko zmienne, ale również wyrażenia do obliczenia. Wywołanie powyższego kodu wypisze na ekran:

  1. 2 + 3 = 5

Budowa wyrażeń

Istnieje wiele różnych specyfikatorów oraz zachowanie części z nich można modyfikować. Ze względu na to, że na początku nie ma potrzeby poznania dokładnie wszystkich możliwych specyfikatorów poniżej znajdują się najczęściej używane w projektach. Szerszy opis specyfikatora znajdzie się w dalszej części kursu.

OznaczenieZastosowanieTyp danych
%dliczba całkowitanp. int, long
%uliczba całkowita bez znakunp. unsigned int, unsigned long
%fliczba rzeczywistanp. float, double
%cznakchar
%słańcuchy znakówchar*, string (i każdy zakończony \0)

W przypadku, gdy chcemy wpisać znak % należy wpisać %%. Podczas pisania wyrażenia można używać poprzednio poznanych znaków specjalnych np. \n, \t. Różny sposób wypisywania danych przedstawia poniższy kod:

  1.   printf("int\t%d\n", 5);
  2.   printf("double\t%f\n", 3.14);
  3.   printf("char\t%c\n", 'a');
  4.   printf("char*\t%s\n", "tekst");
  5.   printf("\n\n");

Wtedy na ekran zostanie wypisane:

  1. int     5
  2. double  3.140000
  3. char    a
  4. char*   tekst

Wczytywanie danych

Funkcją o przeciwnym działaniu do printf() jest scanf(). Używa ona dokładnie tych samych specyfikatorów, ale na ich podstawie odpowiednio rozpoznaje jaki typ danych powinna wczytać. Na początek sugeruje spróbować wczytać dwie liczby całkowite, a potem wypisać ich sumę.

  1.   int a, b;
  2.   scanf("%d %d", &a, &b);
  3.   printf("%d + %d = %d", a, b, a + b);

Podczas (2.) wczytywania danych zmienne należy podać przez referencję. Jest to spowodowane faktem, że program musi wiedzieć gdzie znajduje się zmienna, ale nie jaką ma wartość. Co więcej jeśli przekazana by została wartość zamiast adresu w pamięci to można by nadpisać pamięć w losowym miejscu (na szczęście dziś zabezpieczenia systemów blokują taką możliwość).

Problemu z adresami pamięci nie ma jeśli wczytujemy tekst do zaalokowanej dynamicznie tablicy. Wtedy jest to już tablica wskaźników, więc wystarczy wpisać nazwę zmiennej, bo już wskazuje na adres w pamięci.

  1.   char* dane = new char[32];
  2.   scanf("%s", dane);
  3.   printf("wczytano: %s", dane);
  4.   delete[] dane;

Zastosowanie

Zadanie

Zadanie polega na napisaniu programu, który wczyta ile będzie do rozwiązania równań n, a następnie wczyta n par liczb a b i wypisze ich wyniki w postaci a + b = wynik, gdzie zamiast a i b powinny zostać wyświetlone wartości, a zamiast wynik suma liczb. Przykładowo dla pary 6 5 program powinien wypisać 5 + 6 = 11.

Rozwiązanie

  1. int main() {
  2.   int a, b, n;
  3.   scanf("%d", &n);
  4.   for (int i = 0; i < n; i++) {
  5.     scanf("%d %d", &a, &b);
  6.     printf("%d + %d = %d\n", a, b, a + b);
  7.   }
  8.   printf("\n");
  9.   system("pause");
  10.   return 0;
  11. }

(3.) Wczytaj ile będzie par liczb do wczytania. (4.) Dla każdej pary: (5.) wczytaj parę liczb i (6.) pokaż odpowiednie wyrażenie.

Zadania

Zadanie 1

Napisz program, który wczyta n, a następnie n linijek danych. Każda linijka będzie składała się z dwóch liczb rzeczywistych a, b oraz znaku z. Dla każdej linijki powinien zostać wypisany wynik operacji wskazane przez znak dla wczytanych liczb. Program powinien obsługiwać cztery operatory: + dodawanie, - odejmowania, * mnożenie oraz / dzielenie.

Przykładowo dla danych:

  1. 3
  2. 9.1 6.8 +
  3. 5.4 3.5 -
  4. 91 3 *

Program wypisze na ekran:

  1. 9.100000 + 6.800000 = 15.900001
  2. 5.400000 - 3.500000 = 1.900000
  3. 91.000000 * 3.000000 = 27300000

Nadmiarowe zera można usunąć ustalając odpowiednie modyfikatory, ale o tym będzie w dalszej części kursu. Ponadto wynik 15.900001 jest oczywiście błędem zaokrąglenia danych, a nie wynikiem błędnego działania funkcji wypisującej.