C/Tablice: Różnice pomiędzy wersjami

Usunięta treść Dodana treść
Lethern (dyskusja | edycje)
m przeniesiono fragment do C/Tablice - więcej, link
Lethern (dyskusja | edycje)
przeniesiono część do C/Tablice - więcej, + edycja treści
Linia 50:
 
Jak widać, wszystko się zgadza.
W powyżej zamieszczonym przykładzie użyliśmy stałej do podania rozmiaru tablicy. Jest to o tyle pożądany zwyczaj, że w razie konieczności zmiany rozmiaru tablicy zmieniana jest tylko jedna linijka kodu przy stałej, a nie kilkadziesiąt innych linijek, rozsianych po kodzie całego programu.
 
W powyżej zamieszczonym przykładzie użyliśmy stałej do podania rozmiaru tablicy. Jest to o tyle pożądany zwyczaj, że w razie koniecznościpotrzeby zmiany rozmiaru tablicy, zmieniana jest tylko jednawartość linijkaw jednej linijce kodu przy stałej<tt>#define</tt>, aw nieinnym kilkadziesiątprzypadku innychmusielibyśmy linijek,szukać wszystkich wystąpień rozmiaru rozsianych po kodzie całego programu.
{{infobox|W pierwotnym standardzie języka C rozmiar tablicy nie mógł być określany przez zmienną lub nawet stałą zadeklarowaną przy użyciu [[C/Zmienne#Stałe|słowa kluczowego const]]. Dopiero w późniejszej wersji standardu (tzw. C99) dopuszczono taką możliwość. Dlatego do deklarowania rozmiaru tablic często używa się dyrektywy preprocesora [[C/Preprocesor##define|#define]]. Powinni na to zwrócić uwagę zwłaszcza [[C++/Różnice między C a C++|programiści C++]], gdyż tam zawsze możliwe były oba sposoby.}}
 
Innym sposobem jest użycie operatora sizeof do poznania wielkości tablicy. Poniższy kod robi to samo co przedstawiony:
<source lang="c">
#include <stdio.h>
int main()
{
int tab[3] = {3,6,8};
int i;
printf ("Druk tablicy tab:\n");
for (i=0; i<(sizeof tab / sizeof *tab); ++i) {
printf ("Element numer %d = %d\n", i, tab[i]);
}
return 0;
}
</source>
Należy pamiętać, że działa on tylko dla tablic, a nie wskaźników (jak później się dowiesz wskaźnik też można w pewnym stopniu traktować jak tablicę).
 
==Odczyt/zapis wartości do tablicy==
Tablicami posługujemy się tak samo jak zwykłymi zmiennymi. Różnica polega jedynie na podaniupodawaniu '''indeksu''' tablicy. Określa on jednoznacznie, z którego elementu (wartości) chcemy skorzystać. Indeksemspośród jestwszystkich liczbaumieszczonych naturalnaw począwszytablicy. Numeracja indeksów rozpoczyna się od zera., Toco oznacza, że pierwszy element tablicy ma indeks równy 0, drugi 1, trzeci 2, itd.
 
{{Uwaga|Osoby, które wcześniej programowały w językach, takich jak [[Object Pascal|Pascal]], Basic czy [[Fortran]], muszą przyzwyczaić się do tego, że w języku C indeks numeruje się od 0. Ponadto indeksem powinna być liczba - istnieje możliwość indeksowania za pomocą np. pojedynczych znaków ('a','b', itp.) jednak C wewnętrznie konwertuje takie znaki na liczby im odpowiadające, zatem tablica indeksowana znakami byłaby niepraktyczna i musiałaby mieć odpowiednio większy rozmiar.}}
 
Spróbujmy przedstawić to na działającym przykładzie. Przeanalizuj następujący kod:
Linia 86 ⟶ 68:
}
</source>
Jak widać, na początku deklarujemy 5-elementową tablicę, którą od razu zerujemy. Następnie pod trzeci i czwarty element (liczone począwszy od 0) podstawiamy liczby 3 i 7. Pętla ma za zadanie wyprowadzić wynik naszych działań.
 
==Tablice znaków==
Tablice znaków, tj. typu char oraz unsigned char, posiadają dwie ogólnie przyjęte nazwy, zależnie od ich przeznaczenia:
* bufory - gdy wykorzystujemy je do przechowywania ogólnie pojętych danych, gdy traktujemy je jako po prostu "ciągi bajtów" (typ char ma rozmiar 1 bajta, więc jest elastyczny do przechowywania np. danych wczytanych z pliku przed ich przetworzeniem).
* napisy - gdy zawarte w nich dane traktujemy jako ciągi liter; jest im poświęcony osobny rozdział [[C/Napisy|Napisy]].
Linia 122 ⟶ 104:
};
</source>
Innym, bardziej elastycznym sposobem deklarowania tablic wielowymiarowych, jest użycie wskaźników. Opisane to zostało w następnym [[Programowanie:C:/Wskaźniki#Tablice wielowymiarowe|rozdziale]].
 
== Ograniczenia tablic ==
Pomimo swej wygody '''tablice statyczne''' mają ograniczony, z góry zdefiniowany rozmiar, którego nie można zmienić w trakcie działania programu. Dlatego też w niektórych zastosowaniach tablice statyczne zostały wyparte '''tablicetablicami dynamicznedynamicznymi''', tworzonektórych przezrozmiar dynamicznąmoże alokacjębyć pamięciokreślony w trakcie działania programu. OpisaneZagadnienie to zostało opisane w [[C/Wskaźniki#Dynamiczna alokacja pamięci|następnym rozdziale]].
 
{{Uwaga|Przy używaniu tablic trzeba być szczególnie ostrożnym przy konstruowaniu pętli, ponieważ ani kompilator, ani skompilowany program nie będą w stanie wychwycić przekroczenia przez indeks rozmiaru tablicy <ref>W zasadzie kompilatory mają możliwość dodania takiego sprawdzania, ale nie robi się tego, gdyż znacznie spowolniłoby to działanie programu. Takie postępowanie jest jednak pożądane w okresie testowania programu.</ref>. Efektem będzie odczyt lub zapis pamięci, znajdującej się poza tablicą.}}
{{infobox|[[C++/Różnice między C a C++|Programiści C++]] mogą użyć [[C++/Vector|klasy vector]], która może być wygodnym zamiennikiem tablic.}}
 
Wystarczy pomylić się o jedno miejsce (tzw. błąd [[w:off by one|off by one]]) by spowodować, że działanie programu zostanie nagle przerwane przez system operacyjny:
<source lang="c">
Linia 137 ⟶ 120:
foo[i] = 0;
</source>
 
== Ciekawostki ==
W pierwszej edycji konkursu [[w:IOCCC|IOCCC]] zwyciężył program napisany w C, który wyglądał dość nietypowo:
<source lang="c">
short main[] = {
277, 04735, -4129, 25, 0, 477, 1019, 0xbef, 0, 12800,
-113, 21119, 0x52d7, -1006, -7151, 0, 0x4bc, 020004,
14880, 10541, 2056, 04010, 4548, 3044, -6716, 0x9,
4407, 6, 5568, 1, -30460, 0, 0x9, 5570, 512, -30419,
0x7e82, 0760, 6, 0, 4, 02400, 15, 0, 4, 1280, 4, 0,
4, 0, 0, 0, 0x8, 0, 4, 0, ',', 0, 12, 0, 4, 0, '#',
0, 020, 0, 4, 0, 30, 0, 026, 0, 0x6176, 120, 25712,
'p', 072163, 'r', 29303, 29801, 'e'
};
</source>
Co ciekawe - program ten bez przeszkód wykonywał się na komputerach [[w:en:VAX|VAX]]-11 oraz [[w:PDP|PDP]]-11. Cały program to po prostu tablica z zawartym wewnątrz kodem maszynowym! Tak naprawdę jest to wykorzystanie pewnych właściwości programu, który ostatecznie produkuje kod maszynowy. Linker (to o nim mowa) nie rozróżnia na dobrą sprawę nazw funkcji od nazw zmiennych, więc bez problemu ustawił punkt wejścia programu na tablicę wartości, w których zapisany był kod maszynowy. Tak przygotowany program został bez problemu wykonany przez komputer.
 
==Zobacz również ==