User Tools

Site Tools


dydaktyka:cprog:2015:arrays

This is an old revision of the document!


Tablice

Tablica to ciąg wartości tego samego typu (np. liczb) przechowywanych obok siebie.

Tablice jednowymiarowe

Deklarowanie

Uogólniona deklaracja tablicy:

typ_danych nazwa_tablicy[liczba_elementow];

przy czym dostępne typy elementów są identyczne, jak dla “zwykłych” zmiennych (int, float itd.)

Przykład:

int tab[8]; // tablica osmiu wartosci typu calkowitego

Definiowanie

Definicja tablicy polega na przypisaniu do tablicy podanej w nawiasach klamrowych listy wartości kolejnych elementów (rozdzielonych przecinkami).

Przykład:

int tab[4] = {3, 2, 5, 1};

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:

int tab[] = {1, 2, 3, 4};
int elem = tab[2];  // przypisz zmiennej `elem` wartosc TRZECIEGO elementu tablicy `tab`

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:

typ_danych nazwa_tablicy[rozmiar_1][rozmiar_2]...[rozmiar_n];

na przykładzie dwuwymiarowym:

typ_danych nazwa_tablicy[ilosc_wierszy][ilosc_kolumn];

Przykład:

int tab[8][3]; // tablica o osmiu wierszach i trzech kolumnach, wartosci typu calkowitego

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:

int tab[2][3] = {
        {3, 2, 6},
        {5, 1, 9}
    };

Przykład sposobu “płaskiego”:

int tab[2][3] = {3, 2, 6, 5, 1, 9};

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:

int tab[3][2];
tab[2][0] = 5;  // przypisz wartosc elementowi w 3. wierszu w 1. kolumnie

Poniższy rysunek pomoże Ci załapać tę zasadę:

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$ ($i$ – numer wiersza, $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

int tab[] = {1,2,3};

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:

int tab[][2] = {{1,2}, {3,4}, {5,6}};  // OK
int tab[][] = {{1,2}, {3,4}};  // blad

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:

int s = sizeof(char);  // wartosc `s` to 1, bo tyle wynosi rozmiar typu 'char'
int s2 = sizeof(s);  // wartosc `s2` to (prawdopodobnie) 4

Operator ten można wykorzystać, aby otrzymać ilość elementów tablicy:

int tab[5];
int n = sizeof(tab) / sizeof(int);

Ł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":

:!: 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:

printf("Miasto: %s\n", "Krakow");

Do wczytywania łańcuchów znaków najwygodniej wykorzystać funkcję 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.

char imie[15];
printf("Podaj swoje imie: ");
gets(imie);

:!: 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 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):

#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;
}

Aby określić typ znaku (np. czy dany znak jest cyfrą) warto skorzystać z biblioteki ctype.h.

Zadania

Zadanie IDL

Napisz program, który pobiera imię i nazwisko użytkownika, a następnie wyświetla: w pierwszym wierszu imię i nazwisko, a w drugim liczbę liter w imieniu oraz liczbę liter w nazwisku.

Przydatne operatory arytmetyczne

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:

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

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.

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:

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

"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

int n = 3;
int y = n++ + n++;

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

(poziom trudności: / )

Wykonaj zadania w ramach polecenia Rozmycie obrazu.

dydaktyka/cprog/2015/arrays.1448212292.txt.gz · Last modified: 2020/03/25 11:46 (external edit)