Wskaźniki
Adam Boduch
W tym artykule dowiesz się z niej o sposobach posługiwania się zmiennymi oraz wskaźnikami w C++.
A więc zaczynamy.
W języku C++ można zadeklarować: zmienne, funkcje oraz typy. Na początku zajmiemy się zmiennymi oraz stałymi.
Stała to taka zmienna, której wartość można przypisać tylko raz. Z punktu widzenia komputera niewiele się to różni, bo miejsce w pamięci i tak, stosownie do zadeklarowanego typu zarezerwować trzeba, umieścić w tablicy i zapamiętać sobie identyfikator i adres. Jedyna praktyczna różnica polega na tym, że zmiennej zadeklarowanej jako stała, np.:
const float PI = 3.142;
nie można przypisać w programie żadnej innej wartości, innymi słowy zapis:
const float PI = 3.14;
jest jednocześnie DEKLARACJĄ, DEFINICJĄ i ZAINICJOWANIEM stałej PI.
Przykład :
float x,y,z; /*DEKLARACJA*/
const float TEMP = 6.0; /*DEFINICJA*/
x = 11; /*ZAINICJOWANIE zmiennej*/
Definicja powoduje nie tylko określenie, jakiego typu wartościami może operować dana zmienna bądź funkcja, która zostaje od tego momentu skojarzona z podanym identyfikatorem, ale dodatkowo powoduje:
- w przypadku zmiennej - przypisanie jej wartości,
- W przypadku funkcji - przyporządkowanie ciała funkcji.
Zdefiniujmy dla przykładu własną funkcje:
Przykład 1.
int PokazTekst(void)
{
printf("\\nPrzykładowy tekst\\n");
return 0;
}
PODSTAWOWE TYPY DANYCH
Język C/C++ operuje pięcioma podstawowymi typami danych:
- char (znak, numer znaku w kodzie ASCII) - 1 bajt;
- int (liczba całkowita) - 2 bajty;
- float (liczba z pływającym przecinkiem) - 4 bajty;
- double (podwójna ilość cyfr znaczących) - 8 bajtów;
- void (nieokreślona) 0 bajtów.
Zakres wartości przedstawiono w Tabeli poniżej.
Podstawowe typy danych w C++.
Typ Znak Zakres wartości
char signed -128...+127
int signed -32768...+32767
float signed +-3.4E+-38 (dokładność: 7 cyfr)
double signed 1.7E+-308 (dokładność: 15 cyfr)
void nie dotyczy bez określonej wartości.
(signed - ze znakiem, unsigned - bez znaku.)
WSKAŹNIKI
Wskaźnik to zmienna, która zawiera adres innej zmiennej w pamięci komputera. Istnienie wskaźników umożliwia pośrednie odwoływanie się do wskazywanego obiektu (liczby, znaku, łańcucha znaków itp.) a także stosunkowo proste odwołanie się do obiektów sąsiadujących z nim w pamięci. Załóżmy, że:
x - jest umieszczoną gdzieś w pamięci komputera zmienną całkowitą typu int zajmującą dwa kolejne bajty pamięci, a
px - jest wskaźnikiem do zmiennej x.
Jednoargumentowy operator & podaje adres obiektu, a zatem instrukcja:
px = &x;
przypisuje wskaźnikowi px adres zmiennej x. Mówimy, że:
px wskazuje na zmienną x lub
px jest WSKAŹNIKIEM (pointerem) do zmiennej x.
Operator * (naz. OPERATOREM WYŁUSKANIA) powoduje, że zmienna "potraktowana" tym operatorem jest traktowana jako adres pewnego obiektu. Zatem, jeśli przyjmiemy, że y jest zmienną typu int, to działania:
y = x;
oraz
px = &x;
y = *px;
będą mieć identyczny skutek. Zapis y = x oznacza:
"Nadaj zmiennej y dotychczasową wartość zmiennej x";
a zapis y=*px oznacza:
"Nadaj zmiennej y dotychczasową wartość zmiennej, której adres w pamięci wskazuje wskaźnik px" (czyli właśnie x !).
Wskaźniki także wymagają deklaracji. Poprawna deklaracja w opisanym powyżej przypadku powinna wyglądać tak:
int x,y;
int *px;
Zapis int *px; oznacza:
"px jest wskaźnikiem i będzie wskazywać na liczby typu int".
Zwróć uwagę, że operatory & i * mają wyższy priorytet niż operatory arytmetyczne, dzięki czemu
- najpierw następuje pobranie spod wskazanego przez wskaźnik adresu zmiennej;
- potem następuje wykonanie operacji arytmetycznej; (operacja nie jest więc wykonywana na wskaźniku, a na wskazywanej zmiennej!).
W języku C++ możliwa jest także sytuacja odwrotna:
Y = *(pX + 1);
Ponieważ operator () ma wyższy priorytet niż * , więc: najpierw wskaźnik zostaje zwiększony o 1; potem zostaje pobrana z pamięci wartość znajdująca się pod wskazanym adresem (w tym momencie nie jest to już adres zmiennej X, a obiektu "następnego" w pamięci) i przypisana zmiennej Y.
Taki sposób poruszania się po pamięci jest szczególnie wygodny, jeśli pod kolejnymi adresami pamięci rozmieścimy np. kolejne wyrazy z tablicy, czy kolejne znaki tekstu.
Jeśli dwa wskaźniki wskazują zmienne takiego samego typu, np. po zadeklarowaniu:
int *pX, *pY;
int X, Y;
i zainicjowaniu:
pX = &X; pY = &Y;
można zastosować operator przypisania:
pY = pX;
Spowoduje to skopiowanie wartości (adresu) wskaźnika pX do pY, dzięki czemu od tego momentu wskaźnik pY zacznie wskazywać zmienną X. Zwróć uwagę, że nie oznacza to bynajmniej zmiany wartości zmiennych - ani wielkośc X, ani wielkość Y, ani ich adresy w pamięci NIE ULEGAJĄ ZMIANIE. Zatem działanie instrukcji:
pY = pX; i *pY = *pX;
jest RÓŻNE a wynika to z priorytetu operatorów:
najpierw * wyłuskanie zmiennych spod podanych adresów, potem = przypisanie wartości (ale już zmiennym a nie wskaźnikom!).
Shawk shawk@kki.net.pl
Thx:) Dzięki artykułowi udało mi się w końcu zrozumieć idee wskaźników. Po lekturze podrozdziału z Thinking in C++ nie było to dla mnie zbyt jasne.
A typy short, long int, long long int, long double, long long double to już wywiało z C++? Czy ja o czymś nie wiem? Poza tym rozmiary typów podstawowych zależą od platformy i nie są (jak np. w Javie) wszędzie i zawsze takie same. No a poza tym, przedmówcy zauważyli już, że art słaby. To jest liźnięcie wskaźników i to na poziomie C, a nie C++. Szkoda słów, nawet krytycznych.
progrmuje troche w C++, przeczytalem Symfonie C++, czytam pasjeC++ i kilka innych dobrych ksiazek teraz, i sadze ze jest to slaby kurs ;/ wskazniki sa pobieznie opisane... jest to jeden z najwazniejszych aspektow C++ (joke?) dla poczatkujacych i bardziej zaawansowanych, dlaczego jeden z najwazniejszych? DLA NAUKI! bo z tym sa najwieksze problemy, dlatego wskazniki powinno sie wykuc wprost na pamiec... zrozumiec ich definicje umiec ja czytac i rozumiec! nie mozna czegos umiec na pamiec tego nie rozumiejac, autor tego tekstu znany z dobrych ksiazek o Delphi opisal to POBIEZNIE! nie polecam czytania, mimo iz dobrze napisany poniewaz sa ksiazki i bdb. kursy internetowe w ktorych to wszystko jest napisane bardziej obszernie, czyli LEPIEJ!
sam kurs jest dobry pod wzgledem napisania, poniewaz nie ma wielu bledow, a co do deklaracji i definicji to :
int x; jest definicja ktora jest tez deklaracja... a nie definicja... specjalisci sie trzymaja strasznie definicji tych dwoch pojec ze az to sie gmatwa.. dlatego w skrocie sie mowi : ze jest to deklaracja :) (deklarujemy..)
gritz dla autora bo mial zapal chcial dobrze i to sie liczy :)
Jak juz piszesz cos o wskaznikach to napisz tez cos o wskaznikach do tablic !!
"inicjalizacja:
int x=11;
deklaracja i definicja:
int x;
deklaracje i definicje rozróżniamy przy tworzeniu funkcji."
Tak naprawdę, to:
int i; //definicja
int i = 1024; //definicja + inicalizacja
extern int i; //deklaracja
Deklaracje i definicje zmiennych także się rozróżnia, ta pierwsza jest z extern.
Artykuł jest ok, choć osobiście uważam, iż operator "wyłuskania" trochę brzydko brzmi :) . Bardziej poprawną nazwą jest operator dereferencji.
ponadto zapis "x=11" wcale nie jest inicjalizacją tylko przypisaniem.
inicjalizacja:
int x=11;
deklaracja i definicja:
int x;
deklaracje i definicje rozróżniamy przy tworzeniu funkcji.
Ten artykuł tyczy się rónież języka c, autor nie użył ani trochę nowości dodanych w c++.
Ponadto autor stwierdził, że wskaźnik służy do pośredniego dostawania się do zmiennych, a to zastosowanie wskaźników jest raczej mało przydatne, chyba że używamy tablic - czego autor nie opisał wystarczająco.
Głównym zastosowaniem wskaźników jest dynamiczna alokacja pamięci i obsługa dynamicznych struktur danych co obowiązkowo powino znaleźć się w takim arcie !!!!
I też ważna jest sprawa, czy wskaźnik, jeśli dodamy do niego jeden, to przesuwa się o jeden bajt, czy o jeden rozmiar wskazywanej zmiennej? Kilka moich programów źle działało, bo tego nie wiedziałem. Jeśli mamy wskaźnik do jakiejś zmiennej, to dodając jeden, adres przesuwa się o tyle bajtów, ile zajmuje typ tej zmiennej w pamięci. Dla typu void przesuwa się o 1 bajt
Jest Spoko ;-)
jesli to ma byc text o wskaznikach to wypadaloby tez wspomniec chociaz o typie void *, stwierdzenie typu "void nie dotyczy bez określonej wartości" nie jest do konca trafne i nie mozna bagatelizowac tego typu .Np.:
void *bufor;
Algor
Mogłoby się znależć trochę informacji o wskażnikach zdolnych pokazywać na funkcje, ale poza tym artykuł jest oki