Programowanie w Visual C++ 2010

Spis treści

Formatowanie napisów w konsoli

Wprowadzenie

Często zachodzi potrzeba wyświetlenia w konsoli różnego rodzaju informacji w estetyczny sposób. Dla przykładu, jeśli naszym zadaniem jest wypisanie wartości funkcji sinus wyznaczonej w różnych punktach, warto jest przedstawić wyniki w postaci tabelki. Na szczęście, twórcy języka C++ zaopatrzyli nas w narzędzia, które pozwolą nam dostosować formatowanie wyświetlanych komunikatów do naszych potrzeb.

Gdy w tym samouczku zobaczysz fragment programu, najpierw samodzielnie go skompiluj i domyśl się, jaki będzie efekt działania poszczególnych instrukcji. Warto też będzie nieco poeksperymentować na własną rękę, aby wprawić się w używaniu konkretnych konstrukcji. Powodzenia!

Te specjalne narzędzia są dostępne w znanej już bibliotece <iostream> oraz w bibliotece <iomanip>. Zostaną one przedstawione w tym samouczku.

Jednak zanim zaczniemy korzystać z tych możliwości, musimy poznać nowe pojęcie:

Manipulator to specjalna funkcja (obiekt) pozwalająca na formatowanie tekstów w konsoli. Jest ona "wysyłana" do obiektu cout celem zmienienia jego aktualnego stanu.

Okazuje się, że w naszej programistycznej przygodzie już nieraz korzystaliśmy z pewnego tajemniczego "manipulatora". Przyjrzyjmy się poniższej, dobrze znanej linijce kodu:

   cout << "Hello World!" << endl;

Przypomnijmy, że ta instrukcja powoduje wyświetlenie w konsoli napisu Hello World! i "przejście" do następnego wiersza. Tak, dobrze się domyślasz. To właśnie dzięki manipulatorowi endl (od ang. "end line", czyli zakończ linię/wiersz) możliwe jest wyświetlanie kolejnych komunikatów już w nowej linii.

Znaki specjalne

Na początek sprawdź, jaki będzie efekt wykonania poniższych instrukcji:
   cout << "Hello World!\n";
   cout << "Hello\tWorld!";

Backslash (\, czasem tłumaczony jako wtyłciach) wraz z następują po nim literą stanowią tzw. znak specjalny (właść. ang. escape character). Tego typu znaków jest kilkanaście, najczęściej będziemy używać tych z poniższej tabelki:

Znak Znaczenie
\n nowa linia
\t tabulator poziomy
\" cudzysłów
\' apostrof
\\ backslash
\0 znak NULL (bajt zerowy)

Zauważ, że podczas pisania programu, wstawienie znaku cudzysłowu powoduje, że kompilator wie, iż w danym miejscu kończy się napis do wyświetlenia. Dlatego używa się znaku specjalnego \", aby w konsoli wyświetlał się cudzysłów.

W miarę możliwości używajmy raczej manipulatora endl niż znaku specjalnego \n. Dzięki temu kod programu będzie znacznie bardziej czytelny.

Manipulatory w bibliotece <iostream>

Liczby całkowite: zmiana podstawy systemu liczbowego

Jak już wiesz z drugiego wykładu, programiści (i twórcy komputerów) bardzo lubią liczby będące potęgami dwójki, a przede wszystkim 8 i 16. Dlatego umożliwili oni wyświetlanie liczb w systemach liczbowych o tychże podstawach. Służą do tego manipulatory (odpowiednio): oct (ang. octal) i hex (ang. hexadecimal). Ich przykładowe użycie jest pokazane na poniższym listingu:

#include <iostream>
using namespace std;

int main()
{
   int liczba;
   cout << "Wprowadz liczbe: ";
   cin >> liczba;
   cout << "Podana liczba w systemie osemkowym: " << oct << liczba << endl;
   cout << "Podana liczba w systemie szesnastkowym: " << hex << liczba << endl;
   cout << "Jeszcze raz w szesnastkowym: " << liczba << endl;
   cout << "Wracamy do systemu dziesietnego: " << dec << liczba << endl;

   return 0;
}

Naturalnie, manipulator dec (od ang. decimal) umożliwia prezentowanie liczby w systemie dziesiętnym.

Przyjrzyj się linijkom #10 i #11. Raz użyty manipulator tego typu powoduje, że liczby są wyświetlane w danej konwencji aż do jawnej zmiany na inną.

Niestety, w bibliotece <iostream> nie ma funkcji, która powoduje wyświetlanie liczb w systemie dwójkowym. Nie martwmy się tym zbytnio, już niedługo sami będziemy potrafili napisać program, który dokonuje tej czynności.

Liczby zmiennopozycyjne: zmiana notacji

Możliwa jest także zmiana sposobu wyświetlania liczb zmiennoprzecinkowych: da się je przedstawiać w notacji zwyczajnej (np. z określoną liczbą cyfr znaczących po przecinku) bądź tzw. notacji naukowej.

Przypomnij sobie, czym jest notacja naukowa — być może to pojęcie było wprowadzone na lekcjach matematyki.

Przeanalizujmy działanie poniższego fragmentu kodu:

   double tau = 6.28318530; // τ=2π
   double PKiN = 230.68; //taką wysokość [m] ma najwyższy budynek w Polsce

   cout << "Wartosc liczby tau: " << tau << endl;
   cout << "Wysokosc Palacu Kultury i Nauki: " << PKiN << " m." << endl << endl;

   cout << fixed << tau << endl; //notacja zwyczajna
   cout << scientific << tau << endl << endl; //notacja naukowa
   cout << fixed << PKiN << endl;
   cout << scientific << PKiN << endl << endl;

   cout.precision(8); //umożliwia ustalenie precyzji (zob. dalej)

   cout << "Zmieniona precyzja" << endl;
   cout << fixed << tau << endl;
   cout << scientific << tau << endl << endl;
   cout << fixed << PKiN << endl;
   cout << scientific << PKiN << endl;
