Do tej pory używaliśmy tablic, które miały z góry zadany rozmiar. Deklarowaliśmy je w bardzo prosty sposób:
lub też:
Chcielibyśmy poszerzyć funkcjonalność naszego programu tak, aby była możliwa deklaracja tablic o długości określanej dopiero w trakcie działania programu. Mówimy wówczas o tzw. dynamicznej (tzn. wykonywanej podczas działania programu, a nie podczas kompilacji) alokacji pamięci. W języku C, na taki mechanizm składa się kilka etapów:
malloc()
.free()
.Nowe funkcje wymagają użycia biblioteki stdlib.h
.
Poniższy fragment kodu ilustruje cały mechanizm:
#include <stdlib.h>
void main() {
int N = 100;
double *x; // wskaznik do pierwszego
// elementu tablicy
x = (double*)malloc(N * sizeof(double)); // alokacja tablicy
free(x); // zwolnienie pamieci
}
Kluczowym elementem mechanizmu jest właściwe zastosowanie funkcji
malloc()
. Jej argumentem jest rozmiar pamięci, o którą
wnioskujemy. Potrzebujemy rozmiaru równego \(N\) razy rozmiar zajmowany przez zmienną
typu double
. Stąd wynika obecność funkcji
sizeof()
, która zwraca rozmiar danego typu zmiennych.
Ponadto używamy mechanizmu rzutowania – przed funkcją
malloc()
pojawia się rzutowanie na wskaźnik do typu. W
naszym przypadku jest to wywołanie (double *)
1. Po pracy na tablicy,
należy pamiętać o zwolnieniu pamięci, którą ona zajmowała. Służy do tego
funkcja free()
.
Nowy mechanizm będzie nam potrzebny do wykonania zadania polegającego na wczytaniu współrzędnych konturów map z plików oraz narysowaniu tych map na ekranie. Współrzędne konturów dwóch map są zapisane w plikach: plik1.txt oraz plik2.txt. Pliki mają następującą strukturę:
Pierwsza linia pliku zawiera liczbę punktów zapisanych w pliku. Poniżej, współrzędne \(x\) oraz \(y\) są zapisane w oddzielnych kolumnach.
void printCoords(double *x, double *y, int N, int start, int end)
,
która będzie drukować na ekran zadany przedział współrzędnych z danej
mapy. Funkcja ma informować, gdy zadany przedział nie może być
wydrukowany (bo np. zmienna end
przekracza długość
tablicy).void display()
, która będzie rysować
zadany kontur mapy na ekranie w oknie graficznym. Kontur ma być
narysowany za pomocą linii, które będą łączyć kolejne punkty. Zwróć
uwagę na to, aby połączyć również ostatni punkt z pierwszym. Wyświetl
oba kontury na jednym obrazku. Co to za mapy?Mając kontur, możemy policzyć kilka interesujących rzeczy:
double perimeter()
, która zwraca obwód
zadanego konturu.double area()
, która zwraca powierzchnię
danej mapy. Powierzchnię mapy należy policzyć jako sumę powierzchni
trójkątów, których podstawy są kolejnymi odcinkami konturu a wierzchołek
jest zlokalizowany gdziekolwiek (najwygodniej położyć go w zerze). Pole
takiego trójkąta będzie po prostu połową modułu iloczynu wektorowego,
gdzie wektorami są boki trójkąta: \[
S_{i}=\frac{1}{2} | \boldsymbol v_i\times \boldsymbol v_{i+1} | =
\frac{1}{2} (x_iy_{i+1}-x_{i+1}y_i)
\] Pamiętaj o ostatnim i pierwszym punkcie. Zwróć uwagę, że
otrzymane pole może być ujemne. Od czego to zależy?programując w C można by zrezygnować z rzutowania,
wówczas malloc()
zwróci wskaźnik typu void*
.
Jednak powszechnie stosujemy kompilatory języka C++, który jest językiem
o tzw. silnej kontroli typów i nie zezwala na to, by wskaźnik nie miał
typu. Nie zagłębiając się w szczegóły, należy wyrobić sobie nawyk
rzutowania wskaźnika zwracanego przez funkcję malloc()
, aby
uniknąć nieprzyjemnych sytuacji w przyszłości.↩︎