Programowanie obiektowe W3 Przegląd typów strukturalnych w C++ : tablice statyczne i dynamiczne Dr hab. inż. Lucyna Leniowska, prof. UR Zakład Mechatroniki, Automatyki i Optoelektroniki
Typy złożone: tablice Tablica jest złożoną strukturą danych, składającą się z elementów tego samego typu. Zajmuje ona ciągły obszar pamięci o rozmiarze niezbędnym do zapamiętania jej elementów. W deklaracji tablicy należy określić typ wartości, jakie ma przechowywać tablica, a także liczbę jej elementów. Tablica zdefiniowana jest zgodnie z następującym szablonem: typ nazwa[ilosc_elementow]; Rozpoczyna się od typu elementów, które są w niej przechowywane, a po nim następuje nazwa tablicy. Od deklaracji zwykłej zmiennej odróżnia ją ilość elementów podana w nawiasach kwadratowych.
Deklarowanie tablicy Tablice statyczne jednowymiarowe 1.int wynik_egzaminu [50]; Kompilator C++ przydzieli zmiennej wyniki_egzaminu tyle pamięci, by mogła przechowywać 50 liczb typu int. 2. Tablicy możemy nadać wartości początkowe przy deklaracji: int tablica[3] = {1,2,3; 3. Po ostatnim elemencie tablicy może występować przecinek, a jeżeli poda się tylko część wartości, to dopisywane są zera: int tablica[20] = {1,; 4. Niekoniecznie trzeba podawać rozmiar tablicy, np.: int tablica[] = {1, 2, 3, 4, 5; W takim przypadku kompilator sam ustali rozmiar tablicy
Tablice dwuwymiarowe i wielowymiarowe Tablice w C++ mogą być wielowymiarowe. Deklaracja tablicy N-wymiarowej : typ-elementów identyf_tablicy [wymiar1][wymiar2]..[wymiarn]; Możemy na przykład zdefiniować macierz, czyli tablicę dwuwymiarową. Dwuwymiarowa tablica liczb całkowitych: int tab[4][4]; Analogicznie wygląda także inicjowanie elementów tablicy. int tab2[2][2] = {{3,-10),{90,20; float macierz[][4] = { { 1.6, 4.5, 2.4, 5.6, /* pierwszy wiersz */ { 5.7, 4.3, 3.6, 4.3, /* drugi wiersz */ { 8.8, 7.5, 4.3, 8.6, /* trzeci wiersz */ { 6.3, 2.7, 5.7, 2.7 /* czwarty wiersz */ ;
Dostęp do elementów tablicy Dostęp do elementu jest możliwy za pośrednictwem indeksów. Zakres indeksów tablicy rozpoczyna się od 0, a więc ostatni element równy jest ilości elementów minus 1. np. int t[4];// czteroelementowa tablica elementów typu int : //t[0], t[1], t[2], t[3], element t[4] nie istnieje Elementy tablic nie są inicjowane zerami w chwili deklaracji: int tablicaint[10]; Zerowanie: for(int i=0;i<10;i++) tablicaint[i]=0;
Wpisywanie wartości do tablic Na ekranie zobaczymy: Liczba t[0]=0 Liczba t[1]=100 Liczba t[2]=200 Liczba t[3]=300
Wpisywanie wartości do tablic c.d. #include <iostream> /* using namespace std; nie zaleca się*/ int main(void) { int liczby [5]; //Deklaracja tablicy liczby [0] = 100; liczby [1] = 200; liczby [2] = 300; liczby [3] = 400; liczby [4] = 500; std::cout << "Tablica zawiera następujące wartości:" <<std::endl; for (int i = 0; i < 5; i++){ cout << liczby [i] << ' '; std::cout << '\n'<<"jeszcze raz wyświetlamy: "<<std::endl; //Jeżeli zmienimy pętlę w programie na następującą: for (int i = 4; i >= 0; i--) { std::cout << liczby [i] << ' '; return 0; Na ekranie zobaczymy: Tablica zawiera następujące wartości: 100 200 300 400 500 Jeszcze raz wyswietlamy: 500 400 300 200 100
Losowanie wartości do tablic tablica jednowymiarowa #include <iostream> #include <cstdlib> #include <ctime> /*using namespace std; nie zaleca się*/ int main(void) { short tab[10]; std::srand( time( NULL ) ); for(int i=0; i<10; i++) { tab[i]= rand(); std::cout << "Liczba tab[" << i << "]="<< tab[i]<< std::endl; return 0; Na ekranie zobaczymy: Liczba tab[0]=24139 Liczba tab[1]=13205 Liczba tab[2]=2056 Liczba tab[3]=15216 Liczba tab[4]=17892 Liczba tab[5]=21425 Liczba tab[6]=4416 Liczba tab[7]=6241 Liczba tab[8]=9601 Liczba tab[9]=12494
Losowanie wartości do tablic c.d. tablica dwuwymiarowa #include <iostream> #include <cstdlib> #include <ctime> int main(void) { short tab[3][4]; //inicjacja std::srand( time( NULL ) ); for(int i=0;i<3;i++) { for(int j=0;j<4;j++){ tab[i][j]= rand() % 41-20; std::cout << "tab[" << i << "]"<< "["<< j<< "]= << tab[i][j]<<std::endl; return 0; Na ekranie zobaczymy: tab[0][0]=-3 tab[0][1]=-19 tab[0][2]=2 tab[0][3]=-4 tab[1][0]=18 tab[1][1]=-14 tab[1][2]=7 tab[1][3]=-10 tab[2][0]=-5 tab[2][1]=4 tab[2][2]=-13 tab[2][3]=9
Przekazywanie tablicy do funkcji
Przekazywanie tablicy do funkcji c.d. Do funkcji można też wysłać jeden element tablicy, np. void funk( int x ) ; int tabl[10]; wywołanie : funk(tabl[5]);
Przekazywanie tablicy do funkcji - #include <iostream> przykład void wypisz_tablice (int tablica[], int liczba_elementow) { for (int i = 0; i < liczba_elementow; i++) std::cout << tablica[i] << ' '; std::cout << std::endl; int main(void) { int male_liczby[5] = {1, 2, 3, 4, 5; int duze_liczby[3] = {1000, 2000, 3000; wypisz_tablice (male_liczby, 5); wypisz_tablice (duze_liczby, 3); return 0; Na ekranie zobaczymy: 1 2 3 4 5 1000 2000 3000
Definiowanie aliasów typów -typedef
Tablice dynamiczne Podstawowym ograniczeniem tablic statycznych jest ich z góry określona wielkość. W C++ wprowadzono możliwość deklarowania tzw. tablic dynamicznych. Do określenia wielkości tablicy tworzonej dynamicznie możemy użyć zmiennej, której wartość może być określona/wczytywana przez użytkownika. Pamięć zarezerwowana przez tablice dynamiczne nie zostanie automatycznie zwolniona. Do jej zwolnienia korzystamy z operatora delete[]
Tablice dynamiczne c.d. W języku C do przydzielania i zwalniania pamięci służyły głównie funkcjemalloc() i free(). W języku C++ do alokowania pamięci służy operator new, a do zwalniania delete. Dynamiczne przydzielenie pamięci dla tablicy: Typ_zm* nazwa = new typ_zm[ ilosc_elementow]; Np. int* wektor = new int[10]; // alokowanie pamięci dla tablicy delete[] wektor; // zwalnianie pamięci
Tablice dynamiczne c.d. Za pomocą operatora new można również tworzyć tablice wielowymiarowe: int** tablica = new int*[8]; for (int i = 0; i < 8; ++i) tablica[i] = new int [10]; W ten sposób stworzono tablicę dynamiczną dwuwymiarową którą statycznie zadeklarowalibyśmy jako: int tablica[8][10]; Tablice tworzone dynamicznie są automatycznie inicjowane zerami
Przykład: Dana jest tablica dynamiczna prostokątna A. Utworzyć tablicębprzez skreślenie i-tego wiersza i j-tej kolumny na przecięciu których znaleziono największy element tej macierzy. #include <cassert> #include <cstdlib> #include <iostream> // funkcje wypisujace tablice na ekran void print(int* tablica, size_t n) { std::cout << "[ "; for (size_t ii = 0; ii < n; ++ ii) std::cout << tablica[ii] << " "; std::cout << "]" << std::endl; void print(int** tablica, size_t n, size_t m) { for (size_t ii = 0; ii < m; ++ ii) print(tablica[ii], n);
//wybór max w tablicy input i zapamiętanie indeksów int** wyszukaj(int** input, size_t n, size_t m) { assert(n > 0 && m > 0); size_t imax = 0, jmax = 0; for (size_t ii = 0; ii < m; ++ ii) { for (size_t jj = 0; jj < n; ++ jj) { if (input[ii][jj] > input[imax][jmax]) { imax = ii; jmax = jj;
// przepisanie wartości z tablicy input do nowej (n-1)x(m-1) tablicy output int** output = new int*[m-1]; // alokacja tablicy for (size_t ii = 0; ii < imax; ++ ii) { output[ii] = new int[n-1]; for (size_t jj = 0; jj < jmax; ++ jj) output[ii][jj] = input[ii][jj]; //przepisano wartości do indeksu jmax for (size_t jj = jmax+1; jj < n; ++ jj) // dalsza część przepisywania output[ii][jj-1] = input[ii][jj]; for (size_t ii = imax+1; ii < m; ++ ii) { output[ii-1] = new int[n-1]; // przepisano wartości do indeksu imax for (size_t jj = 0; jj < jmax; ++ jj) // dalsza część przepisywania output[ii-1][jj] = input[ii][jj]; for (size_t jj = jmax+1; jj < n; ++ jj) output[ii-1][jj-1] = input[ii][jj]; return output;
//funkcja inicjuje tablicę, wykonuje działania i wyświetla wynik void wykonaj() { int** t0 = new int*[3]; t0[0] = new int[4]; t0[1] = new int[4]; t0[2] = new int[4]; //alokacja pamięci t0[0][0] = 0; t0[0][1] = 1; t0[0][2] = 2; t0[0][3] = 3; t0[1][0] = 2; t0[1][1] = 3; t0[1][2] = 9; t0[1][3] = 5; t0[2][0] = 4; t0[2][1] = 5; t0[2][2] = 6; t0[2][3] = 7; std::cout << "Dane początkowe: \n"; print(t0, 4, 3); std::cout << std::endl; int** result0 = wyszukaj(t0, 4, 3); std::cout << "Tablica po usunieciu wiersza i kolumny \n na przecięciu których znaleziono największy element: \n"; print(result0, 3, 2); std::cout << std::endl; // trzeba usunąć tablice for (size_t ii = 0; ii < 3; ++ ii) delete[] t0[ii]; delete[] result0;
//funkcja main i efekt działania int main() { std::cout << "Tablica 3x4 \n\n"; wykonaj(); return 0; Na ekranie zobaczymy: Tablica 3x4 Dane początkowe: [ 0 1 2 3 ] [ 2 3 9 5 ] [ 4 5 6 7 ] Tablica po usunięciu wiersza i kolumny na przecięciu których znaleziono największy element: [ 0 1 3 ] [ 4 5 7 ]