Separatorem dziesiętnym liczb jest kropka, a nie przecinek! Pamiętajmy o tym, pisząc program lub wpisując liczby w trakcie działania programu.

Standardowo, liczby są wyświetlanie w konsoli z maksymalnie pięcioma cyframi znaczącymi po przecinku. Użycie manipulatora fixed zmienia tę liczbę domyślnie na sześć cyfr. W linijce #12 pokazany jest sposób ręcznej zmiany tej precyzji, jednakże w dalszej części samouczka poznamy inną możliwość.

Istnieje możliwość odwołania działania manipulatorów, przy czym nie jest to łatwe i wymaga głębszej znajomości biblioteki języka C++. Dlatego przyjmijmy, że wywołanie powyższych manipulatorów powoduje zmianę formatowania od miejsca użycia aż do końca programu lub użycia innego manipulatora z tej samej "rodziny".

Wyrównywanie

Czasami zajdzie potrzeba zmiany sposobu wyrównania tekstu. Przydadzą się do tego manipulatory left, right i (ale to bardzo rzadko) internal.

   int liczba = -100;

   cout.width(5); //ustalenie szerokości "komórki" na 5 znaków (zob. dalej)
   cout << left << liczba << endl; //do lewej
   cout.width(5);
   cout << right << liczba << endl; //do prawej
   cout.width(5);
   cout << internal << liczba << endl; //a to ciekawe...
   //"–" wyrównał się do lewej, a "100" do prawej

   liczba = 100;
   cout.width(5);
   cout << internal << liczba << endl; //kolejna niespodzianka

Powyższy kod raczej nie wymaga dodatkowego komentarza, nieprawdaż?

Zadania do samodzielnego wykonania:
  • Sprawdź, czy rzeczywiście za każdym razem trzeba korzystać z instrukcji cout.width(6).
  • Jak myślisz, jakie jest domyślne wyrównywanie?

Manipulatory w bibliotece <iomanip>

Chcąc korzystać z narzędzi dostępnych w bibliotece <iomanip>, potrzebne będzie wywołanie poniższej dyrektywy na początku programu:

#include <iomanip>

Nie zapominajmy, jak zwykle, również o instrukcji:

using namespace std;

Precyzja

Pamiętasz wywołanie cout.precision() w jednym z powyższych kodów? Alternatywą dla takiej instrukcji jest użycie odpowiedniego manipulatora. Przyjrzyjmy się poniższemu listingowi:

#include <iostream>
#include <iomanip> //dołączamy bibliotekę <iomanip>
using namespace std;

int main()
{
   double tau = 6.28318530;
   double liczba = 3.000;

   cout << tau << endl;
   cout << liczba << endl;
   cout << setprecision(4) << tau << endl; //wyświetlą się 3 cyfry po przecinku
   cout << setprecision(2) << liczba << endl; //a tu co się wyświetli?
   cout << fixed << liczba << endl; //a tu?

   return 0;
}
Jeżeli chcemy wyświetlić n miejsc znaczących po przecinku, pamiętajmy, że musimy napisać setprecision(n+1).

Szerokość komórki

Tak jak już zostało wspomniane, istnieje alternatywa dla instrukcji cout.width(), dzięki której można ustalić szerokość komórki do wpisywania tekstu. Jest to manipulator setw().

   int liczba = 100;
   cout << setw(5) << liczba << "|" << liczba << endl; //sprawdź, jak się to wyświetli
Manipulator setw() odnosi się wyłącznie do zmiennej, która znajduje się po najbliższym <<.

Znaki wypełniające

Potrafimy już ustalać szerokość komórki, w której ma być wpisany tekst bądź liczba. Możemy jednak "uatrakcyjnić" wygląd takiego napisu, wypełniając puste miejsce określonymi znakami. Służy do tego manipulator setfill(), którego argumentem (czyli tym, co stoi w nawiasie) jest dowolny pojedynczy znak. Przykład poniżej:

   int liczba = 100;
   cout << setw(7) << setfill('*') << liczba << endl;
   cout << left << setw(7) << liczba << endl;

   liczba = -100;
   cout << internal << setw(7) << liczba;

Podsumowanie

W niniejszym samouczku omówiliśmy najbardziej popularne manipulatory formatujące tekst wyświetlany w konsoli. Poniżej znajduje się tabelka, do której możemy zaglądać, gdy chcemy sobie przypomnieć działanie poszczególnych funkcji:

Manipulator Znaczenie
endl przejście do nowej linii
oct liczby całkowite: wyświetlenie liczby w systemie ósemkowym
dec liczby całkowite: wyświetlenie liczby w systemie dziesiętnym
hex liczby całkowite: wyświetlenie liczby w systemie szesnastkowym
fixed liczby zmiennopozycyjne: wyświetlenie liczby w notacji zwyczajnej
scientific liczby zmiennopozycyjne: wyświetlenie liczby w notacji naukowej
left wyrównanie napisu do lewej
right wyrównanie napisu do prawej
setprecision() ustalenie precyzji wyświetlanej liczby
setw() ustalenie szerokości komórki
setfill() ustalenie znaku wypełniającego
Więcej informacji na temat manipulatorów znajdziesz w angielskojęzycznej dokumentacji na stronie cplusplus.com.
CC By 3.0
Copyright © 2011-2016 by Katarzyna Fokow [Last update: 2017-02-01 17:17:06]
This work is licensed under a Creative Commons Attribution 3.0 Unported License