This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
dydaktyka:cprog:2015:arrays [2015/12/03 09:02] pkleczek [Fotoszop] |
— (current) | ||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== Tablice ====== | ||
- | |||
- | Tablica to ciąg wartości tego samego typu (np. liczb) przechowywanych obok siebie. | ||
- | |||
- | ===== Tablice jednowymiarowe ===== | ||
- | |||
- | |||
- | ==== Deklarowanie ==== | ||
- | |||
- | Uogólniona deklaracja tablicy: | ||
- | <code> | ||
- | typ_danych nazwa_tablicy[liczba_elementow]; | ||
- | </code> | ||
- | przy czym dostępne typy elementów są identyczne, jak dla "zwykłych" zmiennych (''int'', ''float'' itd.) | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int tab[8]; // tablica osmiu wartosci typu calkowitego | ||
- | </code> | ||
- | |||
- | ==== Definiowanie ==== | ||
- | |||
- | Definicja tablicy polega na przypisaniu do tablicy podanej w nawiasach klamrowych listy wartości kolejnych elementów (rozdzielonych przecinkami). | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int tab[4] = {3, 2, 5, 1}; | ||
- | </code> | ||
- | |||
- | W przypadku podania zbyt małej liczby wartości do inicjalizacji, pozostałe elementy tablicy otrzymują wartość 0. | ||
- | |||
- | ==== Dostęp do elementów ==== | ||
- | |||
- | Dostęp do poszczególnych elementów tablicy można uzyskać za pomocą indeksu elementu, będącego zawsze liczbą naturalną, umieszczonego w nawiasach kwadratowych. | ||
- | |||
- | :!: W języku C indeksowanie zaczyna się od zera -- czyli aby uzyskać wartość pierwszego elementu piszemy ''tab[0]''! | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int tab[] = {1, 2, 3, 4}; | ||
- | int elem = tab[2]; // przypisz zmiennej `elem` wartosc TRZECIEGO elementu tablicy `tab` | ||
- | </code> | ||
- | |||
- | ==== Zadania ==== | ||
- | |||
- | === Zadanie SUM1D === | ||
- | |||
- | Stwórz jednowymiarową tablicę wartości zmiennoprzecinkowych zainicjalizowaną wybranymi przez siebie wartościami, a następnie oblicz sumę jej elementów. | ||
- | |||
- | //Wskazówka: Skorzystaj z pętli ''for''.// | ||
- | |||
- | === Zadanie MAX1D === | ||
- | |||
- | Napisz program, który wyznaczy największą wartość w jednowymiarowej tablicy liczb całkowitych. | ||
- | ===== Tablice wielowymiarowe ===== | ||
- | |||
- | ==== Deklarowanie ==== | ||
- | |||
- | Uogólniona deklaracja tablicy wielowymiarowej: | ||
- | <code> | ||
- | typ_danych nazwa_tablicy[rozmiar_1][rozmiar_2]...[rozmiar_n]; | ||
- | </code> | ||
- | |||
- | na przykładzie dwuwymiarowym: | ||
- | <code> | ||
- | typ_danych nazwa_tablicy[ilosc_wierszy][ilosc_kolumn]; | ||
- | </code> | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int tab[8][3]; // tablica o osmiu wierszach i trzech kolumnach, wartosci typu calkowitego | ||
- | </code> | ||
- | |||
- | Komputer przechowuje w pamięci taką tablicę dwuwymiarową liniowo, jako kilka następujących po sobie tablic jednowymiarowych. | ||
- | |||
- | ==== Definiowanie ==== | ||
- | |||
- | Tablicę wielowymiarową można zdefiniować na dwa sposoby: | ||
- | * używając "zagnieżdżonych" klamer (pierwszy zestaw -> piewszy rząd, drugi zestaw -> drugi rząd itd.) | ||
- | * stosując "płaską" definicją -- wszystkie wartości znajdują się w jednych klamrach, przypisywane są do kolejnych elementów wierszami (najpierw całkowicie zapełniany jest pierwszy wiersz, potem drugi itd.) | ||
- | |||
- | Przykład sposobu z "zagnieżdżaniem" klamer: | ||
- | <code c> | ||
- | int tab[2][3] = { | ||
- | {3, 2, 6}, | ||
- | {5, 1, 9} | ||
- | }; | ||
- | </code> | ||
- | |||
- | Przykład sposobu "płaskiego": | ||
- | <code c> | ||
- | int tab[2][3] = {3, 2, 6, 5, 1, 9}; // zdecydowanie mniej czytelne, | ||
- | // w miare mozliwosci unikac! | ||
- | </code> | ||
- | |||
- | |||
- | ==== Dostęp do elementów ==== | ||
- | |||
- | Podobnie jak w przypadku tablicy jednowymiarowej, dostęp uzyskuje się przez podanie w nawiasach kwadratowych numerów pozycji dla kolejnych wymiarów. \\ | ||
- | Dla przypadku dwuwymiarowego, podaje się najpierw numer wiersza, a potem numer kolumny. | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int tab[3][2]; | ||
- | tab[2][0] = 5; // przypisz wartosc elementowi w 3. wierszu w 1. kolumnie | ||
- | </code> | ||
- | |||
- | Poniższy rysunek pomoże Ci załapać tę zasadę:\\ | ||
- | {{:dydaktyka:cprog:2015:2d-array_indexing.png?nolink|}} | ||
- | |||
- | ==== Zadania ==== | ||
- | |||
- | === Zadanie SUM2D === | ||
- | |||
- | Zadeklaruj tablicę dwuwymiarową $A_{N \times M}$. Przypisz do każdego z jej elementów $a(i,j)$ wartość $i + 2 \cdot j$, gdzie $i$ -- numer wiersza, a $j$ -- numer kolumny. Oblicz sumę elementów leżących w co drugim wierszu, zaczynając od pierwszego wiersza. | ||
- | |||
- | //Wskazówka 1: Użyj zagnieżdżonych pętli ''for'' zarówno do inicjalizacji elementów tablicy, jak i do obliczenia sumy elementów.// \\ | ||
- | //Wskazówka 2: Zastosuj osobny zestaw pętli dla inicjalizacji i osobny dla sumowania.// | ||
- | ===== Tablice bezwymiarowe ===== | ||
- | |||
- | Kompilator C może automatycznie obliczyć rozmiar tablicy, jeśli tablica zostanie zadeklarowana jako bezwymiarowa (czyli programista nie poda ilości elementów tablicy). | ||
- | |||
- | Jeśli kompilator napotka, przykładowo, zapis | ||
- | <code c>int tab[] = {1,2,3}; | ||
- | </code> | ||
- | to utworzy tablicę na tyle dużą, by pomieścić wszystkie te elementy. | ||
- | |||
- | :!: Kompilator jest w stanie obliczyć tylko jeden wymiar tablicy -- pierwszy od lewej. Pozostałe wymiary muszą zostać podane: | ||
- | <code c> | ||
- | int tab[][2] = {{1,2}, {3,4}, {5,6}}; // OK | ||
- | int tab[][] = {{1,2}, {3,4}}; // blad | ||
- | </code> | ||
- | |||
- | ===== Operator "sizeof" ===== | ||
- | |||
- | Operator ''sizeof'' zwraca rozmiar operandu (w bajtach). Używa się go podobnie do wywołania funkcji, przy czym argumentem może być nazwa zmiennej lub typ danych: | ||
- | <code c> | ||
- | int s = sizeof(char); // wartosc `s` to 1, bo tyle wynosi rozmiar typu 'char' | ||
- | int s2 = sizeof(s); // wartosc `s2` to (prawdopodobnie) 4 | ||
- | </code> | ||
- | |||
- | Operator ten można wykorzystać, aby otrzymać ilość elementów tablicy: | ||
- | <code c> | ||
- | int tab[5]; | ||
- | int n = sizeof(tab) / sizeof(int); | ||
- | </code> | ||
- | ===== Łańcuchy znaków ===== | ||
- | |||
- | Język C nie posiada specjalnego typu łańcuchowego. Zamiast tego, łańcuchy przechowywane są w tablicach elementów typu ''char''. Kolejne znaki, z których składa się łańcuch, znajdują się w kolejnych komórkach pamięci, a na ich końcu znajduje się **znak zerowy** (//null character//). | ||
- | |||
- | Znak zerowy nie jest cyfrą zero, tylko znakiem niedrukowanym o kodzie ASCII równym 0. Łańcuchy w języku C są przechowywane razem z tym znakiem. Oznacza to, że tablica musi mieć długość przynajmniej o jedną komórkę większą niż długość zapisanego w niej łańcucha. \\ | ||
- | Literał znaku zerowego to ''%%'\0'%%''. | ||
- | |||
- | Przykład -- łańcuch znaków ''%%"Hello"%%'': \\ | ||
- | {{:dydaktyka:cprog:2015:string.png?nolink|}} | ||
- | |||
- | :!: Znaki cudzysłowu nie są częścią łańcucha. Informują one jedynie kompilator, że to, co znajduje się pomiędzy nimi, jest łańcuchem -- podobnie jak apostrofy sygnalizują stałą znakową. | ||
- | |||
- | |||
- | ==== Wyświetlanie i wczytywanie ==== | ||
- | |||
- | Do wyświetlania łańcuchów znaków służy specyfikator konwersji ''%s'': | ||
- | <code c> | ||
- | printf("Miasto: %s\n", "Krakow"); | ||
- | </code> | ||
- | |||
- | Do wczytywania łańcuchów znaków najwygodniej wykorzystać funkcję [[http://www.cplusplus.com/reference/cstdio/gets/?kw=gets|gets()]], która odczytuje znaki do momentu napotkania znaku końca linii (ENTER) i zapisuje je jako łańcuch w tablicy znaków -- sam znak końca linii nie jest kopiowany. Funkcja automatycznie dołącza do wczytanych znaków znak zerowy, tworząc tym samym łańcuch znaków. | ||
- | <code c> | ||
- | char imie[15]; | ||
- | printf("Podaj swoje imie: "); | ||
- | gets(imie); | ||
- | </code> | ||
- | |||
- | Oczywiście możesz też użyć funkcji ''scanf()'' ze specyfikatorem konwersji ''%s'': | ||
- | <code c> | ||
- | char imie[15]; | ||
- | printf("Podaj swoje imie: "); | ||
- | scanf("%s", imie); // `imie` to tablica, a nazwa tablicy to rownoczesnie ADRES jej | ||
- | // pierwszego elementu - nie trzeba zatem dodawac '&' przed nazwa tablicy | ||
- | </code> | ||
- | |||
- | :!: Pamiętaj, żeby wczytywać znaki do wystarczająco dużej tablicy (aby zmieściły się wszystkie znaki i jeszcze znak zerowy)! | ||
- | |||
- | |||
- | ==== Przydatne funkcje ==== | ||
- | |||
- | Do badania długości łańcucha znaków służy funkcja [[http://www.cplusplus.com/reference/cstring/strlen/?kw=strlen|strlen()]]. \\ | ||
- | Zwróć uwagę, że ''sizeof'' i ''strlen'' zwracają różne wartości dla tablicy przechowującej łańcuch znaków, gdyż łańcuch może nie zajmować całej tablicy (uruchom poniższy program): | ||
- | <code c> | ||
- | #include <stdio.h> | ||
- | #include <stdlib.h> | ||
- | #include <string.h> | ||
- | |||
- | int main () | ||
- | { | ||
- | char str[10] = "ABC"; // lancuch zajmuje 4 elementy tablicy | ||
- | |||
- | printf("sizeof = %d , strlen = %d\n", sizeof(str), strlen(str)); | ||
- | |||
- | return 0; | ||
- | } | ||
- | </code> | ||
- | |||
- | Aby określić typ znaku (np. czy dany znak jest cyfrą) warto skorzystać z biblioteki [[http://www.cplusplus.com/reference/cctype/|ctype.h]]. | ||
- | |||
- | ==== Zadania ==== | ||
- | |||
- | === Zadanie IDL === | ||
- | |||
- | Napisz program, który pobiera imię i nazwisko użytkownika (używając jednego wywołania funkcji ''scanf()''), a następnie wyświetla: w pierwszym wierszu imię i nazwisko, a w drugim liczbę liter w imieniu oraz liczbę liter w nazwisku. | ||
- | |||
- | Na przykład: | ||
- | <code c> | ||
- | Podaj imie i nazwisko: Jan Nowak | ||
- | |||
- | Jan Nowak | ||
- | 3 5 | ||
- | </code> | ||
- | |||
- | //Wskazówka: Przechowuj imię i nazwisko w osobnych tablicach.// | ||
- | |||
- | ===== Przydatne operatory arytmetyczne ===== | ||
- | |||
- | ==== Arytmetyczne operatory przypisania ==== | ||
- | |||
- | Język C udostępnia //arytmetyczne operatory przypisania// ''<op>='' (gdzie ''<op>'' oznacza operator arytmetyczny: ''+'', ''-'', ''*'', ''/'' bądź ''%''): instrukcja ''x <op>= y;'' jest równoważna ''x = x <op> (y);'' | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int a = 5; | ||
- | int b = 2; | ||
- | a *= 3; // nowa wartosc `a` to 5 * 3 = 15 | ||
- | b *= 3 + 1; // nowa wartosc `b` to 2 * (3 + 1) = 8 | ||
- | </code> | ||
- | |||
- | ==== Inkrementacja i dekrementacja ==== | ||
- | |||
- | Operatory inkrementacji (''++'') i dekrementacji (''%%--%%'') powodują odpowiednio zwiększenie bądź zmniejszenie wartości zmiennej o 1. | ||
- | |||
- | Są one dostępne w dwóch trybach: | ||
- | * przedrostkowym (//pre-incrementation//) -- najpierw następuje zwiększenie wartości zmiennej, potem dalsze operacje na zwiększonej wartości; np. ''++i'' | ||
- | * przyrostkowym (//post-incrementation//) -- najpierw wykonywane są operacje (na pierwotnej wartości), a dopiero potem następuje zwiększenie wartości zmiennej; np. ''i++'' | ||
- | |||
- | Przykład: | ||
- | <code c> | ||
- | int a1 = 3; | ||
- | int a2 = 3; | ||
- | int b_pre = 2 * ++a1; // b_pre = 6, a1 = 3 | ||
- | int b_post = 2 * a2++; // b_post = 4, a2 = 3 | ||
- | |||
- | printf("a = %d, b_pre = %d, b_post = %d\n", b_pre, b_post); | ||
- | </code> | ||
- | |||
- | Operatory inkrementacji i dekrementacji działają tylko dla zmiennych (a ściślej: dla modyfikowalnych l-wartości). Oznacza to, że instrukcja ''int a = 6++;'' jest błędna. | ||
- | |||
- | Stosuj powyższe operatory ostrożnie -- zwiększają one zwięzłość kodu, lecz łatwo popełnić błąd w zapisie. | ||
- | |||
- | ==== "Co za dużo to niezdrowo!" ==== | ||
- | |||
- | Nie łącz zbyt wielu operatorów w jednym wyrażeniu, nie rób "optymalizacji" długości kodu kosztem czytelności -- w ten sposób unikniesz wielu błędów. W szczególności: | ||
- | * Nie stosuj operatora inkrementacji lub dekrementacji do zmiennej, która jest częścią więcej niż jednego argumentu funkcji. | ||
- | * Nie stosuj operatora inkrementacji lub dekrementacji do zmiennej, która w wyrażeniu pojawia się więcej niż jeden raz. | ||
- | |||
- | Na przykład po wykonaniu kodu | ||
- | <code c> | ||
- | int n = 3; | ||
- | int y = n++ + n++; | ||
- | </code> | ||
- | ''y'' może mieć albo wartość ''6'' -- jeśli kompilator dwukrotnie użyje starej wartości -- albo wartość ''7'' (''3 + 4''), jeśli zwiększenie nastąpi przed obliczeniem sumy. Standard języka C nie narzuca jednego słusznego sposobu obliczania takiego wyrażenia. | ||
- | ===== Zadania podsumowujące ===== | ||
- | |||
- | ==== Fotoszop ==== | ||
- | |||
- | ([size=10]poziom trudności:[/size] {{stars>2/4}} / {{stars>3/4}}) | ||
- | |||
- | Wykonaj zadania w ramach polecenia [[dydaktyka:cprog:2015:photoshop#cwiczenia|Rozmycie obrazu]]. | ||
- | |||