KURS C/C++ WYKŁAD 5

Transkrypt

KURS C/C++ WYKŁAD 5
KURS C/C++
WYKŁAD 5
Typ wyliczeniowy enum
Istnieje inna często wygodniejsz niż deklaracja const metoda nazywania stałych całkowitych
Deklaracja:
enum {WRITE, READ, DELETE);
definiuje trzy stałe całkowite WRITE, READ, DELETE, które nazywamy stałymi wyliczanymi i
przypisuje im kolejno wartości całkowite 0,1,2.
Deklaracja ta jest równoważna zapisowi:
const WRITE = 0;
const READ = 1;
const DELETE = 2;
Wyliczenie może mieć nazwę.
enum RIGHT {WRITE, READ, DELETE);
Nazwa wyliczenia staje się odrębnym typem.
enum nazwa_typu { lista wyliczeniowa }
Przykład:
enum miesiace {styczeń, luty, marzec, kwiecień, maj, czerwiec};
enum miesiace {styczen =1, luty, marzec, kwiecien=6, maj, czerwiec=luty+marzec};
enum miesiace {styczen =1, luty, marzec, kwiecien, maj, czerwiec};
W ten sposób zdefiniowaliśmy nowy typ o nazwie miesiace. Definiujemy zmienną tego typu:
miesiace mm;
Sposób użycia tych zmiennych jest następujący:
mm = styczen;
if (mm = = luty) {.....}
Kompilator ostrzega przy przypisaniach np.:
mm = 2; powinno być
mm = 3;
mm = miesiace (2);
mm = miesiace (3);
mm = miesiace (23); // nie ma błędu, pakiet Borland 3.1
Kompilator sygnalizuje błąd przy przypisaniu:
styczeń = 1;
ponieważ zmienne wyliczeniowe sa traktowane jak constans.
// enum {BLACK, BLUE, GREEN, CYAN, RED, MAGENTA);
enum {black, blue, green, cyan, red, magenta);
czyli black = 0, blue = 1, itd
textcolor (green);
cprintf (″Zmiana koloru na zielony″);
printf (″\n″ );
Operacje we/wy
Język C/C++ nie posiada zdefiniowanych instrukcji realizujących operacje we/wy. Do tego
celu służą funkcje znajdujące się w standardowych bibliotekach.
standardowe strumienie predefiniowane wejścia/wyjścia
stdin
- strumień wejściowy (konsola)
stduot
- strumień wyjściowy (konsola)
stderr
- strumień komunikatów błędów (konsola)
stdaux
- strumień pomocniczy (konsola)
stdprn
- strumień drukarki
np.:
fputs (″Nazwa firmy″, stdprn);
Funkcja printf();
Funkcje printf() i scanf(), służą do realizacji tzw. formatowanego we/wy.
Składnia funkcji jest następująca:
int printf (const char *format [,argument,...]);
Parametr format wskazuje tzw. łańcuch formatujący. Pewne sekwencje tego łancucha są specjalnie
traktowane przez funkcje printf().
int a=1; float b=2.45; char c=�d�;
printf("Wartość zmiennej a = %d zmiennej b = %4.2f \
zmiennej c = %c zmiennej d = %s \n",a,b,c,″C++″);
char text[]=�C++�;
printf("Wartość zmiennej a = %.2d zmiennej b = %4.2f \
zmiennej c = %c zmiennej d = %s \n",a,b,c,text);
Aby wydrukować znak % trzeba napisać: %%
Ogólny format sekwencji formatującej przedstawia się następująco:
%[flagi][szerokość][.precyzja][h|l|L]znak-typu.
flagi:
flagi
znaczenie
default
-
dosunięcie argumentu do lewego krańca jego pola
znak tylko dla ujemnej
+
liczba zawsze ze znakiem +/-
#
dla formatu x,X, poprzedzenie liczby 0x, 0X
bez znaków wiodących
dla formatu o, poprzedzenie liczby 0
dla formatu e,E,f wstawia zawsze znak kropki
szerokość:
n - wyświetlanych jest przynajmniej n znaków. Jeśli wartość zajmuje mniej niż n znaków
szerokość pola jest uzupełniana dodakowymi spacjami z lewej lub prawj strony w zależności od
ustawionej flagi.
float y=10.96
printf ("y=%5.2f ",y);
y=10.96
printf ("y=%10.2f ",y);
y=
10.96_
printf ("y=%#.0f ",y);
y=11.
int i = 12;
printf ("y=%#x",y);
y=0xc.
int y=23;
printf ("y=%6d",y);
y=
printf ("y=%-6d",y);
y =23
printf ("y=%+6d",y);
23_
_
y = +23
_
znak_typu:
znak typu
argument wejściowy
argument wejściowy
d ,i
całkowity
liczba dziesiętna ze znakiem
o
całkowity
liczba ósemkowa bez znaku
x,X
całkowity
liczba szesnastkowa bez znaku
u
całkowity
liczba dziesiętna bez znaku
c
znak
pojedynczy znak
s
wskaźnik łańcucha
ciąg znaki łańcucha, aż do wystapienia �\0� lub tyle ile
określono w precyzji
f
zmiennoprzecinkowy [-]m.ddd gdzie liczbę cyfr d określa precyzja
(domyślnie 6).
e, E
zmiennoprzecinkowy [-]m.dde+-xx. Przed kropką dokładnie jedna cyfra, liczba
cyfr po kropce zależna od precyzji(domyślnie 6).
g, G
zmiennoprzecinkowy liczba będzie wyświetlana w postaci e lub f w zależności
od zadanej precyzji. Nie wypisuje zbędnej kropki
dziesiętnej i nie znaczących zer.
y=0.000002;
printf ("y=%f
y=%g
y=%e",y);
wyświetla: y=0.000002
y=2e-06
y=2.000000e-06
y=2000000;
wyświetla: y=2000000.000000
y=2e+06
y=2.000000e+06
modyfikatory:
modyfikator znaczenie
h
argument traktowany jak typu short int dla znaków typu d,i,o,u,x,X
l
argument traktowany jak long int dla znaków typu d,i,o,u,x,X
dla znaków e, E, g, G jako typu double
L
argument traktowany jak long double dla znaków typu e,E,f,g,G
precyzja:
.0 - dla e, E, f nie jest drukowany znak kropka dziesiętna liczba zero nie zostanie wydrukowana
.n
znak typu
znaczenie
d,i,o,u,x,X
n cyfr znaczących zostanie wydrukowanych, jeśli jest ich mniej
uzupełnienie zerami z lewej strony., jeśli więcej nie będzie obcięta.
e,E, f
n cyfr znaczących zostanie wydrukowanych po przecinku
dziesiętnym. Ostatnia cyfra jest zaokraglana.
s
co najmniej n znaków zostanie wydrukowanych
long double y=2.1e45;
printf ("y=%Le″,y);
y = 2.100000e+45
printf ("y=%.2Le″,y);
y = 2.10e+45
printf ("y=%Lf″,y);
long int y=50000;
printf ("y=%ld″,y);
y = 50000
printf ("y=%d",y);
y=902
printf ("y=%.6d",y);
y=000902
char nazwa[]="Microsoft";
printf ("%.5s", nazwa);
Micro
Przyjmowane precyzje domyślne:
1 - dla znaków typu d, i ,o, u, x, X
6 - dla znaków typu e, E, f
- wszystkie cyfry znaczące dla znaków typu G,g
- łańcuchy są drukowane do pierwszego znaku �\0�., znaków c nie dotyczy.
Jeśli wartość zajmuje mniej niż n znaków szerokość pola jest uzupełniana dodatkowymi
z lewej lub prawj strony w zależności od ustawionej flagi.
spacjami
Funkcja scanf()
Funkcja scanf() służy do realizacji formatowanego wejścia. Składnia tej funkcji jest
następująca:
int scanf (const char* format [,address, ...]);
Parametr format wskazuje tzw. łańcuch formatujący. łańcuch ten zawiera sekwencje
określające typy wprowadzanych danych.
Funkcja wczytuje znaki ze standardowego wejścia, interpretuje je zgodnie ze specyfikacjami
zawartymi w formacie i zapamiętuje wyniki w miejscach określonych przez pozostale argumenty.
Argumenty muszą być adresami, określają adres obszaru pamięci gdzie dane mają być
umieszczone.
int i,j;
scanf("%d%d", &i, &j);
Ogólny format sekwencji formatującej przedstawia się następująco:
%[*][szerokość][h|l|L] znak-typu.
*
oznacza, że dane pole zostanie odczytane ale nie zostanie zapamiętane we
wskazanym miejscu
szerokość
określa maksymalną liczbę znaków danego pola
znak-typu
tak jak opisane w funkcji printf(), dodatkowo można używać dużych liter:
D, O, I, U
scanf ("%d,%d,%d", &d, &m, &r); - wprowadzane dane oddzielane muszą być przecinkami.
float f;
scanf ("%5f", &f); wprowadzamy 1234567
printf ("f=%f", f);
f=12345.0
char tab[20];
scanf ("%7s", tab); wprowadzamy Wolszczan
printf ("s=%s", tab); s=Wolszcz
Funkcja gets(), puts()
char *gets (char *s); // #include <stdio.h>
Funkcja odczytuje znaki ze standardowego strumienia wejściowego (stdin) i umieszcza je w łańcuchu s;
char znaki[20];
gets (znaki);
Czytanie jest przerywane po napotkaniu znaku końca wiersza, ktry zostaje zamieniony na
znak końca łańcucha(NULL).
int puts (const char *s);
char znaki[20]=″Przykład wyprowadzania łańcucha na ekran″;
puts (znaki);
Ekran: Przykład wyprowadzania łańcucha na ekran
Strumienie predefiniowane C++
Wprowadzanie i wyprowadzanie informacji można potraktować jako strumień bajtów
płynący od źródła do ujścia. Jeśli chcemy zmiennej x nadać wartość wczytaną z klawiatury, wtedy
strumień bajtów płynie od urządzenia zewnętrznego - klawiatura do tego miejsca w pamięci
przeznaczonego dla zmiennej x.
Dla operacji we/wy kompilator predefiniuje kilka strumieni (predefiniuje czyli zakłada
stumień, otwiera strumień i po zakończeniu programu zamyka strumień) : cout, cin, cerr.
Aby skorzystać z tych strumieni w programie trzeba umieścić dyrektywę:
#include<iostream.h> podobnie jak dla C <stdio.h>.
Ze strumieniem wyjściowym cout został stowarzyszony operator <<
<< insert operator
(put to wstaw do strumienia cout)
Ze strumieniem wyjściowym cin został stowarzyszony operator >>
>> extract operator
(get from pobierz ze strumienia cin )
Przykład
#include<iostream.h>
void main(){
int x = 123;
cout<<x;
}
Można wysyłać różne typy zmiennych i stałych przy pomocy jednej instrukcji np.
int x=123;
cout<<"Wartość x = "<< x <<'.'
W przykładzie tym, za pomocą jednej instrukcji przesłano na ekran napis Wartość x =,
wartość zmiennej i pojedynczy znak kropki. Na ekranie pojawi się napis: Wartość x = 123.
Poszczególne typy oddzielone są operatorami <<.
W C++ ze strumieniem cout współpracuje zestaw manipulatorów dec, oct, hex. Zmieniają
one bieżący format dla całkowitego argumentu.
Przykład
#include<iostream>
main(){
int x=123;
cout<<dec<<x<<' '
<<oct<<x<<' '
<<hex<<x;
}
Przykład pokazuje jak można wyświetlić wartość całkowitą w trzech systemach liczbowych:
dec, oct, hex. Wynik działania programu to :123 173 7b.
Ze strumieniem wejściowym cin został stowarzyszony operator >>, odpowiadający za wczytanie
informacji ze strumienia wejściowego (którego początek jest na klawiaturze), czyli program
Przykład .
void main(){
int x;
cout<<"wprowadź wartość x :\n";
cin>>x;
// >> pobieranie ze strumienia płynącego z klawiatury
cout<<"wartość x = "<<x;
}
powoduje wczytanie ze strumienia wejściowego (klawiatury) wartości do zmiennej x.
Jak widać operacje we/wy dla standardowych typów realizowane są bardzo prosto. Nie
musimy pamiętać o formacie wprowadzania i wyprowadzania wyników, a strumienie cout i cin
interpretują je prawidłowo. Trochę trudniej przedstawiają się te operacje dla typów zdefiniowanych
przez użytkownika, ale o tym opowiemy dużo później.
Mamy również możliwość specyfikacji szerokości pola, precyzji i sposobu wypełniania
pola. Do tego celu służą funkcje składowe klasy o nazwie ios. Są nimi:
int width (int) - określa minimalny rozmiar pola, dotyczy tylko jednej następnej operacji
we/wy
int width () - zwraca bieżący rozmiar pola
int precission (int) - dokładność wypisywania liczb zmiennoprzecinkowych.
Przez domniemanie=6. Efekt trwały.
int precission() - zwraca bieżąca wartość precyzji
int fill (int) - znak wypełniający obszar. Efekt trwały
int fill () - podaje bieżący parametr.
Przykłady wykorzystania funkcji i manipulatorów formatujących
int liczba;
cout.width (9);
- musi być wywołana przed operacją na strumieniu
cout.fill (�*�);
cout<<liczba;
******107
char string[12];
cin.width(11);
cin>>string - nie ma wpływy na liczby, a jedynie na stringi. Zapobiega przekraczaniu zakresu
char napis[7];
cin.width (sizeof(napis));
cin>>napis;
//1 miejsce jest przeznaczane na �\0�
Odpowiednikiem tych funkcji są manipulatory które można wstawić do strumienia:
setw (długość)
<=> cout.width (dlugosc)
setfill (znak)
<=> cout.fill (znak)
setprecision
<=> cout.precision (liczba);
setw(9); setfill (�*�); setprecision(2); // muszą być umieszczone w strumieniu
setprecision(n); - działa do odwołania
setfill (�*�);
- działa do odwołania.
setw(n); - dla następnej wyprowadzanej wartośći.
liczba=67.237;
cout<< setw(9) << setfill (�*�) << setprecision(2)<<liczba;
cout<<f;
Ekran:****67.24
Porównanie bibliotek stdio oraz iostream
Jak widać z powyższej analizy, język C++, wprowadził znaczne uproszczenia w realizacji
mechanizmów we/wy. Ponadto, biblioteka stdio ma wiele wad, które zniwelowały w/w
mechanizmy. Należą do nich między innymi:
1. printf(), scanf() są funkcjami ze zmienną ilością argumentów. Kompilator nie ostrzega więc o przypadku
niedostosowania formatu do listy argumentów np.:
printf(″%i %f %d″, a, b);
2. nie są kontrolowane przypadki złego typu argumentów (patrz wyżej)
3. dla funkcji scanf, jeśli liczba argumentów jest mniejsza niż w formacie - efekt jest nie zdefiniowany, w przeciwnym
przypadku, dane są pobierane choć nie zdefiniowane.
Mieszanie bibliotek
Pomiędzy predefiniowanymi strumieniami stdio.... cout..... nie ma żadnej łączności. W związku z
tym, gdy mieszamy operacje we/wy realizowane mechanizmami C i C++, możemy spodziewać się
nieprzewidzianych efektów z ich realizacją.
cout<<�tekst1�;
printf(�tekst2�);
cout<<�tekst3�;
printf(�tekst4�);
Powyższy zapis nie musi wcale prowadzić do oczekiwanego rezultatu: tekst1tekst2tekst3tekst4.
Może być np.
tekst1tekst3tekst2tekst4 lub odwrotnie.
Strumień cout jest buforowany a stdout nie. Inna jest więc zasada wypisywania. Język C++
przewidział mechanizm synchronizujący oba te strumienie.
Jest nim funkcja ios::sync_with_stdio(); Powinna być użyta na początku programu. Użycie tej
funkcji powoduje jednak utratę szybkości, ponieważ strumienie przestają byc buforowane.