Język C++ Wskaźniki Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła.

Podobne prezentacje


Prezentacja na temat: "Język C++ Wskaźniki Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła."— Zapis prezentacji:

1 Język C++ Wskaźniki Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła Jerzego Matuszyka

2 = *= /= %= += -= <<= >>= &= |= ^=
Wskaźniki Wskaźnik – obiekt zawierający adres innego obiektu. Operator odwołania się do obiektu znajdującego się pod adresem zapisanym we wskaźniku (operator wyłuskiwania): * Wskaźniki definiuje się również za pomocą *. Jeżeli przed nazwą znajduje się gwiazdka, to nazwa NIE ZAWSZE jest nazwą wskaźnika! Definiując wskaźnik podajemy jego nazwę oraz typ obiektów na które może pokazywać, np.: int *wskaźnik; 18 17 ++ -- POST () [] 16 ++ -- PRE + - ! ~ * 15 14 * / % 13 + - 12 << >> 11 < <= > >= 10 == != 9 & 8 ^ 7 | 6 && 5 || 4 ? : 3 = *= /= %= += -= <<= >>= &= |= ^= 2 1 ,

3 = *= /= %= += -= <<= >>= &= |= ^=
Wskaźniki 18 17 ++ -- POST () [] 16 ++ -- PRE + - ! ~ * & 15 14 * / % 13 + - 12 << >> 11 < <= > >= 10 == != 9 & 8 ^ 7 | 6 && 5 || 4 ? : 3 = *= /= %= += -= <<= >>= &= |= ^= 2 1 , Operatorem dualnym do operatora wyłuskania jest operator pobrania adresu & (zwraca adres obiektu). int a = 1; int *p = &a; cout << a; cout << *p; cout << p; cout << &a; 1 1 0032FEA0 0032FEA0

4 Wskaźniki Z definicji wskaźnika wynika, że wskaźnik pokazuje na obiekt. Może on zarówno pokazywać na typy fundamentalne jak i złożone (tablice, wskaźniki, funkcje). Referencja nie jest obiektem  nie można definiować wskaźnika do referencji. Obiekt rejestrowy nie ma adresu  nie można definiować wskaźnika do obiektu rejestrowego. Typ wskaźnika precyzyjnie określa, na jakie obiekty można takim wskaźnikiem pokazywać. Generalnie, wskaźnikiem typu A* nie można pokazywać na obiekty typu B.

5 Wskaźniki - definiowanie
Wskaźnik na typ fundamentalny (bool, char, int, double, void): int *w1; Wskaźnik na tablicę (bool[5], char[5], int[5], double[5]): int (*w2)[5]; Zapis: int *t[5]; oznacza tablicę wskaźników typu int, a nie wskaźnik do tablicy! Wskaźnik na inny wskaźnik (bool*, char*, int*, double*, void*): int **w3; Wskaźnik na funkcję (bool(), char(), int(), double(), void()): int (*w4)(); int *f(); oznacza funkcję zwracająca wskaźnik, a nie wskaźnik do funkcji!

6 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. int *a(); a jest funkcją zwracającą wskaźnik int (*b)(); b jest wskaźnikiem do funkcji int *c[5]; c jest tablicą wskaźników int (*d)[5]; d jest wskaźnikiem do tablicy

7 Wskaźniki Definicja wskaźnika tworzy jedynie obiekt wskaźnikowy – wskaźnik nie pokazuje na konkretny obiekt: int *p; // p pokazuje na "nie-wiadomo-co" Aby bezpiecznie używać wskaźnika, należy go ustawić: int n; p = &n; // teraz p pokazuje na n Najbezpieczniej ustawić wskaźnik od razu (w definicji): int *p = 0; // p pokazuje na adres 0x Żaden obiekt nie może być umieszczony w pamięci pod adresem 0. Zero pełni rolę literału wskaźnikowego, oznaczającego wskaźnik, który nie pokazuje na żaden obiekt.

8 Zachodzi konwersja tablicy na wskaźnik:
Tablice a wskaźniki Nazwa tablicy jest adresem jej pierwszego elementu. Wskaźnik jest obiektem przechowującym adres innego obiektu. Posługując się tablicą można stosować notację wskaźnikową. Posługując się wskaźnikiem można stosować notację tablicową. int t[]={1,2,3}; int *w; w=t; for (int i=0; i<3; i++) cout<<*(t+i)<<‘\t’<<w[i]<<endl; Zachodzi konwersja tablicy na wskaźnik: int [] -> int * Konwersja trywialna Wskaźnik w pokazuje nie na tablicę tylko na element tablicy. Dlatego jest typu int * a nie int (*)[].

