Web - Amazon

We provide Linux to the World


We support WINRAR [What is this] - [Download .exe file(s) for Windows]

CLASSICISTRANIERI HOME PAGE - YOUTUBE CHANNEL
SITEMAP
Audiobooks by Valerio Di Stefano: Single Download - Complete Download [TAR] [WIM] [ZIP] [RAR] - Alphabetical Download  [TAR] [WIM] [ZIP] [RAR] - Download Instructions

Make a donation: IBAN: IT36M0708677020000000008016 - BIC/SWIFT:  ICRAITRRU60 - VALERIO DI STEFANO or
Privacy Policy Cookie Policy Terms and Conditions
Zmienna wskaźnikowa - Wikipedia, wolna encyklopedia

Zmienna wskaźnikowa

Z Wikipedii

W językach programowania niższych poziomów (jak np. Asembler, C, C++, Cyclone) pamięć jest reprezentowana jako jednowymiarowa tablica bajtów - wszystkie zmienne (statyczne i dynamiczne) są umieszczane w tej "tablicy".

Wskaźnik jest indeksem do tej tablicy -- najczęściej ów indeks jest jednocześnie logicznym adresem. Zwykle istnieje też specjalny symbol, który określa wskazanie jako puste. W językach C, C++, Cyclone jest to NULL, w Pascalu nil. Wskaźnik taki nie wskazuje na nic (konkretnie: jego wartość liczbowa jako adresu jest równa 0), gdyż w nowoczesnych systemach operacyjnych żaden proces nie ma dostępu do komórki pamięci o adresie 0, stąd też jest ona wykorzystywana do oznaczenia wskazania do niczego. Wartość ta służy np. do oznaczania końca listy jednokierunkowej, liści drzewa binarnego, itp.

W nowszych językach wysokiego poziomu jak Java, C# zamiast wskaźników używa się ulepszonej formy referencji, które nigdy nie mogą wskazywać na przypadkowy adres pamięci, mogą jedynie wskazywać na rzeczywisty obiekt lub mieć wartość null. Eliminuje to całą kategorię błędów wynikających z próby interpretacji przypadkowego fragmentu pamięci jako obszaru zawierającego konkretne, użyteczne dane.

Spis treści

[edytuj] Definicja wskaźnika na obiekt lub (prostą) zmienną

W językach C/C++ definicja wskaźnika jest instrukcją składającą się z nazwy typu, operatora * i identyfikatora nowotworzonego wskaźnika:

TYP * zmienna;

Przykłady:

int*    p;  // 'p' jest zmienną wskaźnikową przechowującą adres liczby typu 'int'
double* q;  // 'q' jest zmienną wskaźnikową przechowującą adres liczby typu 'double' 
 
struct X;   // deklaracja struktury
X* pp;      // definicja wskaźnika na obiekt/strukturę typu X

Użyty w powyższych przykładach operator * zwany jest operatorem wyłuskania. W języku C tradycyjnie umieszcza się go tuż przy nazwie zmiennej (co uwypukla nazwę typu); w C++ tuż przy nazwie typu (co uwypukla nazwę zmiennej):

int *p;     // zapis w stylu języka C
int* p;     // ta sama instrukcja w stylu języka C++

[edytuj] Operator pobrania adresu

Każda zmienna/obiekt posiada jednoznaczny adres. W językach C i C++ adres ten można pobrać przy pomocy operatora &

int *w;     /* 'w' jest wskaźnikiem na zmienną typu int */
int a = 5;
int b = 5;
 
w = &a;     /* wskaźnik 'w' wskazuje teraz na obszar
               pamięci zajmowany przez zmienną 'a' */
 
w = &b;     /* a teraz 'w' wskazuje na zmienną 'b' */

[edytuj] Wyłuskanie wskaźnika

Obszar wskazywany przez wskaźnik na TYP można interpretować jako zmienną (obiekt) typu TYP. Do odczytywania tej zmiennej służy operator *. Operację pobrania danych za pośrednictwem wskaźnika zwie się wyłuskiwaniem (ang. dereferencing) lub adresowaniem pośrednim (ang. indirection)

int *w;       /* wskaźnik na zmienną typu int */
int  a = 100;
int  b;
 
w = &a;       /* wskaźnik 'w' wskazuje na zmienną typu int 'a' */
b = *w;       /* przypisz zmiennej 'b' wartość spod adresu wskazywanego
                 przez 'w'; teraz 'b' równe jest 100  */

[edytuj] Rzutowanie wskaźnika

Ponieważ formalnie wskaźnik pokazuje na obszar pamięci, można dowolnie interpretować zawartość tej pamięci. Jest to pewne uogólnienie, które może powodować błędy. Rzutowaniem nazywa się operację wymuszającą interpretację danego wskazania jako określonego typu danych. Np.

