540 likes | 637 Views
Podstawy informatyki 2013/2014. Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka. int , int *, int **. int a=1; int * w=&a ; int ** ww=&w ; cout<<&ww<<endl ; cout<<ww<<endl ;
E N D
Podstawy informatyki2013/2014 Łukasz SztangretKatedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiałyDanuty Szeligi i Pawła Jerzego Matuszyka
int, int*, int** int a=1; int *w=&a; int **ww=&w; cout<<&ww<<endl; cout<<ww<<endl; cout<<*ww<<endl; cout<<**ww<<endl; 0043F8CC 0043F8CF 1 a 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww 0043F8D4 0043F8D0 0043F8CC 1
void f1(int), void f3(int*), void f5(int**)void f2(int&), void f4(int*&), void f6(int**&) void f1(intfa){} intmain() { int a=1; int *w=&a; int **ww=&w; f1(a); return 0; } 0043F8CC 0043F8CF 1 a Nie możemy zmienić: a, w, ww Możemy zmienić: 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww 0043F8D8 0043F8DB 1 fa
void f1(int), void f3(int*), void f5(int**)void f2(int&), void f4(int*&), void f6(int**&) void f2(int &fa){} intmain() { int a=1; int *w=&a; int **ww=&w; f2(a); return 0; } 0043F8CC 0043F8CF 1 a fa Nie możemy zmienić: w, ww Możemy zmienić: a 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww
void f1(int), void f3(int*), void f5(int**)void f2(int&), void f4(int*&), void f6(int**&) void f3(int *fw){} intmain() { int a=1; int *w=&a; int **ww=&w; f3(w); return 0; } 0043F8CC 0043F8CF 1 a Nie możemy zmienić: w, ww Możemy zmienić: a 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww 0043F8D8 0043F8DB 0043f8CC fw
void f1(int), void f3(int*), void f5(int**)void f2(int&), void f4(int*&), void f6(int**&) void f4(int *&fw){} intmain() { int a=1; int *w=&a; int **ww=&w; f4(w); return 0; } 0043F8CC 0043F8CF 1 a Nie możemy zmienić: ww Możemy zmienić: a, w 0043F8D0 0043F8D3 0043F8CC w fw 0043F8D4 0043F8D7 0043F8D0 ww
void f(int), void f(int*), void f(int**)void f(int&), void f(int*&), void f(int**&) void f5(int **fww){} intmain() { int a=1; int *w=&a; int **ww=&w; f5(ww); return 0; } 0043F8CC 0043F8CF 1 a Nie możemy zmienić: ww Możemy zmienić: a, w 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww 0043F8D8 0043F8DB 0043F8D0 fww
void f(int), void f(int*), void f(int**)void f(int&), void f(int*&), void f(int**&) void f6(int **&fww){} intmain() { int a=1; int *w=&a; int **ww=&w; f6(ww); return 0; } 0043F8CC 0043F8CF 1 a Nie możemy zmienić: Możemy zmienić: a, w, ww 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww fww
Możliwe wywołania funkcji int a=1; int *w=&a; int **ww=&w; 0043F8CC 0043F8CF 1 a 0043F8D0 0043F8D3 0043F8CC w 0043F8D4 0043F8D7 0043F8D0 ww int a; int *w; int **ww; void f1(int); f1(a); f1(*w); f1(**ww); void f2(int&); f2(a); f2(*w); f2(**ww); void f3(int*); f3(&a); f3(w); f3(*ww); void f4(int*&); -- f4(w); f4(*ww); void f5(int**); -- f5(&w); f5(ww); void f6(int**&); -- -- f6(ww);
Wskaźnik do funkcji • Funkcję można wywołać lub można pobrać jej adres (miejsce, gdzie jej kod zaczyna się w pamięci). • W wyniku wywołania zaczyna się wykonywać kod tej funkcji: q = fun(x, 7); • W wyniku pobrania adresu funkcji uzyskuje się wskaźnik do tej funkcji: pfun = &fun; • Wskaźnika tego można użyć do wywołania funkcji: q = (*pfun)(x, 7)
Wskaźnik do funkcji • Definicja: • funkcji fun typu T (T1, T2, ...): T fun(T1, T2, ...) { ... } • wskaźnika pf (do tej funkcji) typu T (*)(T1, T2, ...): T (*pf)(T1, T2, ...); int (*pf)(double, char); • Ustawienie (dwa alternatywne sposoby): pf = fun; pf = &fun; • Użycie (wywołanie funkcji przez wskaźnik): intres; double x=0.5; char y=‘a’; res = (*pf)(x, y); res = pf(x, y);
#include<iostream> usingnamespacestd; intpodwoj(int a); intpotroj(int a); intmain() { int a, (*fun)(int a); a=10; fun=podwoj; cout << (*fun)(a) << endl; fun=potroj; cout << (*fun)(a) << endl; cout << a << endl; return 0; } int podwoj(int a) { return (a*2); } int potroj(int a) { return (a*3); } Wskaźnik do funkcji 20 30 10
Wskaźnik do funkcji #include<iostream> usingnamespacestd; int f(int a); voidfun(int (*)(int),int); intmain() { int (*w)(int)=&f; fun(w,5); return 0; } int f(int a) { return 2*a; } void fun(int (*wf)(int), int a) { cout<<wf(a)<<endl; } 10
Czytanie deklaracji • Zaczynamy od nazwy. • Następnie poruszamy się w prawo. • Gdy napotkamy na nawias zamykający poruszamy się w lewo. • Jeżeli odczytaliśmy już wszystko w obrębie danego nawiasu wychodzimy na zewnątrz i znowu poruszamy się w prawo.
Co to jest a??? int *(*(*a)(int))[10]; int *(*(*a)(int))[10 a jest]; int *(*(*a)(int))[10]; wskaźnikiem int *(*(*a)(int))[10]; do funkcji wywoływanej z parametrem typu int int *(*(*a)(int))[10]; zwracającej wskaźnik int *(*(*a)(int))[10]; do 10-cio elementowej tablicy int *(*(*a)(int))[10]; wskaźników do obiektów typu int
Co to jest a??? int (*(*a())[10])(); int (*(*a())[10])(); a jest funkcją wywoływaną bez parametrów int (*(*a())[10])(); zwracającą wskaźnik int (*(*a())[10])(); do 10-cio elementowej tablicy int(*(*a())[10])(); wskaźników int(*(*a())[10])(); do funkcji wywoływanych bez parametrów int(*(*a())[10])(); zwracających obiekty typu int
Co to jest a??? float (*(*a)(int))(); float (*(*a)(int))();a jest float (*(*a)(int))();wskaźnikiem float (*(*a)(int))();do funkcji wywoływanej z parametrem typu int float(*(*a)(int))();zwracającej wskaźnik float(*(*a)(int))(); do funkcji wywoływanej bez parametrów float(*(*a)(int))(); zwracających obiekty typu float
Co to jest a??? int (*(*(*a)())[10])(); int (*(*(*a)())[10])();a jest int (*(*(*a)())[10])();wskaźnikiem int (*(*(*a)())[10])();do funkcji wywoływanej bez parametrów int (*(*(*a)())[10])();zwracającej wskaźnik int (*(*(*a)())[10])();do 10-cio elementowej tablicy int(*(*(*a)())[10])();wskaźników int(*(*(*a)())[10])(); do funkcji wywoływanych bez parametrów int(*(*(*a)())[10])(); zwracających obiekty typu int
Wskaźnik do funkcji jako argument innej funkcji #include<iostream> usingnamespacestd; double dod (double a, double b){return (a+b);} double ode (double a, double b){return (a-b);} double mno (double a, double b){return (a*b);} double dzi (double a, double b){return (a/b);} double wykonaj(double (*)(double, double),double,double); intmain() { intwybor; double a ,b; cout << "Wybierz dzialanie\n"; cout << "1.Dodawanie\n2.Odejmowanie\n"; cout << "3.Mnozenie\n4.Dzielenie\n"; cin >> wybor; cout << "Podaj dwie liczby\n"; cin >> a >> b; double (*wsk[4])(double, double)={dod, ode, mno, dzi}; cout<<wykonaj(*wsk[wybor-1],a,b)<<endl; return 0; } double wykonaj(double (*wsk)(double, double), double a, double b){return (*wsk)(a,b);}
Arytmetyka wskaźników • Rezultat zastosowania do wskaźników operatorów arytmetycznych +, -, +=, -=, ++ i -- zależy od typu wskazywanego obiektu. • Stosując operator arytmetyczny do wskaźnika p typu T* zakładamy, że p wskazuje na element w tablicy obiektów typu T. • Wtedy: • p + 1oznacza adres następnego elementu w tablicy, • p - 1oznacza adres poprzedniego elementu w tablicy, • p + ioznacza adres i-tego następnego elementu, • p - i oznacza adres i-tego poprzedniego elementu
Arytmetyka wskaźników #include<iostream> usingnamespacestd; intmain() { inttab[]={0,1,2,3,4}; int *wsk1,*wsk2; wsk1=&tab[1]; wsk2=&tab[4]; cout << wsk2-wsk1 << endl; return 0; } 3
Arytmetyka wskaźników intmain() { inttab[5]={1,2,3,4,5}; int *wsk; wsk=tab; for (int i=0;i<5;i++) { cout<<*wsk<<"\t"<<wsk<<endl; wsk++; } return 0; }
Porównywanie wskaźników • Dwa wskaźniki tego samego typu są równe (różne) jeżeli pokazują (nie pokazują) na ten sam obiekt: int *wsk1,*wsk2; if (wsk1==wsk2){} //ten sam obiekt if (wsk1!=wsk2){} //różne obiekty • Porównywanie wskaźników operatorami <, >, <= i >= ma sens tylko wtedy, gdy oba wskaźniki wskazują na elementy tej samej tablicy. • Wtedy, jeżeli w1 < w2, to oznacza to, że obiekt wskazywany przez w1 znajduje się w pamięci wcześniej niż drugi (w1 jest bliżej początku tablicy niż w2).
Wskaźniki i const • zwykły wskaźnik: int *wsk; • stały wskaźnik int * constwsk; • wskaźnik do obiektu stałego constint * wsk; • stały wskaźnik do stałego obiektu constint * constwsk;
Stały wskaźnik #include<iostream> usingnamespacestd; intmain() { int a=5,b=10; int * constw=&a; cout << *w << endl; (*w)++; cout << *w << endl; w=&b; return 0; } 5 6 BŁĄD
Wskaźnik do obiektu stałego intmain() { constint a=5,b=10; constint *st_w; int *zm_w; st_w=&a; cout << *st_w << endl; st_w=&b; cout << *st_w << endl; (*st_w)++; zm_w=&a; return 0; } 5 10 BŁĄD BŁĄD
Stały wskaźnik do stałego obiektu intmain() { constint a=5,b=10; const int * const st_w=&a; cout << *st_w << endl; (*st_w)++; st_w=&b; return 0; } 5 BŁĄD BŁĄD
Wskaźnik typu void intmain() { intti[]={1,2,3,4},*wi; double td[]={1.0,2.0,3.0,4.0},*wd; void *wv; wi=ti; wd=td; wv=wi; cout<<*wv<<endl; wv++; wv=wd; return 0; } BŁĄD BŁĄD
Operatory rzutowania intmain() { double d=2.5; int i; i=d; cout << d << endl << i << endl; return 0; } conversion from 'double' to 'int', possible loss of data 2.5 2
Operatory rzutowania intmain() { double d=2.5; int i; i=(int)d; // lub i=int(d) cout << d << endl << i << endl; return 0; } 2.5 2
Operatory rzutowania intmain() { int i=65; char c; c=(char)i; cout << i << endl << c << endl; return 0; } 65 A
Nowe operatory rzutowania • Stare operatory rzutowania: • (nazwa_typu)wyrażenie • nazwa_typu (wyrażenie) • Nowe operatory rzutowania: • static_cast<nazwa_typu>(wyrażenie) • const_cast<nazwa_typu>(wyrażenie) • dynamic_cast<nazwa_typu>(wyrażenie) • reinterpret_cast<nazwa_typu>(wyrażenie)
static_cast • Operator static_cast jest używany do wszystkich konwersji, które są dobrze zdefiniowane i mogą być wykonane przez kompilator (mogą powodować ostrzeżenia), np.: • konwersje roszerzające (np. int -> float, int -> long), • konwersje zawężające (utrata informacji, np. float -> int),
static_cast intmain() { double d=3.14; int i; i=static_cast<int>(d); cout << d << endl << i << endl; return 0; } 3.14 3
const_cast • Używany do konwersji typu: • const -> non-const • volatile -> non-volatile • Używany TYLKO do konwersji tego typu – jeżeli równocześnie konieczna jest inna konwersja, musi być ona wykonana za pomocą oddzielnego operatora. • Nie może być użyty do bezpośredniej konwersji obiektu const na non-const.
const_cast intmain() { constint a=2; constint *st_w=&a; int *zm_w; cout<<a<<endl; zm_w=const_cast<int *>(st_w); *zm_w=-2; cout<<*zm_w<<endl; cout<<a<<endl; return 0; } 2 -2 ???
dynamic_cast dynamic_cast robi rzutowanie tylko pod warunkiem, że w danej konkretnej chwili ma to sens.
dynamic_cast class pojazd { protected: intl_kol, max_sp; public: pojazd(inta,int b):l_kol(a),max_sp(b){} virtualvoid wypisz(); }; classsamochod: public pojazd { double poj_s; public: samochod(inta,intb,double c):pojazd(a,b), poj_s(c){} void wypisz(); }; class rower: public pojazd { intli_prze; public: rower(int a, int b, int c):pojazd(a,b), li_prze(c){} void wypisz(); }; intmain() { pojazd P(2,30),*WP; samochod S(4,180,1.9),*WS; rower R(2,30,21); char a; cout<<"S czy R\n"; cin>>a; if (a=='S') WP=&S; else WP=&R; WS=dynamic_cast<samochod*>(WP); cout<<&S<<endl; cout<<WS<<endl; return 0; } S czy R S 0040F950 0040F950 S czy R R 0040F950 00000000
reinterpret_cast • Jest to najmniej bezpieczny mechanizm rzutowania, mogący powodować błędy. • Traktuje obiekty jak pewien zestaw bitów, nie zwraca uwagi na znaczenie.
reinterpret_cast intmain() { intti[]={1,2,3,4},*wi,*wt; double td[]={1.0,2.0,3.0,4.0},*wd; wi=ti; wd=td; for (int i=0;i<4;i++) cout<<*(wi+i)<<"\t"<<*(wd+i)<<endl; wt=wi; wi=reinterpret_cast<int *>(wd); wd=reinterpret_cast<double *>(wt); cout<<endl; for (int i=0;i<4;i++) cout<<*(wi+i)<<"\t\t"<<*(wd+i)<<endl; return 0; }
reinterpret_cast intmain() { int *wi; cin>>wi; return 0; } intmain() { int *wi,a; a=00203040; wi=reinterpret_cast<int*>(a); cout<<wi<<endl; cout<<oct<<a<<endl; return 0; } 00010620 203040
Dynamiczne tworzenie tablic • 1D int *w=newint[n]; • 2D int **w = new int*[n]; for(int i=0;i<n;i++) w[i] = newint[m]; • 3D int ***w = new int**[n]; for(int i=0;i<n;i++) w[i] = newint*[m]; for(int i=0;i<n;i++) for(int j=0;j<m;j++) w[i][j] = newint[o];
Usuwanie tablic • 1D delete [] w; • 2D for(int i=0;i<n;i++) delete [] w[i]; delete [] w; • 3D for(int i=0;i<n;i++) for(int j=0;j<m;j++) delete [] w[i][j]; for(int i=0;i<n;i++) delete [] w[i]; delete [] w;
Dynamicznetworzenietablicy 2D 0031FC3C 0031FC3F 00658E58 tab 0031FC40 0031FC43 2 m 0031FC44 0031FC47 3 n int n=3,m=2; int **tab; tab=newint *[n]; for (int i=0; i<n; i++) tab[i]=newint [m]; for (int i=0; i<n; i++) for (int j=0; j<m; j++) tab[i][j]=i*m+j+1; cout<<&tab<<endl; cout<<tab<<endl; cout<<*tab+1<<endl; cout<<*(tab+1)<<endl; cout<<tab[1]<<endl; cout<<&tab[1]<<endl; cout<<tab[1][0]<<endl; cout<<*(*(tab+1)+1)<<endl; cout<<&tab[1][0]<<endl; 00658E58 00658E5B 00651F10 int* 00658E5C 00658E5F 00651F20 int* 00658E60 00658E63 00651F30 int* 0031FC3C 00658E58 00651F10 00651F13 1 int 00651F14 00651F14 00651F17 2 int 00651F20 00651F20 00651F20 00651F23 3 int 00658E5C 00651F24 00651F27 4 int 3 4 00651F30 00651F33 5 int 00651F20 00651F34 00651F37 6 int
Dynamicznetworzenietablicy 2D int n=3,m=2; int **tab; tab=newint *[n]; for (int i=0; i<n; i++) tab[i]=newint [m]; for (int i=0; i<n; i++) for (int j=0; j<m; j++) tab[i][j]=i*m+j+1; cout<<typeid(&tab).name()<<endl; cout<<typeid(tab).name()<<endl; cout<<typeid(*tab+1).name()<<endl; cout<<typeid(*(tab+1) ).name()<<endl; cout<<typeid(tab[1] ).name()<<endl; cout<<typeid(&tab[1] ).name()<<endl; cout<<typeid(tab[1][0] ).name()<<endl; cout<<typeid(*(*(tab+1)+1) ).name()<<endl; cout<<typeid(&tab[1][0] ).name()<<endl; int * * * int * * int * int * int * int * * int int int *
Dynamiczne tworzenie tablic #include<iostream> usingnamespacestd; intmain() { int n; cout << "Podaj rozmiar tablicy\n"; cin >> n; int *w=newint[n]; for (int i=0; i<n; i++){ cout << "Podaj wartosc\n"; cin >> w[i];} for (int i=0; i<n; i++) cout << *(w+i) << endl; delete [] w; return 0; }
Dynamiczne tworzenie tablic 2-D #include<iostream> using namespace std; int main() { int n; cout << "Podaj rozmiar\n"; cin >> n; int **wsk=new int*[n]; for (int i=0; i<n; i++) wsk[i]=new int[n]; for (int i=0; i<n; i++) for (int j=0; j<n; j++) wsk[i][j]=i*n+j; for (int i=0; i<n; i++){ for (int j=0; j<n; j++) cout<<*(*(wsk+i)+j)<<"\t"; cout << endl;} for(int i=0;i<n;i++) delete [] wsk[i]; delete [] wsk; return 0; }
Wskaźnik do tablicy wielowymiarowej intmain() { inttab[][3]={1,2,3,4,5,6,7,8,9}; int **w=newint*[3]; for (int i=0; i<3; i++) *(w+i)=&tab[i][0]; for (int i=0; i<3; i++){ for (int j=0; j<3; j++){ cout<<w[i][j]<<"\t";} cout << endl;} return 0; }
Funkcja zwracająca tablicę int *fun() { inttab[5]; for (int i=0; i<5; i++) tab[i]=i; return tab; } intmain() { int *w; w=fun(); for (int i=0; i<5; i++) cout << w[i] << endl; return 0; }
Funkcja zwracająca tablicę int *fun() { int *wsk=newint[5]; for (int i=0; i<5; i++) wsk[i]=i; return wsk; } intmain() { int *w; w=fun(); for (int i=0; i<5; i++) cout << w[i] << endl; return 0; }