9 Wskaźnik pokazujący na element tablicy i wskaźnik do pokazujący na tablicę
int main() { int (*w_do_t)[3]; int *w_do_el_t; int t[] = { 1,2,3 }; w_do_t = &t; w_do_el_t = t; // lub w_do_el_t=&t[0]; cout << w_do_t << '\t' << w_do_el_t << endl; cout << *w_do_t << '\t' << *w_do_el_t << endl; cout << *w_do_t[0] << endl; system("pause"); return 0; } 001DF8C8 001DF8C8 001DF8C8 1 1

10 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 + 1 oznacza adres następnego elementu w tablicy, p - 1 oznacza adres poprzedniego elementu w tablicy, p + i oznacza adres i-tego następnego elementu, p - i oznacza adres i-tego poprzedniego elementu

11 Arytmetyka wskaźników
int main() { int tab[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;

12 Arytmetyka wskaźników
#include<iostream> using namespace std; int main() { int tab[]={0,10,20,30,40}; int *wsk1,*wsk2; wsk1=&tab[1]; wsk2=&tab[4]; cout << wsk2-wsk1 << endl; return 0; } 3

13 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).

14 Tablice a wskaźniki Jeżeli mamy wskaźnik w, to operatory: * oraz [] działają identycznie: *(w + i) == w[i] *w == w[0] Przemienność dodawania: a+b=b+a *(w+i)==*(i+w) w[0]==0[w] int t[]={1,2,3}; int *w=t; for (int i=0; i<3; i++) cout<<i[t]<<‘t’<<i[w]<<endl;

15 Tablice a wskaźniki int t[] = {1, 4, -2}; Posługując się tablicą możemy stosować notację wskaźnikową: *(t+2) = 5; // lub: t[2]=5; -> wynik: {1, 4, 5} int *w; // równoważnie można zapisać: w = &t[0]; // *w wynosi 1 w = t; // *w wynosi 1 // w wskazuje na ostatni element w = &t[2]; // *w wynosi 5 w = t+2; // *w wynosi 5

16 Tablica obiektów, tablica wskaźników
Tablica obiektów typu int: int a[10]; // a typu: int [10] int* pn = &a[3]; // pn typu: int* *pn = 7; // a[3] = 7 int* pa = a; // pa typu: int* // nastąpiła konwersja: int[]  int* pa[3] = 7; // a[3] = 7 Tablica obiektów typu int* (wskaźników): int n; // n typu: int int* ap[10]; // ap typu: int *[10] ap[3] = &n; // ustawiamy adres n *ap[3] = 7; // n = 7

17 Wskaźniki w argumentach funkcji
#include<iostream> using namespace std; void podwoj(int *); int main() { int a=2; cout << a << endl; podwoj(&a); return 0; } void podwoj(int *wsk) *wsk*=2; 2 4

18 cout<<&ww<<endl; cout<<ww<<endl;
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

19 void f1(int fa){} int main() { int a=1; int *w=&a; int **ww=&w; f1(a);
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f1(int fa){} int main() { 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

20 void f2(int &fa){} int main() { int a=1; int *w=&a; int **ww=&w;
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f2(int &fa){} int main() { 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

21 void f3(int *fw){} int main() { int a=1; int *w=&a; int **ww=&w;
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f3(int *fw){} int main() { 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

22 void f4(int *&fw){} int main() { int a=1; int *w=&a; int **ww=&w;
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f4(int *&fw){} int main() { 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

23 void f5(int **fww){} int main() { int a=1; int *w=&a; int **ww=&w;
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f5(int **fww){} int main() { 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

24 void f6(int **&fww){} int main() { int a=1; int *w=&a; int **ww=&w;
void f1(int), void f3(int*), void f5(int**) void f2(int&), void f4(int*&), void f6(int**&) void f6(int **&fww){} int main() { 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

25 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);

26 Wskaźnik do funkcji Wskaźnik zawiera adres w pamięci. Może zawierać adres w pamięci, gdzie rozpoczyna się kod funkcji. Definiując wskaźnik do funkcji jednoznacznie określamy na jakie funkcje może pokazywać. Deklaracja funkcji Definicja wskaźnika void f1(); void (*w1)(); int f2(float); int (*w2)(float); char *f3(); char *(*w3)(); double f4(int[]); double (*w4)(int[]); int *f5(int*); int *(*w5)(int*); int f6(int&); int (*w6)(int&);

27 Nazwa funkcji jest jednocześnie adresem jej początku!
Wskaźnik do funkcji Nazwa funkcji jest jednocześnie adresem jej początku! Mamy funkcję: int f(float); oraz wskaźnik: int (*w)(float); Ustawienie (dwa alternatywne sposoby): w = f; w = &f; Użycie (wywołanie funkcji przez wskaźnik): int a; float b=0.5; a = (*w)(b); a = w(b); Nawias () to operator wywołania funkcji! Tu nie chcemy wywoływać funkcji

28 Wskaźnik do funkcji 20 30 10 #include<iostream>
using namespace std; int podwoj(int); int potroj(int); int main() { int a, (*wsk)(int); a=10; wsk=podwoj; cout << (*wsk)(a) << endl; wsk=potroj; cout << a << endl; } int podwoj(int a) { return (a*2); } int potroj(int a) return (a*3); 20 30 10

29 Wskaźnik do funkcji #include<iostream> using namespace std; int f(int); void fun(int (*)(int),int); int main() { int (*w)(int)=&f; fun(w,5); } int f(int a) { return 2*a; } void fun(int (*wf)(int), int a) cout<<wf(a)<<endl; 10

30 Wskaźnik do funkcji jako argument innej funkcji
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); } int main() { int wybor; 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(*tab[4])(double, double) = { dod, ode, mno, dzi }; cout << tab[wybor - 1](a, b) << endl; system("pause"); return 0; }

31 Wskaźniki i const int a; zwykły wskaźnik: int * wsk = &a;
stały wskaźnik: int * const wsk = &a; wskaźnik do obiektu stałego: const int * wsk = &a; int const * wsk = &a; stały wskaźnik do stałego obiektu: const int * const wsk = &a; int const * const wsk = &a;

32 Wskaźniki i const int wskaźnik do int wskaźnik do wskaźnika int a=1;
NON-CONST - int const a=2; CONST int * w = &a; int * const w = &a; int const * w = &a; int const * const w = &a; int * * ww = &w; int * * const ww = &w; int * const * ww = &w; int * const * const ww = &w; int const * * ww = &w; int const * * const ww = &w; int const * const * ww = &w; int const * const * const ww = &w;

33 Stały wskaźnik #include<iostream> using namespace std; int main() { int a=5,b=10; int * const w=&a; cout << *w << endl; (*w)++; w=&b; return 0; } 5 6 BŁĄD

34 Wskaźnik do obiektu stałego
int main() { const int a=5,b=10; const int *w_do_st; int *w; w_do_st =&a; cout << *w_do_st << endl; w_do_st =&b; (*w_do_st)++; w=&a; return 0; } 5 10 BŁĄD BŁĄD

35 Stały wskaźnik do stałego obiektu
int main() { const int a=5,b=10; const int * const w=&a; cout << *w << endl; (*w)++; w=&b; return 0; } 5 BŁĄD BŁĄD

36 Wskaźnik typu void int main() { int ti[]={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++; wi = wv; cout << *reinterpret_cast<int*>(wv) << endl; wv=wd; return 0; } BŁĄD BŁĄD BŁĄD 1

37 Operator new służy do tworzenia obiektu int *wsk; wsk=new int;
Operatory new i delete Operator new służy do tworzenia obiektu int *wsk; wsk=new int; Operator delete zwalnia pamięć delete wsk; 002CFE90 002CFE93 004FA0F8 wsk Obszar zarezerwowany 004FA0F8 004FA0FB Obiekty tworzone operatorem new nie mają nazwy, ale istnieje wskaźnik na niego pokazujący

38 Operatory new[] i delete[]
Operator new[] służy do tworzenia wielu obiektów (tablicy) int *wsk; wsk=new int[3]; Operator delete[] zwalnia pamięć delete[] wsk; 0021FA60 0021FA63 006642B8 wsk 006642B8 006642BB Obszar zarezerwowany 006642BC 006642BF 006642C0 006642C3

39 Priorytety 18 17 ++ -- POST () [] 16
++ -- PRE + - ! ~ * & new delete new[] delete[] 15 14 * / % 13 + - 12 << >> 11 < <= > >= 10 == != 9 & 8 ^ 7 | 6 && 5 || 4 ? : 3 = *= /= %= += -= <<= >>= &= |= ^= 2 1 ,

40 Operatory new i delete int main() { int *w; w = new int; *w = 5; cout << w << endl << *w << endl; int *v = w; delete w; cout << v << endl << *v << endl; system("pause"); return 0; } 0062A110 5 0062A110 44

41 Dynamiczne tworzenie tablic
int *w=new int[n]; 2D int **w = new int*[n]; for(int i=0;i<n;i++)     w[i] = new int[m]; 3D int ***w = new int**[n];     w[i] = new int*[m];     for(int j=0;j<m;j++) w[i][j] = new int[o];

42 Usuwanie tablic 1D delete [] w; 2D for(int i=0;i<n;i++)
    delete [] w[i]; 3D     for(int j=0;j<m;j++) delete [] w[i][j];

43 Dynamiczne tworzenie tablicy 2D
0031FC3C 0031FC3F 00658E58 tab 0031FC40 0031FC43 2 m 0031FC44 0031FC47 3 n int n=3,m=2; int **tab; tab=new int *[n]; for (int i=0; i<n; i++) tab[i]=new int [m]; 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; for (int i = 0; i < n; i++) delete[] tab[i]; delete[] tab; 00658E58 00658E5B 00651F10 int* 00658E5C 00658E5F 00651F20 int* 0031FC3C 00658E60 00658E63 00651F30 int* 00658E58 00651F14 00651F10 00651F13 1 int 00651F20 00651F14 00651F17 2 int 00651F20 00658E5C 00651F20 00651F23 3 int 3 00651F24 00651F27 4 int 4 00651F20 00651F30 00651F33 5 int 00651F34 00651F37 6 int

44 Dynamiczne tworzenie tablicy 2D
Konieczne jest dołączenie biblioteki typeinfo int n=3,m=2; int **tab; tab=new int *[n]; for (int i=0; i<n; i++) tab[i]=new int [m]; for (int j=0; j<m; j++) tab[i][j]=i*m+j+1; cout<<typeid(n).name()<<endl; cout<<typeid(&n).name()<<endl; 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 int int *

45 Dynamiczne tworzenie tablic
int main() { int n; cout << "Podaj rozmiar tablicy\n"; cin >> n; int *w = new int[n]; for (int i = 0; i < n; i++) w[i] = i; for (int i = 0; i<n; i++) cout << *(w + i) << endl; delete[] w; system("pause"); return 0; } Stworzenie Wypełnienie Wypisanie Usunięcie

46 Dynamiczne tworzenie tablic 2-D
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++) { cout << *(*(wsk + i) + j) << '\t'; cout << endl;} delete[] wsk[i]; delete[] wsk; return 0; } Stworzenie Wypełnienie Wypisanie Usunięcie

47 Inicjalizacja dynamicznie tworzonych tablic – począwszy od wersji C++ 11
int *t_1D = new int[3]{ 1,2,3 }; 2D int **t_2D = new int*[2]{ new int[3]{1,2,3}, new int[3] {4,5,6} }; Tworzenie stałej tablicy const int *t_1D = new int[3]{ 1,2,3 }; const int **t_2D = new int*[2]{ new int[3]{1,2,3}, new int[3] {4,5,6} }; Tworząc tablicę za pomocą operatora new nie można pominąć jej wielkości nawet gdy jest ona inicjalizowana!

48 Przesyłanie do funkcji tablic 1D
void wypisz(int t[], int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int t1[3] = { 1,2,3 }; const int t2[3] = { 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 BŁĄD Argument formalny funkcji wypisz nie jest tablicą stałą

49 Przesyłanie do funkcji tablic 1D
void wypisz(const int t[], int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int t1[3] = { 1,2,3 }; const int t2[3] = { 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 4 5 6

50 Przesyłanie do funkcji tablic 1D
void wypisz(int *t, int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int t[3] = { 1,2,3 }; wypisz(t, 3); system("pause"); Zachodzi konwersja tablicy na wskaźnik: int [] -> int * Konwersja trywialna 1 2 3

51 Przesyłanie do funkcji tablic 1D
void wypisz(int t[], int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int *t = new int[3]{ 1,2,3 }; wypisz(t, 3); system("pause"); Konwersja int * -> int [] nie zajdzie, ale argument formalny i tak jest traktowany jako wskaźnik. 1 2 3

52 Przesyłanie do funkcji tablic 1D
void wypisz(int *t, int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int t1[3] = { 1,2,3 }; const int t2[3] = { 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 BŁĄD Argument formalny funkcji wypisz nie jest wskaźnikiem do pokazywania na stałe obiekty

53 Przesyłanie do funkcji tablic 1D
void wypisz(const int *t, int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int t1[3] = { 1,2,3 }; const int t2[3] = { 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 4 5 6

54 Przesyłanie do funkcji tablic 1D
void wypisz(int *t, int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int *t1 = new int[3]{ 1,2,3 }; const int *t2 = new int[3]{ 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 BŁĄD Argument formalny funkcji wypisz nie jest wskaźnikiem do pokazywania na stałe obiekty

55 Przesyłanie do funkcji tablic 1D
void wypisz(const int *t, int n) { for (int i = 0; i < n; ++i) cout << t[i] << endl; } int main() int *t1 = new int[3]{ 1,2,3 }; const int *t2 = new int[3]{ 4,5,6 }; wypisz(t1, 3); wypisz(t2, 3); system("pause"); 1 2 3 4 5 6

56 Przesyłanie do funkcji tablic 2D
void wypisz(int t[][3], int n) { for (int i = 0; i < n; ++i) { for (int j = 0; j < 3; ++j) cout << t[i][j] << '\t'; cout << endl; } int main() int t[][3] = { 1,2,3,4,5,6 }; wypisz(t, 2); system("pause"); 1 2 3 4 5 6

57 Przesyłanie do funkcji tablic 2D
void wypisz(int **t, int n, int m) { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) cout << t[i][j] << '\t'; cout << endl; } int main() int t[][3] = { 1,2,3,4,5,6 }; wypisz(t, 2, 3); system("pause"); BŁĄD Nie zajdzie konwersja tablicy dwuwymiarowej na wskaźnik do wskaźnika int [][] -> int **

58 Dlaczego nie zachodzi konwersja int[][]->int **
Argument aktualny: int t[][3] = { 1,2,3,4,5,6 }; cout<<t; Argument formalny: int **t 0014FA48 0014FA4B 0015A110 t 0015F730 0015F733 1 0015F734 0015F737 2 0015A110 0015A113 0015F730 t[0] 0015F738 0015F73B 3 0015A114 0015A117 0015F73C t[1] 0015F73C 0015F73F 4 0015F740 0015F743 5 0015F730 0015F733 1 0015F744 0015F747 6 0015F734 0015F737 2 0015F738 0015F73B 3 0015F730 0015F73C 0015F73F 4 0015F740 0015F743 5 0015F744 0015F747 6

59 Przesyłanie do funkcji tablic 2D
void wypisz(int *t[], int n, int m) { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) cout << t[i][j] << '\t'; cout << endl; } int main() int t[][3] = { 1,2,3,4,5,6 }; wypisz(t, 2, 3); system("pause"); BŁĄD Nie zajdzie konwersja tablicy dwuwymiarowej na tablicę wskaźników int [][] -> int *[]

60 Dlaczego nie zachodzi konwersja int[][]->int *[]
Argument aktualny: int t[][3] = { 1,2,3,4,5,6 }; cout<<t; Argument formalny: int *t[] cout<<t; 0015F730 0015F733 1 0015A110 0015A113 0015F730 t[0] 0015F734 0015F737 2 0015A114 0015A117 0015F73C t[1] 0015F738 0015F73B 3 0015F73C 0015F73F 4 0015F730 0015F733 1 0015F740 0015F743 5 0015F734 0015F737 2 0015F744 0015F747 6 0015F738 0015F73B 3 0015F73C 0015F73F 4 0015F730 0015F740 0015F743 5 0015F744 0015F747 6 0015A110

61 void wypisz(int **t, int n, int m)
{ for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) cout << t[i][j] << '\t'; cout << endl; } int main() int t[][3] = { 1,2,3,4,5,6 }; int *t1[] = { &t[0][0], &t[1][0] }; int **w = new int*[2]{ &t[0][0], &t[1][0] }; wypisz(t1, 2, 3); wypisz(w, 2, 3); system("pause"); void wypisz(int *t[], int n, int m) { for (int i = 0; i < n; ++i) { for (int j = 0; j < m; ++j) cout << t[i][j] << '\t'; cout << endl; }

62 Funkcja zwracająca tablicę
int *fun() { int tab[5]; for (int i = 0; i < 5; ++i) tab[i] = i; cout << tab[i] << endl; return tab; } int main() int *w; w=fun(); for (int i=0; i<5; ++i) cout << w[i] << endl; return 0; Obszar wolny 0025FB50 0025FB53 0025FB54 w 0025FB FB57 1 2 3 4 0025FB FB5B 1 0025FB5C 0025FB5F 2 0025FB FB63 3 0025FB FB67 4

63 Funkcja zwracająca tablicę
Obszar zarezerwowany int *fun() { int *tab = new int[5]; for (int i = 0; i < 5; ++i) tab[i] = i; cout << tab[i] << endl; return tab; } int main() int *w; w=fun(); for (int i=0; i<5; ++i) cout << w[i] << endl; return 0; 0041FB54 0041FB57 005090F0 w 0041FB58 0041FB5B 005090F0 tab 1 2 3 4 005090F0 005090F3 005090F4 005090F7 1 005090F8 005090FB 2 005090FC 005090FF 3 4 1 2 3 4

64 Odbieranie tablic 2-D od funkcji
int **tworz(); int main() { int **t; t = tworz(); for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) cout << *(*(t + i) + j) << '\t'; cout << endl; } system("pause"); return 0; int **tworz() { int tab[3][3]; for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) tab[i][j] = i*3 + j; return tab; } BŁĄD

65 Odbieranie tablic 2-D od funkcji
int **tworz(); int main() { int **t; t = tworz(); for (int i = 0; i < 3; ++i) for (int j = 0; j < 3; ++j) cout << *(*(t + i) + j) << '\t'; cout << endl; } system("pause"); return 0; int **tworz() { int **tab = new int*[3]; for (int i = 0; i < 3; ++i) tab[i] = new int[3]; for (int j = 0; j < 3; ++j) tab[i][j] = i*3 + j; return tab; } 0 1 2 3 4 5 6 7 8

66 Argumenty z linii wywołania programu
Liczba argumentów przekazanych do funkcji main Tablica wskaźników zawierająca argumenty jako napisy – każdy element tablicy to typ char * #include<iostream> using namespace std; int main(int argc, char *argv[]) { cout<<"Dostalem parametrow: "<<argc<<endl<<endl; for (int i=0; i<argc; i++) cout<<i<<" parametr to\t"<<argv[i]<<endl; return 0; }

67 00762B1B . 00762B1C e 002CF92C 002CF92F 4 argc 00762B1D x 002CF930 002CF933 00762B00 argv 00762B1E e 00762B1F \NULL 00762B00 00762B03 00762B14 00762B20 A 00762B04 00762B07 00762B20 00762B21 G 00762B08 00762B0B 00762B24 00762B22 H 00762B0C 00762B0F 00762B26 00762B23 \NULL 00762B24 1 00762B14 p 00762B25 \NULL 00762B15 r 00762B26 3 00762B16 o 00762B27 . 00762B17 g 00762B28 1 00762B18 r 00762B29 4 00762B19 a 00762B30 \NULL 00762B1A m

68 Prezentacja udostępniona na licencji Creative Commons: Uznanie autorstwa, Na tych samych warunkach 3.0. Pewne prawa zastrzeżone na rzecz autorów. Zezwala się na dowolne wykorzystywanie treści pod warunkiem wskazania autorów jako właścicieli praw do prezentacji oraz zachowania niniejszej informacji licencyjnej tak długo, jak tylko na utwory zależne będzie udzielana taka sama licencja. Tekst licencji dostępny jest na stronie:


Pobierz ppt "Język C++ Wskaźniki Łukasz Sztangret Katedra Informatyki Stosowanej i Modelowania Prezentacja przygotowana w oparciu o materiały Danuty Szeligi i Pawła."
Reklamy Google