Prog cz 5

1. WSKAŹNIKI - PODSTAWY

Wskaźniki, jak sama nazwa wskazuje, mają za zadanie na coś pokazywać. W wypadku języków programowania tym czymś jest fragment pamięci RAM, w którym zapisana jest wartość zmiennej. Co więcej, wskaźnik musi (prawie) zawsze wskazywać na wartość określonego typu (np. int).

Wskaźniki definiujemy poprzez dodanie gwiazdki przed nazwą, np:

int *wskaznik;


Zobaczmy:


char znak = 'M'; // definicja "zwyklej" zmiennej typu char

char *wskaznik; // definicja wskaznika typu char

wskaznik = &znak; // do wskaznika zapisujemy adres w pamieci do zmiennej znak

cout << *wskaznik << endl; // wyswietlenie wartosci zmiennej, na ktora pokazuje wskaznik

cout << wskaznik; // wyswietlenie adresu zmiennej, na ktora pokazuje wskaznik


Wyjaśnijmy sobie, o co chodzi. Aby wpisać do wskaźnika adres do zmiennej znak, skorzystaliśmy z referencji (zapis z & - przypomnij sobie). Jeżeli chcemy w programie odnieść się do wartości zmiennej, na którą pokazuje wskaźnik, musimy dodać przed nim *. Jeśli zaś chcemy zobaczyć jedynie adres zapisany w zmiennej wskaźnikowej, podajemy tylko jego nazwę.


Przykładowo:


int zmienna = 25, *wskaznik; // definicje zmiennych

wskaznik = &zmienna; // wpisanie adresu do wskaznika

*wskaznik = 28; /* wpisanie wartosci do zmiennej, na ktora pokazuje wskaznik (występuje *) */

cout << zmienna;


Do zapamiętania z rozdziału:

- wskaźnik zawiera w sobie adres do komórki pamięci, w której zapisana jest wskazywana zmienna

- aby odnieść się do wskazywanej zmiennej dodajemy przed nazwą wskaźnika *

- zapis &zmienna oznacza, że odnosimy się do adresu zmiennej, a nie do jej wartości


Zadanie:

Napisz program, który iteracyjnie (przy pomocy pętli) wyświetli wszystkie adresy do poszczególnych elementów tablicy liczb całkowitych (tablicę zdeklarujmy jako int tab[100]).


2. OPERATOR NEW I DELETE, TABLICE DYNAMICZNE

Dzięki wskaźnikom możliwe jest w C++ korzystanie z dynamicznych struktur danych. Już wyjaśniam, o co chodzi. Wyobraźmy sobie taką sytuację - mamy stworzyć tablicę n-elementową, przy czym ilość elementów nie jest z góry znana, ale zostanie wprowadzona przez użytkownika. Niektóre kompilatory w takich sytuacjach statyczną (taką, z jakiej korzystaliśmy do tej pory) definicję (int tablica[n]) zamienią automatycznie na dynamiczną (o której zaraz sobie powiemy). Najpierw musimy zdefiniować wskaźnik do danych odpowiedniego typu. W tym celu piszemy:

int *tab;


Aby stworzyć nową tablicę skorzystamy z operatora new:

tab = new int[n];


Zwróćmy uwagę, że nie podajemy ponownie nazwy tablicy (po operatorze new), a jedynie jej typ (który, nawiasem mówiąc, musi być zgodny z typem wskaźnika) oraz rozmiar (n).

Stworzony obiekt możemy oczywiście wykasować i zwolnić miejsce dla nowych zmiennych. Służy do tego operator delete. Używamy go bardzo prosto:

delete [] tab;


Zobaczmy przykład wykorzystujący new i delete:


#include <iostream.h>

main()

{

int *tab, n;

cout << "Podaj ilosc elementow tablicy: ";

cin >> n;

tab = new int[n]; // tworzymy tablice o rozmiarze n

cout << "Powstala tablica " << n << "-elementowa << endl";

delete [] tab; // usuwamy tablice

cout << "Tablicy juz nie ma";

}


