Programowanie w języku C 2 - instrukcja do laboratorium nr 4
Autor: Mariusz Wiśniewski


  1. Formatowane wyjście - funkcja printf
    Funkcja printf służy do wyświetlania ciągu znaków odpowiednio sformatowanego przy pomocy ciągu znaków formatujących. Format wywołania funkcji jest następujący:

        int printf(char *format, arg1, arg2, ...)

    Funkcja printf na podstawie argumentu format przekształca, formatuje i wypisuje swoje argumenty do standardowego wyjścia. Jej wartością jest liczba wypisanych znaków. Format zawiera dwa typy znaków: zwykłe znaki, które są wyświetlane bez zmian oraz znaki specjalne, które są odpowiednio przekształcane przed wyświetleniem. Każdą specyfikację przekształcenia rozpoczyna się znakiem %, a kończy znakiem charakterystycznym dla tego przekształcenia. Ogólny format operatora przekształcenia jest następujący:

        %[flagi][szerokość][.precyzja][F|N|h|l|L]znak-typu

    Kolejne elementy przekształcenia oznaczają:
    • znaki flag - dodatkowe możliwości (np. wyrównanie lewostronne),
    • szerokość - liczbę wysłanych znaków,
    • precyzję - tzn. liczbę cyfr znaczących,
    • modyfikatory rozmiaru argumentów - zawierają dodatkową informację na temat rozmiaru argumentu i są wykorzystywane w połączeniu ze znakami typu w celu wskazania faktycznego typu argumentu,
    • znaki typu - określają typ argumentów.

    • Znaki typu - liczby całkowite:
      Znak typu Argument wejściowy Postać wyjściowa
      d
      i
      o
      u
      x
      X
      całkowity
      całkowity
      całkowity
      całkowity
      całkowity
      całkowity
      dziesiętna ze znakiem,
      dziesiętna ze znakiem,
      ósemkowa ze znakiem,
      dziesiętna bez znaku,
      szesnastkowa bez znaku (litery: a, b, c, d, e, f),
      j.w. - litery: A, B, C, D, E, F.
    • Znaki typu - liczby zmiennoprzecinkowe:
      e zmiennoprzecinkowy [-]d.ddd...e[+/-]ddd - przed przecinkiem dziesiętnym jedna cyfra, liczba cyfr po przecinku równa precyzji, wykładnik co najmniej dwie cyfry,
      E zmiennoprzecinkowy jak e, ale ze znakiem E dla wykładnika,
      f zmiennoprzecinkowy [-]d.ddd... - liczba cyfr po przecinku równa precyzji,
      g zmiennoprzecinkowy liczba będzie wyświetlana jak e lub f zależnie od zadanej precyji,
      G zmiennoprzecinkowy jak g z tym, że dla oznaczenia wykładnika będzie użyty znak E.
    • Znaki typu - znaki:
      c
      s
      %
      znak
      wskaźnik do łańcucha znaków
      -
      pojedynczy znak,
      znaki łańcucha aż do napotkania znaku „\0”
      drukuje znak %
    • Znaki typu - wskaźniki:
      n int * umieszcza w miejscu wskazanym parametrem liczbę dotychczas wysłanych znaków,
      p wskaźnik drukuje argument w postaci wskaźnika - zależnie od modelu pamięci - seg:off lub off.

    • Modyfikatory - niosą ze sobą dodatkową informację o typie argumentów wejściowych, wskazują na ich rozmiar:
      Modyfikator Działanie
      F
      N
      h
      l

      L
      argument zostanie potraktowany jako daleki wskaźnik, używany ze znakami typu: p, s, n,
      argument będzie traktowany jako wskaźnik bliski, dotyczy tych opcji co w F,
      argument traktuje się jako typ short int dla znaków: d, i, o, u, x, X,
      argument zostanie zinterpretowany jako typu long int dla znaków typu d, i, o, u, x i X; dla znaków e, E, f, g, G jako typ double,
      argument traktowany jako typu long double dla znaków typu e, E, f, g i G.

    • Specyfikatory precyzji - określają ilość miejsc znaczących argumentów liczbowych:
      Specyfikator Precyzja
      nie podano
      przyjmowane są następujące domyślne precyzje:
      - 1 dla znaków typu d, i, o, u, x, X,
      - 6 dla znaków typu e, E, f,
      - wszystkie znaczące cyfry dla znaków typu g i G,
      - łańcuchy są drukowane do pierwszego znaku „\0”, znaków c - nie dotyczy.
      .0 dla znaków typu d, i, o, u, x, X przyjmowana jest precyzja d domyślna; dla znaków e, E i f nie jest drukowany przecinek dziesiętny; liczby o wartości 0 nie będą w ogóle drukowane.
      .n drukowane będzie n znaków lub cyfr dziesiętnych; jeśli wartość wymaga większej liczby znaków, wówczas w zależności od znaku typu nastąpi obcięcie lub zaokrąglenie.
      * lista argumentów zawiera wartość określającą precyzję; wartość ta musi poprzedzać argument, którego dana sekwencja dotyczy.

    • Wpływ specyfikatora precyzji (.n) na konwersję argumentów:
      Znak typu Wpływ na konwersję
      d, i, o, u, x, X n cyfr znaczących zostanie wydrukowanych; jeśli argument wejściowy ma mniej niż n cyfr, wówczas zostanie on z lewej strony uzupełniony zerami; jeśli wartość ma więcej niż n cyfr, wartość wyjściowa nie będzie obcięta.
      e, E, f n cyfr zostanie wydrukowanych po przecinku dziesiętnym; ostatnia drukowana cyfra jest zaokrąglana.
      g, G przynajmniej n cyfr znaczących zostanie wydrukowanych.
      c nie wpływa.
      s co najwyżej n znaków zostanie wydrukowanych.

    • Specyfikator szerokości - określenie minimalnej szerokość dla wartości wyjściowej:
      Specyfikator Wpływ na formatowane dane
      n drukowanych jest przynajmniej n znaków; jeśli wartość zajmuje mniej niż n znaków, zostaną umieszczone dodatkowe spacje z lewej strony lub z prawej strony (jeśli ustawiono odpowiednią flagę).
      0n drukowanych jest przynajmniej n znaków; jeśli wartość zajmuje mniej niż n znaków zostanie ona wypełniona zerami z lewej strony.
      * szerokość pola znajduje się w argumencie poprzedzającym argument z którym związana jest dana sekwencja.

    • Flagi w sekwencjach formatujących:
      Flaga Co określa
      - wyrównanie lewostronnie sytuowaną wartość, umieszczając z prawej strony odpowiednią liczbę spacji.
      + jeśli wyświetlana jest liczba ze znakiem, wówczas zostanie przed nią umieszczony znak + lub -, w zależności od jej wartości.
      spacja jeśli wartość jest nieujemna, zamiast plus będzie wyświetlana spacja; w przypadku wartości ujemnych wyświetlany będzie -.
      # wpływ tej flagi zależy od tego z jakim znakiem typu jest związana (poniższa tabela).

    • Wpływ flagi # w zależności od znaku typu:
      Znak typu Wpływ flagi #
      c, s, d, i, u nie wpływa.
      0 zero będzie dołączanie do niezerowych argumentów.
      x lub X 0x lub 0X będzie dołączone do argumentów.
      e, E, f przecinek dziesiętny będzie wyświetlany niezależnie od tego, czy wystąpią po nim jakieś cyfry.
      g (G) tak jak powyżej z tym, że końcowe zera nie będą usuwane.

    Przykład użycia:

        int drukuj_info(char *nazwisko, char *imie1, char *imie2, int wiek, int czas_pracy, int stawka_za_godzinę)
        {
            return printf("%-15s %-10s %-10s %2d %3d %5.2lf zł\n", nazwisko, imie1, imie2, wiek, czas_pracy, stawka_za_godzinę);
        }

    Funkcja printf ma implementacje operujące także poza standardowym wyjściem:

        int fprintf(FILE *stream, const char *format, ...);
        int sprintf(const char *buffer, const char *format, ...);

  2. Zadanie do samodzielnego wykonania
    Korzystając z powyższych informacji należy przygotować program pozwalający na sprawdzenie każdej z możliwości oferowanej przez funkcję printf. Program powinien mieć możliwość wyboru jednego lub wielu parametrów na raz.