260 likes | 392 Views
Zachodniopomorska Szkoła Biznesu. Podstawy programowania. Wykład 5: Tablice i wskaźniki. Dane złożone. Często do opisu pewnego obiektu lub grupy obiektów nie wystarcza pojedyncza zmienna konieczne jest wtedy zdefiniowanie zbioru różnych zmiennych, które tworzą pewną całość
E N D
Zachodniopomorska Szkoła Biznesu Podstawy programowania Wykład 5: Tablice i wskaźniki
Dane złożone • Często do opisu pewnego obiektu lub grupy obiektów nie wystarcza pojedyncza zmienna • konieczne jest wtedy zdefiniowanie zbioru różnych zmiennych, które tworzą pewną całość • W języku C++ dla opisu takiej sytuacji stosuje się typy złożone, które pozwalają pod jedną nazwą zmiennej pozwalają ukryć wiele prostych wartości • Najważniejsze typy złożone: • tablica • struktura (rekord) • klasa (programowanie obiektowe) Podstawy programowania - Tablice i wskaźniki
Tablice • Stosowane są gdy chcemy w sposób uporządkowany zapisać zbiór wartości tego samego typu, np. • oceny poszczególnych studentów z grupy • ceny produktów w ofercie • nazwiska znajomych • Każdy element tablicy ma swój indeks (numer), który jednoznacznie go identyfikuje • Można powiedzieć, że tablica to uporządkowany zbiór zmiennych jednakowego typu • Zdefiniowanie tablicy wymaga podania typu elementu oraz liczby elementów • Ze względu na sposób uporządkowania elementów można wyróżnić tablice jednowymiarowe, dwuwymiarowe, itd. • Rozmiar tablicy (liczba elementów) musi być określona już w trakcie pisania programu Podstawy programowania - Tablice i wskaźniki
Deklaracja tablicy jednowymiarowej • Składnia: typ nazwa[liczba_elementów]; // całkowita>0 • Przykłady float oceny_grupy[30]; int duzy_lotek[6]; int a,b[10],c,d[2]; // b,d - tablice • Inicjalizacja tablicy: float punkt3D[3] = {0, 2, 1.5 }; int duzy_lotek[3+3]= {2,4,6,7}; // można mniej Nie można podać więcej wartości niż zdefiniowano w tablicy. b[0] b[1] b[2] b[3] b[4] b[5] b[6] b[7] b[8] b[9]tablica b: Podstawy programowania - Tablice i wskaźniki
Korzystanie z tablicy • Dostęp do tablicy odbywa się dla każdego elementu osobno, każdy z nich można wykorzystywać jak normalną zmienną, należy w tym celu podać nazwę tablicy oraz wyrażenie określające indeks pomiędzy znakami: ‘[‘ i ‘]‘ • Indeksy elementów w C++ zaczynają się zawsze od 0 !!!Jeżeli wielkość tablicy to N, indeksy elementów to 0 ... N-1 • Nie wolno korzystać z elementów o indeksach wykraczających poza zadeklarowany zakres • Przykłady:int x,tablica[10];tablica[0]=1;tablica[5]=2;tablica[6]=tablica[5]+2;x=2*tablica[6];tablica[x+1]=10; // obliczenie indeksutablica[10]=0; // błąd: poza tablicą!!!jakie wartości są teraz w tablicy? Podstawy programowania - Tablice i wskaźniki
Algorytmiczny dostęp do tablicy • Wykorzystanie zmiennych do określania indeksu umożliwia dostęp do poszczególnych elementów za pomocą pętli, zwykle jest to pętla for • Przykładowy fragment programu:float tablica[10];for (int i=0; i<5; i++) // zerowanie elementów 0-4 tablica[i]=0;for (i=5; i<10; i++) tablica[i]=i-1; // el. 5-9, wartości 4-8tablica po wykonaniu programu: Podstawy programowania - Tablice i wskaźniki
Sumowanie elementów tablicy #include <iostream.h> #define N 10 void main() { int i, tab[N]; // N to nie zmienna!for (i=0; i<N; i++) // pobieranie danych{ cout << "Podaj element " << i << ":"; cin >> tab[i];}int suma=0; // obowiązkowe wyzerowaniefor (i=0; i<N; i++) suma+= tab[i]; // czyli suma=suma+tab[i]cout << ”Średnia wartość:” << (float)suma/N << endl; } Podstawy programowania - Tablice i wskaźniki
Wartość maksymalna / minimalna float tab[10];... // pomijamy wprowadzaniefloat min=tab[0], max=tab[0];int nrmin=0, nrmax=0;for (int i=0; i<N; i++) // szukamy największego if (tab[i]>max) { max=tab[i]; nrmax=i; }for (i=0; i<N; i++) // szukamy najmniejszego if (tab[i]<min) { min=tab[i]; nrmin=i; } cout << ”Największy jest element: ” << nrmax;cout << ", wynosi: " << max << endl;cout << ”Najmniejszy jest element: ” << nrmin;cout << ", wynosi: " << min << endl; Podstawy programowania - Tablice i wskaźniki
Szukanie i zliczanie elementów spełniających podane kryterium float tab[10];... // pomijamy wprowadzanieint licznik=0;// wyzerowanie licznika for (int i=0; i<N; i++){ cout << "element " << i << ": ";if (tab[i]>0)// szukamy liczb dodatnich { cout << tab[i] << " jest dodatni\n";licznik++; }}cout << "Dodatnie : " << licznik << endl;cout << "Niedodatnie: " << N-licznik << endl; Podstawy programowania - Tablice i wskaźniki
Tablica jako parametr funkcji • Jeżeli funkcja przyjmuje tablicę jako parametr, wyjątkowo nie jest ona przesyłana jako kopia. Przesyłany jest adres tablicy źródłowej. Funkcja może więc zmienić zawartość tej tablicy • W nagłówku funkcji można pominąć rozmiar tablicy ponieważ nie jest to deklaracja nowej tablicy (pamięć już przydzielono) • Przykład: void zeruj(float tab[], int n){ for (int i=0; i<n; i++) tab[i]=0.0;}void main(){ float tablica[10]; zeruj(tablica, 10);} Podstawy programowania - Tablice i wskaźniki
Deklaracja tablicy dwuwymiarowej • Można myśleć o takiej tablicy jak o macierzy prostokątnej • Zawiera więc ona NxM elementów, które uporządkowane są w N kolumn i M wierszy • W składni języka C++ należy ją rozumieć jako tablicę tablic • Składnia: typ nazwa[M][N]; // tablica M tablic N-element. • Przykład: float oceny[30][5]; // 30 studentów po 5 ocen • Dostęp do elementu (wiersz i, kolumna j): nazwa[i][j];np.oceny [1][3]; • Każdy z indeksów numerowany jest od 0! 5 30 ... Podstawy programowania - Tablice i wskaźniki
Korzystanie z tablicy dwuwymiarowej • W celu przetworzenia wszystkich elementów tablicy z reguły używa się dwóch zagnieżdżonych pętli for (pętla w pętli) • Przykład: utworzenie i wydruk macierzy jednostkowej 10x10: float macierz [10][10];for (int i=0; i<10; i++) // kolejne wiersze for (int j=0; j<10; j++) // kolejne kolumny if (i==j) macierz[i][j]=1; else macierz[i][j]=0;// krócej: macierz[i][j]= (i==j); for (i=0; i<10; i++){ for (j=0; j<10; j++) cout << macierz[i][j] << " "; cout << endl;} Podstawy programowania - Tablice i wskaźniki
Tablica dwuwymiarowa jako parametr funkcji void zerujmacierz(float tab[][5], n) // n wierszy for (int i=0; i<n; i++) // m musimy znać for (int j=0; j<5; j++) tab[i][j]=0.0;}void zerujwiersz(float tab[], m) // m - dł. wiersza{ for (int i=0; i<n; i++) tab[i]=0.0;}void main(){ float tablica[10][5]; zerujmacierz(tablica,30); zerujwiersz(tablica[2], 5); // zerujemy wiersz 2} Podstawy programowania - Tablice i wskaźniki
Wskaźniki • W wielu sytuacjach istnieje potrzeba przechowywania lub przesyłania informacji na temat położenia zmiennej w pamięci. • W języku C/C++ służą do tego zmienne o specjalnych typach danych zwanych wskaźnikami (ang. pointer)Zawierają one informacje o: • adresie danej w pamięci - • typie danej (a więc i o jej rozmiarze w bajtach) • Każdemu z typów podstawowych można przypisać typ wskaźnikowy przeznaczony do pokazywania na zmienne tego typu. Typ wskaźnikowy określany jest za pomocą operatora *, jako typ * , np. wskaźnik do zmiennej typu int to int * • Pobranie adresu zmiennej odbywa się za pomocą operatora &,a pobranie wartości z adresu, na który pokazuje wskaźnik - za pomocą operatora * stojącego po jego lewej stronie • Uwaga! Wskaźnik zawsze na coś pokazuje! Podstawy programowania - Tablice i wskaźniki
Wskaźniki - przykład void main() {int a=10,b=20; int *iwsk; // wskaźnik na int iwsk=&a; // iwsk pokazuje teraz na a b= *iwsk+1; // pobranie wartości spod adresuiwsk=&b; // iwsk pokazuje teraz na b float x, *fwsk; // fwsk jest typu float*iwsk= &x; // błąd - inny typ wskaźnika!!!fwsk=iwsk; // j.w.fwsk=&x;x=5;cout << *fwsk<< endl; // wypisze 5x=6;cout << *fwsk<< endl; // wypisze 6 ! } Podstawy programowania - Tablice i wskaźniki
Operacje na wskaźnikach • Porównywanie (operatory ==, !=, <, >, <=, >=) porównywane są adresy zapisane we wskaźnikach, ale typy bazowe muszą być jednakowe • Odejmowanie wskaźnikówmożna odjąć dwa wskaźniki o jednakowych typach bazowych. Wynikiem będzie różnica adresów podzielona przez rozmiar typu bazowego (ile elementów dzieli te adresy) • Dodawanie/odejmowanie od wskaźnika wartości całkowitej oznacza przesunięcie zapisanego adresu o podaną liczbę elementów. Liczba bajtów przesunięcia zależy od rozmiaru typu bazowego.Można korzystać również z operatorów ++ i -- • Wskaźnik zerowy (NULL)wartość 0 jako jedyna traktowana jest jako nie wskazująca na nic. Symbol NULL zdefiniowany jest w stdio.h, stdlib.h, i w iostream.h Podstawy programowania - Tablice i wskaźniki
Przykłady operacji na wskaźnikach int *wsk1, *wsk2=NULL; *wsk1=5; // uwaga! wskaźnik przypadkowy!!! *wsk2=5; // tutaj zareaguje system int a,b,c; wsk1=&a; wsk2=&c; cout << "Adres a: " << wsk1 << end; // można wypisywać cout << "Następny po a: " << wsk1+1 << endl; cout << "Różnica c i a to: " << wsk2-wsk1 << endl; cout << "większy: ((wsk1>wsk2) ? wsk1 : wsk2) << endl; Podstawy programowania - Tablice i wskaźniki
Typ void * • Jest to wskaźnik uniwersalny, który może pokazywać na każdy typ danych • Nie posiada jednak informacji o typie, a więc i o rozmiarze pokazywanego elementu • Nie można jednak stosować wobec niego operatora * (odczytywać danej, na którą pokazuje) • Nie można stosować do niego dodawania stałej, ani odejmować takich wskaźników (nieznany jest rozmiar elementu) • Można do niego przypisać wartość dowolnego innego wskaźnika(niejawna konwersja typu) • Przypisanie wartości wskaźnika void * do innego wskaźnika, a także odczyt pokazywanej danej są możliwe ale wymagają jawnej konwersji • Stosuje się go do wskazywania danych o nieokreślonej postaci Podstawy programowania - Tablice i wskaźniki
Przykłady użycia void * void *adres;int *iwsk;float *fwsk; int i=5,j;float f; adres=&i; // tu nie trzeba konwersjiiwsk=adres;// nie uda sięiwsk=(int *) adres; // konwersja jawna - uda się!fwsk=(float *)adres; // to też się uda!j=*adres;// to się nie udaj=*iwsk; f=*fwsk; // ciekawe co jest w f ??? Podstawy programowania - Tablice i wskaźniki
Wskaźnik a tablica • Nazwa tablicy (bez nawiasów []) jest wskaźnikiem do jej zerowego (początkowego) elementu • Jest to wskaźnik, którego wartości nie można zmienić (wskaźnik stały). Można jednak używać go w różnych wyrażeniach • Do wskaźnika wolno użyć nawiasów [], tak, jak gdyby był on zadeklarowany jako tablica jednowymiarowa • Przykłady: int tab[10];int *poczatek=tab; // wskazuje na tab[0]int *koniec=tab+9; // wskazuje na tab[9]int numer2= tab[2]; // tablica normalnie numer2= *(tab+2); // tab. jako wskaźnik numer2= *(poczatek+2); // wskaźnik normalnie numer2= poczatek[2]; // wskaźnik jako tab tab=&numer2;// błąd! wskaźnik stały Podstawy programowania - Tablice i wskaźniki
Typ char - stałe i zmienne • Jest to typ znakowy, przydatny do przetwarzania tekstu, obsługi klawiatury i ekranu • Pozwala na zapamiętanie jednego znaku w postaci tzw. kodu ASCII (jednobajtowa liczba całkowita) • Domyślnie signed/unsigned zależy od kompilatora • Wartość typu char można traktować w wyrażeniach jako liczbę całkowitą, konwersje znak - liczba odbywają się automatycznie • Stałe znakowe • znak pomiędzy parą znaków' i', np. 'A', '0', '@' • znak \ i kod ASCII pomiędzy parą znaków' i', np. '\65', '\0' • W przypadku przypisania liczby do zmiennej znakowej, następuje automatyczna konwersja na znak o podanym kodzie ASCII • Znaki specjalne'\n'(new line),'\t'(tab), '\\', '\'', '\"' Podstawy programowania - Tablice i wskaźniki
Typy char[]i char * • W celu zapisu tekstu tworzy się tablice znaków.W języku C wprowadzono konwencję, zgodnie z którą tekst kończy się znakiem '\0' (na który trzeba przewidzieć dodatkowy bajt w tablicy) - tzw. null-terminated string • Praca z taką tablicą wymaga zwykle przetwarzania każdego znaku z osobna. Stosuje się do tego pętle, najczęściej pętlę for.W całości można jedynie dokonać inicjalizacji tablicy.Operacje na całym tekście można też wykonywać z udziałem wielu funkcji bibliotecznych. • Zmienne typu char* wskazują na pojedyncze znaki, opisuje się też w ten sposób również cały tekst (wskazując pierwszy znak) • Stałe tekstowe zapisuje się pomiędzy parą znaków " i "Są one typu char* • Przydatne funkcje obsługujące teksty (zdefiniowane jako tablice lub wskaźniki) znaleźć można w pliku string.h Podstawy programowania - Tablice i wskaźniki
Przykłady pracy z tekstem char nazwisko[31]; // max. 30 znaków + '\0' char logo1[]= "ZPSB"; // wygodna inicjalizacja char logo2[]={'Z','P','S','B','\0'}; // tak też można char imie[20]="Michał"; // rozmiar jest większy nazwisko="Kowalski"// Błąd! stały wskaźnik! nazwisko[7]='a'; char *tekst=imie; *tekst='A'; //wstawimy "ABC" do imie *(tekst+1)='B'; tekst[2]='C'; tekst[3]=0; // koniec, konwersja z int cin >> nazwisko; // musi wystarczyć miejsca! cout << nazwisko<< endl; Podstawy programowania - Tablice i wskaźniki
Wskaźnik jako parametr funkcji (1) • Funkcja może jako parametr przyjmować wskaźnik. Wartość wskaźnika jest kopiowana, więc wskazuje on na tę samą zmienną, co wskaźnik wysłany jako parametr • Pozwala to funkcji na zmianę wartości tej zmiennej, co nie jest możliwe przy zwykłym przesyłaniu danych przez wartość • Przykład: void zeruj_ujemne (int *liczba){ if (*a<0) a=0;}void main(){ int a=-5; // tutaj a=-5 int *wsk=&a; zeruj_ujemne(wsk); // a tutaj już a=0 zeruj_ujemne(&a); // tak też można} Podstawy programowania - Tablice i wskaźniki
Wskaźnik jako parametr funkcji (2) • Wskaźnik służy też zwykle do przekazywania tablicy (także tekstu) jako parametr. • Często wykorzystuje się też wskaźniki, jeżeli funkcja generuje kilka różnych wartości wynikowych (zwrócić można tylko jedną) • Przykład (zliczanie wartości dodatnich i niedodatnich w tablicy): void plusminus(int *tab, int n, int *plus, int *minus){ int pl=0, min=0; // zmienne lokalne for (int i=0; i<n; i++) if (tab[i]>0) pl++; // wskaźnik jako tabl. else min++;*plus=pl; // przekazanie wyników*minus=min;} // nie ma return, a funkcja zwraca wynikivoid main(){ int tablica[20], ileplus, ileminus;plusminus(tablica, 20, &ileplus, &ileminus);} Podstawy programowania - Tablice i wskaźniki
To już jest koniec++ Dziękuję za uwagę