Oczywiście operatorów new i delete można także używać w wypadku standardowych zmiennych - wtedy jednak nie piszemy nawiasów kwadratowych [].


Tym właśnie różnią się dynamiczne struktury danych od statycznych - w wypadku dynamicznych program w momencie uruchomienia nie rezerwuje w pamięci RAM obszaru pamięci na zmienne - robi to dopiero w trakcie działania. Dynamiczne zmienne są szczególnie często używane w sytuacjach, gdy mamy do czynienia z danymi o dużych rozmiarach.


Po co nam wskaźniki? Po pierwsze (o czym już powiedzieliśmy): możemy dzięki nim znacznie oszczędzać RAM, rezerwując jej odpowiedni obszar - tworzymy np. tablice o nieznanym początkowo rozmiarze i zwalniamy później pamięć komputera. Po drugie (ale tym się na razie nie będziemy zajmować): możemy odnosić się do konkretnych komórek pamięci operacyjnej. Po trzecie: zużywamy krótszy czas na dostęp do konkretnych elementów tablicy.


Wyjaśnijmy sobie punkt 3 (w ramach dygresji - nie musisz tego pamiętać). Jeśli mamy zdeklarowaną tablicę (np. int tab[n][m]), to gdy odnosimy się do któregoś elementu (przykładowo tab[k][l]), program za każdym razem musi obliczyć jej połozenie względem pierwszego elementu (w naszym przykładzie wyglądałoby to następująco: (k * n) + l). Jest to czynność dosyć czasochłonna (przy dużych rozmiarach danych). Wskaźnik natomiast cały czas pamięta adres do konkretnej komórki pamięci.

Co więcej, aby "przestawić" wskaźnik na kolejny element tablicy wystarczy go inkrementować, np. wskaznik++;


Zobaczmy jak wygląda to w praktyce:


#include <iostream.h>

main()

{

int *wskaznik, tab[100], k;

wskaznik = &tab[0]; // ustawiamy wskaznik na pierwszym elemencie

for(k=0; k<=99; k++)

{

cout << *wskaznik;

wskaznik++; // inkrementujemy wskaźnik

}


Można oczywiście tworzyć całe tablice wskaźników, np:

int *wskazniki[n];


Do zapamiętania z rozdziału:

- operatory new oraz delete pozwalają dynamicznie tworzyć struktury danych o różnych rozmiarach

- do kolejnych elementów tablicy możemy odwoływać się poprzez inkrementację wskaźnika ustawionego na jej pierwszym elemencie


Zadanie:

* Napisz program wczytujący rozmiary 10 tablic liczb całkowitych. Po wczytywaniu kolejnych program ma sprawdzać, czy nie jest dopuszczalny przekroczony limit pamięci, przeznaczony na tablice (niech będzie to np. 2 MB). Jeśli tak, usuwa tablice, które zostały stworzone jako pierwsze, aż do zwolnienia odpowiedniej ilości pamięci. Jeśli nie, tworzy tablicę. Jeśli rozmiar tablicy przekracza 2 MB, program kończy pracę. Jedna liczba całkowita (int) zajmuje w pamięci 4 bajty. Dodatkowo możesz posłużyć się funkcją sizeof(zmienna), która zwraca rozmiar zmiennej w pamięci (w bajtach).


W następnej części kursu zajmiemy się typami danych, które sami będziemy definiować.


Wyszukiwarka

Podobne podstrony:
Prog cz 2
Prog cz 3
Prog cz 6
Prog cz 1
Prog cz 4
Biol kom cz 1
Systemy Baz Danych (cz 1 2)
cukry cz 2 st
wykłady NA TRD (7) 2013 F cz`
JĘCZMIEŃ ZWYCZAJNY cz 4
Sortowanie cz 2 ppt
CYWILNE I HAND CZ 2
W5 sII PCR i sekwencjonowanie cz 2
motywacja cz 1
02Kredyty cz 2
Próg rentowności
Ćwiczenia 1, cz 1