Tablice – TEORIA Tablica to ciąg obiektów tego samego typu, które zajmują ciągły obszar w pamięci. Dzięki stosowaniu tablic, zamiast nazywania każdej z np. stu zmiennych osobno możemy zabudować tablicę 100-elementową, a następnie odnosić się do poszczególnych elementów tablicy. Dla przykładu następująca definicja: int tab[100]; rezerwuje w pamięci miejsce dla 100 elementów typu int. Rozmiar tak definiowanej tablicy musi być stałą znaną już w momencie kompilacji, ponieważ kompilator musi już wtedy wiedzieć ile miejsca ma zarezerwować na daną tablicę. Tablice są typem pochodnym. Poniżej mamy przykłady deklaracji różnych tablic: char slowo[80]; // slowo jest tablicą 80 elementów typu char float ulamek[15]; // ulamek jest tablicą 15 elementów typu float unsigned long liczba[789]; //liczba - tablica 789 elementów typu unsigned long • Elementy tablicy Do poszczególnych elementów mamy dostęp poprzez ich numer kolejny w tablicy. Jeśli zdefiniujemy następującą tablicę: int tab[5]; to jest to tablica 5 elementów typu int a poszczególne elementy tej tablicy to: tab[0] tab[1] tab[2] tab[3] tab[4] Numerowanie elementów zawsze rozpoczyna się od zera, tzn. element pierwszy ma numer 0, a element ostatni numer (indeks) o jeden mniejszy od rozmiaru tablicy (czyli liczby elementów tablicy). Jeżeli o tym zapomnimy i będziemy chcieli wpisać coś do nieistniejącego elementu tab[5] to kompilator nie zasygnalizuje błędu, natomiast może to powodować nieprzewidziane skutki, w szczególności zmianę wartości innych zmiennych. W niektórych przypadkach (zależnie od implementacji i ustawień kompilatora) zostanie zniszczone w obszarze pamięci coś co następuje bezpośrednio za tablicą, jako ze przy powyższej definicji tablicy element tab[5] nie istnieje. Np. jeśli mamy następujące definicje zmiennych: int tab[5]; int r; to podczas próby zapisu czegoś do nieistniejącego elementu tab[5], np. tab[5]=5; zostanie zniszczona treść zmiennej r, jako że została ona umieszczona w pamięci bezpośrednio po tablicy tab. • Przypisywanie wartości elementom tablicy W wyniku wykonania następującego fragmentu programu int t[4]; for (int i=0; i<4; i++) t[i]=2*i; poszczególnym elementom tablicy t zostaną przypisane następujące wartości: t[0]=0 t[1]=2 t[2]=4 t[3]=6 Oczywiście nie musimy przypisywać wartości wszystkim elementom tablicy. Np. dla zdefiniowanej tablicy jak powyżej, instrukcja for (int i=0; i<2; i++) t[i]=2*i; przypisze wartości tylko dwóm pierwszym elementom tablicy, tzn. t[0]=0 t[1]=2. Podobnie w przypadku wyświetlania elementów tablicy, jeśli wyświetlamy istniejące elementy, to zostaną wyświetlone wartości poszczególnych elementów tablicy. Np. w wyniku wykonania fragmentu programu: int t[4]; for (int i=0; i<4; i++) t[i]=2*i; for (int i=0; i<4; i++) cout << t[i] << ” ”; na ekranie monitora pojawia się wartości: 0 2 4 6 Gdybyśmy teraz zmodyfikowali ostatnią instrukcję na następującą: for (int i=0; i<5; i++) cout << t[i] << ” ”; to spowoduje to próbę wypisania na ekranie również piątego nieistniejącego elementu tablicy t[4], czyli nastąpi pobranie wartości z obszaru pamięci bezpośrednio za tablicą i wyświetlenie dość bezsensownej (przypadkowej z naszego punktu widzenia) wartości. • Inicjalizacja tablic (nadanie wartości początkowych w momencie definicji tablicy) Podobnie jak w przypadku inicjalizacji zmiennych zwykłych typów, np. int k=4; float zm=0.34; możemy nadawać wartości początkowe również tablicom, z tą różnicą, że tutaj trzeba nadać wartość każdemu elementowi tablicy. Będzie to wyglądało np. następująco: int t[6]={3,6,12,14,56,1}; W wyniku takiej inicjalizacji poszczególne elementy naszej tablicy mają teraz następujące wartości: t[0]=3 t[1]=6 t[2]=12 t[3]=14 t[4]=56 t[5]=1 UWAGA: Jeśli nie podamy rozmiaru tablicy, to kompilator przeliczy ilość inicjalizatorów i zarezerwuje odpowiednią ilość miejsca. Powyższy przypadek jest zatem równoważny inicjalizacji: int t[]={3,6,12,14,56,1}; UWAGA 2: W prawie każdej operacji wykonywanej na zmiennej tab zmienna ta jest niejawnie konwertowana do typu wskaźnikowego. Wartością tab jest wtedy adres pierwszego elementu tablicy, a więc elementu o indeksie zero. A zatem po deklaracji int tab[20]; zmienna tab może być traktowana jako wskaźnik typu int* const wskazujący na pierwszy element tablicy. Modyfikator const znaczy tutaj, że zawartość tablicy może być zmieniana, ale nie można do tab wpisać adresu innej tablicy. • Przekazywanie tablic do funkcji. Konwersja, o której wspomnieliśmy, zachodzi w szczególności, gdy tablicę „wysyłamy” do funkcji. Wysyłamy tak naprawdę (przez wartość) adres początku tablicy i nic więcej. W szczególności nie ma tam żadnej informacji o wymiarze tablicy. Więcej: nie ma nawet informacji, że to w ogóle jest adres tablicy, a nie adres „normalnej” zmiennej odpowiedniego typu. Zatem jeśli argumentem funkcji jest tablica, to typem odpowiedniego parametru funkcji (w jej deklaracji/definicji) jest typ wskaźnikowy, a nie tablicowy! Taki sposób przekazania tablic do funkcji umożliwia zmianę wartości elementów tablicy pod wpływem działania funkcji. Ponadto wymiar tablicy należy przekazać jako osobny argument. (np. float max(float tab[],int wymiar)) Tablice znakowe (C-napisy) W klasycznym C nie ma typu napisowego, a rolę zmiennych napisowych pełnią tablice znaków, przy czym koniec napisu oznaczany jest znakiem o kodzie ASCII równym zero: ' \0'. Znak ten nazywany jest NUL. Znak ten jest po to by zaznaczyć gdzie kończy się ciąg liter. • Definiowanie tablic znakowych char tab1[] = "Kasia" tworzy tablicę sześciu znaków na podstawie literału napisowego: pięć znaków imienia i jako szósty znak '\0', który oznacza koniec napisu - kompilator doda automatycznie. Zdefiniujmy teraz tablicę znakową o 40 elementach i zainicjalizujmy napisem uwaga: // zwróć uwagę na cudzysłów char t[40]={ ”uwaga”}; W wyniku powyższej inicjalizacji poszczególne elementy tablicy mają wartości: t[0]=’u’ t[1]=’w’ t[2]=’a’ t[3]=’g’ t[4]=’a’ Dalsze elementy tablicy nas obecnie nie interesują. Jest też inny sposób inicjalizacji tablicy znaków: char t[40]={’u’,’w’,’a’,’g’,’a’,'\0'}; Tu znak '\0' musimy dodać „ręcznie”. t[5]=NUL Jeśli natomiast zainicjujemy tablicę następująco char t1[40]={’u’,’w’,’a’,’g’,’a’}; to kompilator nie dokończy tego znakiem NUL, czyli nie ma znaku kończącego napis. Początkowych 5 elementów tablicy ma natomiast taką samą wartość jak w poprzednim przypadku. Różnica pojawi się w sytuacji, gdy nie podamy rozmiaru tablicy. W pierwszym przypadku char t[]={”uwaga”}; tablica jest 6- elementowa, natomiast w przypadku char t[]={’u’,’w’,’a’,’g’,’a’}; będziemy mieli zarezerwowane miejsce na jedynie 5 elementów tablicy. Uwaga: przekazując do funkcji napis w postaci tablicy znakowej nie musimy przekazywać jej wymiaru: obecność znaku ' \0' pozwala bowiem określić koniec napisu, a więc i jego długość, np. void napisz (char tab[]) { cout << "Napis: " << tab << endl; } Zauważmy też, że wyjątkowe jest traktowanie zmiennych typu char* (char []) przez operator wstawiania do strumienia. W zasadzie po 'cout « nap', gdzie nap jest typu char*, powinna zostać wypisana wartość zmiennej nap, czyli pewien adres (tak by było, gdyby zmienna nap była np. typu int*). Wskaźniki do zmiennych typu char są jednak traktowane odmiennie: zakłada się, że wskaźnik wskazuje na pierwszy znak napisu i wypisywane są wszystkie znaki od tego pierwszego poczynając aż do napotkania znaku ' \0'. Ważne więc, aby znak ' \0' tam był. Tablice wielowymiarowe Elementami tablic mogą być w szczególności także inne tablice. Jeśli elementem tablicy jest inna tablica jednowymiarowa, mamy do czynienia z tablicą dwuwymiarową. Taką tablicę możemy zadeklarować następująco: int t[3][2]; //t jest tablicą 3-elementową, której elementami są dwuelementowe tablice typu int Elementy naszej tablicy to: t[0][0] t[0][1] t[1][0] t[1][1] t[2][0] t[2][1] Poszczególne elementy takiej tablicy są umieszczane kolejno w pamięci komputera tak, ze najszybciej zmienia się najbardziej skrajny prawy indeks, zatem poniższa inicjalizacja: int t[3][2]={1,2,3,4,5,6}; spowoduje następujące nadanie wartości elementom tablicy: t[0][0]=1 t[1][0]=3 t[2][0]=5 t[0][1]=2 t[1][1]=4 t[2][1]=6 Często o takiej dwuwymiarowej tablicy myślimy jak o macierzy, która w naszym przypadku miałaby 3 wiersze i 2 kolumny. Poniżej fragment programu nadającego poszczególnym elementom tablicy wartość będącą sumą numeru jej wiersza i kolumny i wyświetlający te wartości w postaci macierzy: int t[3][2]; int i,j; for (i=0; i<3; i++) for (j=0; j<2; j++) t[i][j]=i+j; //wyświetlenie for (i=0; i<3; i++) {for (j=0; j<2; j++) cout<<t[i][j]<<” cout << endl; } ”; TABLICE – ZADANIA Wczytywanie i drukowanie. Dostęp do elementów tablicy. 1. Napisz program wczytujący z klawiatury 10 liczb całkowitych. Wczytane liczby należy wydrukować na ekranie. 2. Napisz program wczytujący z klawiatury 10 liczb całkowitych. Wczytane liczby należy wydrukować na ekranie w odwrotnej kolejności. 3. Napisz program wczytujący z klawiatury n liczb całkowitych. Liczbę n należy pobrać z klawiatury. Jeśli wartość n podana przez użytkownika jest liczbą z zakresu od 1 do 30, wówczas program ma wczytać podaną ilość liczb całkowitych, a następnie wczytane liczby wydrukować na ekranie. Jeśli natomiast podana wartość n jest liczbą spoza przedziału [1;30], wówczas program kończy pracę drukując stosowny komunikat. W zadaniu należy wykorzystać 30-elementową tablicę liczb całkowitych. 4. Napisz program, który wczytuje do jednowymiarowej tablicy (o rozmiarze nmax=100) n<= nmax liczb (liczbę n podaje na początku użytkownik), a następnie wyświetla te elementy. #include<iostream> using namespace std; int main() { const int NMAX=100;//ilosc el. tablicy float tab[NMAX];//deklaracja statycznej nmax-el. tablicy int n;//ilosc wykorzystywanych elementow tablicy //pobranie ilosci elementow tablicy (1 <= n <= nmax)-petla zaporowa do { cout<<"podaj dlugosc tablicy \n"; cin>>n; if (n<=0||n>NMAX) cout<<"podana liczba jest spoza zakresu podaj jeszcze raz "; }while (n<=0||n>nmax); //pobranie elementow for (int i=0; i<n; i++) { cout<<"Podaj "<<i<<" element tablicy "; cin>>tab[i]; } //wyświetlenie el.tablicy for(int i=0; i<n; i++) cout<< tab[i]<<endl; system(”pause”); return 0; } Wyszukiwanie w tablicy Napisz program, który wczytuje do jednowymiarowej tablicy (o rozmiarze nmax=100) n<= nmax liczb (liczbę n podaje na początku użytkownik), a następnie 5. prosi użytkownika o podanie jakiejś liczby i sprawdza, ile razy występuje ona we wczytanej tablicy. 6. prosi użytkownika o podanie jakiejś liczby i sprawdza, czy występuje ona we wczytanej tablicy. Jeżeli tak, program powinien wyświetlić napis ,,JEST'' i numer pierwszej pozycji na której wystąpiła ta liczba, a jeśli nie, wyświetlić napis ,,NIE MA''. 7. sprawdza czy występuje zero i na której pozycji pierwszy raz 8. program ma znaleźć największą spośród podanych liczb i wydrukować ją na ekranie. 9. program ma znaleźć najmniejszą spośród podanych liczb i wydrukować ją na ekranie. 10. program ma znaleźć największą spośród podanych liczb oraz wydrukować na ekranie informację mówiącą o tym, ile razy największa liczba wystąpiła w podanym ciągu liczb. 11. program ma znaleźć najmniejszą spośród podanych liczb oraz wydrukować na ekranie informację mówiącą o tym, ile razy najmniejsza liczba wystąpiła w podanym ciągu liczb. 12. program ma znaleźć drugi co do wielkości wyraz podanego ciągu liczb (czyli liczbę mniejszą od największej liczby występującej w ciągu, ale większą od wszystkich pozostałych). 13. program ma znaleźć drugi co do wielkości (ciut większy od najmniejszego) wyraz podanego ciągu liczb (czyli liczbę większą od najmniejszej ale mniejszą od każdej innej). 14. oblicza ile razy w podanym ciągu liczb wystąpił drugi co do wielkości największy element ciągu? 15. oblicza ile razy w podanym ciągu liczb wystąpił drugi co do wielkości najmniejszy element ciągu? 16. wypisuje na ekranie te liczby, które są mniejsze od średniej arytmetycznej wszystkich liczb w tablicy. 17. podaje ilość miejsc w których element mniejszy następuje po większym, np. dla tablicy [4,7,5,5,2,6,8,7] program powinien podać 3, a dla tablicy [2,2,4,6,7,9] powinien podać 0 18. sprawdza, czy wczytany ciąg jest posortowany (nierosnący lub niemalejący). Przetwarzanie elementów tablicy Napisz program wczytujący ciąg liczb rzeczywistych. 19. Każdą podana liczbę należy podnieść do kwadratu, a następnie wydrukować na ekranie. 20. Każdą podana liczbę należy podnieść do trzeciej potęgi, a następnie wydrukować na ekranie. 21. Do każdej podanej liczby należy dodać jeden. Tak otrzymane liczby należy wydrukować na ekranie. 22. Każdą podaną liczbę należy pomnożyć przez dwa. Tak otrzymane liczby należy wydrukować na ekranie. 23. Liczby ujemne należy zastąpić zerami. Tak otrzymane liczby drukujemy na ekranie. Napisz program wczytujący ciąg liczb całkowitych. 24. 25. 26. 27. 28. 29. 30. 31. Wydrukuj na ekranie kolejno wszystkie parzyste spośród podanych liczb. Dodaje 10 do tych które są parzyste. Wydrukuj na ekranie kolejno wszystkie nieparzyste spośród podanych liczb. Wydrukuj na ekranie kolejno wszystkie liczby, które dzielą się przez 3. Wydrukuj na ekranie kolejno wszystkie liczby, które należą do przedziału [4;15). Wydrukuj na ekranie kolejno wszystkie liczby, które mają wszystkie cyfry parzyste. Wydrukuj na ekranie kolejno wszystkie liczby, których suma cyfr wynosi 1. Do liczb parzystych należy dodać 100, a następnie wydrukować wszystkie liczby na ekranie. Przetwarzanie elementów tablicy o zadanych indeksach 32. Napisz program wczytujący ciąg liczb rzeczywistych. Wydrukuj na ekranie te spośród liczb, których indeks jest liczbą parzystą. 33. Napisz program wczytujący ciąg liczb rzeczywistych. Wydrukuj na ekranie te spośród liczb, których indeks jest liczbą będącą kwadratem liczby całkowitej ( 1, 4, 9, 16 itd.). Różne 34. 35. 36. 37. Napisz program generujący ciąg liczb pierwszych od 0 do n metoda sita Eratostanesa. Napisz program generujący ciąg n początkowych liczb Fibonacciego. Napisz program sortujący wczytane n liczb metodą wyszukiwania kolejnych minimów. Napisz program wypełniający tablicę n liczb t[0] ... t[n-1] wartościami: a) od 0 do n-1 b) od 7 do n+6 c) ciągiem 4, 8, 12, 16, ... d) ciągiem 1, 2, 4, 8, 16, ... e) 2,3,4,....,n+1 Wielomiany Wielomian n-tego stopnia postaci f(x)=anxn+an-1xn-1+...+a1x+a0 możemy reprezentować za pomocą tablicy jego współczynników a0,a1,...,an. Napisz program, który 38. wczytuje stopień wielomianu (nie większy niż 50) i jego współczynniki a następnie oblicza wartość wielomianu w podanym z klawiatury punkcie x korzystając ze schematu Hornera. 39. wyczytuje stopnie (nie większe niż 50) i współczynniki dwóch wielomianów a następnie wyświetla stopień i współczynniki wielomianu będącego ich sumą. 40. wczytuje stopnie (nie większe niż 50) i współczynniki dwóch wielomianów a następnie wyświetla stopień i współczynniki wielomianu będącego ich iloczynem. Wektory 41. Napisz program, który wczytuje z klawiatury wektor i następnie oblicza jego długość. 42. Wektory A=[a1,a2,...,an], B=[b1,b2,...,bn] są współliniowe, gdy istnieje taka liczba rzeczywista t, że bi=t*ai dla każdego 1<=i<=n. Napisz program, który wczytuje dwa wektory wymiaru n<=20 (podanego wcześniej z klawiatury) i sprawdza, czy są one współliniowe. 43. Napisz program, który wczytuje z klawiatury współrzędne dwóch n-wymiarowych wektorów (wymiaru co najwyżej nmax=20) a następnie oblicza, ich iloczyn skalarny. 44. Wczytaj z klawiatury współrzędne dwóch wektorów n-wymiarowych A, B (n<= 20) a następnie oblicz i wypisz wartość cosinusa kąta pomiędzy tymi wektorami daną wzorem cosα=<A,B>/(|A|*|B|), gdzie <A,B> oznacza iloczyn skalarny wektorów, zaś |A| jest długością wektora A. Tablice wielowymiarowe Napisz program, który 1. wczytuje z klawiatury wymiary m,n (m,n<= 10) i elementy macierzy a następnie wypisuje ją na ekranie w ten sposób, by każdy wiersz macierzy znajdował się w osobnej linii a elementy w wierszu były wypisane na 5 miejscach. #include <iostream> #include <iomanip> using namespace std; int main() { const int nmax = 10;//rozmiar macierzy float a[nmax][nmax];//deklaracja macierzy nmax x nmax int n, m; //n-il.wierszy, m-il. kolumn //pobieranie il. wierszy do { cout << "Podaj il. wierszy\n n = "; cin >> n; }while((n < 1) || (n > nmax)); //pobieranie il. kolumn do { cout << "Wstaw il. kolumn\n m = "; cin >> m; }while((m < 1)||(m > nmax)); //pobieranie el. macierzy cout << "\nPodaj elementy macierzy A\n"; for(int i=0; i < n; i++) for(int j=0; j < m; j++) { cout << "A["<< i+1 << ", " << j+1 << "] = "; cin >> a[i][j]; } //wyswietlanie el. macierzy cout<<fixed<<setprecision(2);//el. wysw. z dokladn.do 2-ch miejsc po przecinku for(int i=0; i < n; i++) {//wyswietlamy el. i-tego wiersza for(int j=0; j < n; j++) cout << setw(5) << a[i][j]; cout << endl;//przechodzimy do nowego wiersza } system("pause"); return 0; } 2. wczytuje macierz (jej wymiary i elementy) a następnie oblicza sumę elementów macierzy. 3. wyznacza minimum w wierszach wczytanej z klawiatury tablicy dwuwymiarowej rozmiaru n x n (gdzie n<=10 było podane z klawiatury) 4. wprowadza liczby do dwuwymiarowej tablicy liczb o wymiarach n wierszy na m kolumn oraz oblicza: sumy elementów w wierszach i sumy elementów w kolumnach. Wyprowadza na ekran obliczone sumy z numerem wiersza i kolumny. 5. wczytuje macierz kwadratową a następnie liczy jej ślad, tzn. sumę elementów na głównej przekątnej. 6. wczytuje dwie macierze a potem, jeżeli jest to możliwe, dodaje je i wypisuje macierz będącą ich sumą. 7. wczytuje z klawiatury stopień n macierzy kwadratowej (n<= 10) a potem jej elementy, a następnie podaje numer tego wiersza macierzy w którym suma elementów w wierszu była najmniejsza. 8. wczytuje z klawiatury stopień n macierzy kwadratowej (n<= 10), potem jej elementy, a następnie podaje numer tej kolumny macierzy w której suma elementów w kolumnie była największa.