char* wiki = "Wikipedia";
printf("Adres %d interpreterowany jako\n", (unsigned int)wiki);
printf("* łańcuch znaków: %s\n", wiki);
printf("* znak: %c\n", *(char*)wiki);
printf("* wartość całkowita ze znakiem: %d\n",  *(int*)wiki);
printf("* wartość całkowita bez znaku: %d\n",  *(unsigned int*)wiki);

I przykładowy wynik działania programu:

Adres 134514016 interpreterowany jako
* łańcuch znaków: Wikipedia
* znak: W
* wartość całkowita ze znakiem: 1768646999
* wartość całkowita bez znaku: 1768646999

[edytuj] Problemy podczas rzutowania

O ile takie rzutowanie np.: z typu long double* na typ char* jest bezpieczne o tyle rzutowanie z char* na long double* może już takowe nie być:

long double c = 0.0;
char d = 'x';
 
long double* wsk1LongDouble = &c;
d = (char*)wsk1LongDouble; // bezpiecznie
 
char* wskChar = &d;
c = (long double*)wskChar; // niebezpieczne

Jest to spowodowane tym, że rozmiar zmiennej typu char wynosi 1 bajt (jest to pewne uproszczenie, ale dla potrzeb przykładu wystarczy) podczas gdy zmiennej typu long double wynosi 8 bajtów. W momencie interpretacji (czyli rzutowania) fragmentu pamięci wskazywanej przez wskaźnik typu char* jako typ long double*, nastąpi próba odczytu nie jednego bajtu, ale 8, które znajdują się być może w obszarze pamięci który nie został przydzielony programowi przez system operacyjny. Podobna sytuacja ma miejsce podczas rzutowania w dół

[edytuj] Rzutowanie w dół

Przykład w języku C++:

class Bazowa {
  public:
    int x;
};
 
class Pochodna : public Bazowa {
  public:
    int y;
};
 
void fun1( Bazowa& obiekt ) {
  obiekt.x = 5;
}
 
void fun2( Pochodna& obiekt ) {
  obiekt.y = 5;
}
 
int main() {
Bazowa obiektBazowy;     // deklaracja obiektu klasy Bazowa
Pochodna obiektPochodny; // deklaracja obiektu klasy Pochodna
Bazowa* wskBazowa = &obiektBazowy;
Pochodna* wskPochodna = &obiektPochodny;
fun1( obiektPochodny ); // ok
fun1( *wskPochodna ); // ok
fun2( *((Pochodna*)wskBazowa) ); // nie ok!!
}

Możliwa jest konwersja standardowa obiektu typu pochodnego na typ bazowy. Zarówno obiekt bazowy jak i pochodny posiadają w swojej strukturze pole x. Problem może się pojawić podczas konwersji w drugą stronę: z typu bazowego na typ pochodny (w tym wypadku musi być ona jawna). Obiekt klasy bazowej nie posiada w swojej strukturze pola y (jest mniejszy z punktu widzenia rozmiaru) stąd też wskazanie w funkcji void fun2( Pochodna& ) obiekt.y = 5; będzie wskazywało poza obszar zajmowany przez obiekt klasy bazowej co może naruszyć ochronę pamięci.

Pomimo tego, czasem celowo rzutuje się w dół, lecz należy dbać o bezpieczeństwo takiego rzutowania.

Wikibooks
Zobacz podręcznik na Wikibooks: C - Wskaźniki

Zobacz też: język programowania, C, referencja

Our "Network":

Project Gutenberg
https://gutenberg.classicistranieri.com

Encyclopaedia Britannica 1911
https://encyclopaediabritannica.classicistranieri.com

Librivox Audiobooks
https://librivox.classicistranieri.com

Linux Distributions
https://old.classicistranieri.com

Magnatune (MP3 Music)
https://magnatune.classicistranieri.com

Static Wikipedia (June 2008)
https://wikipedia.classicistranieri.com

Static Wikipedia (March 2008)
https://wikipedia2007.classicistranieri.com/mar2008/

Static Wikipedia (2007)
https://wikipedia2007.classicistranieri.com

Static Wikipedia (2006)
https://wikipedia2006.classicistranieri.com

Liber Liber
https://liberliber.classicistranieri.com

ZIM Files for Kiwix
https://zim.classicistranieri.com


Other Websites:

Bach - Goldberg Variations
https://www.goldbergvariations.org

Lazarillo de Tormes
https://www.lazarillodetormes.org

Madame Bovary
https://www.madamebovary.org

Il Fu Mattia Pascal
https://www.mattiapascal.it

The Voice in the Desert
https://www.thevoiceinthedesert.org

Confessione d'un amore fascista
https://www.amorefascista.it

Malinverno
https://www.malinverno.org

Debito formativo
https://www.debitoformativo.it

Adina Spire
https://www.adinaspire.com