poniedziałek, 28 grudnia 2015

C - Wskaźniki

W tym poście chciałbym opisać sposób deklarowania wskaźników, oraz opisać po co i do czego się je stosuje.

Wskaźnik jest to specjalny rodzaj zmiennej, który przechowuje jej adres . Pozwala na wskazanie miejsca w jakim została ona zapisana. Dzięki nim możliwe jest współużytkowanie pamięci przez różne funkcje. Daje to możliwość ograniczenia ilość wykorzystywanej pamięci. Właśnie po to przekazywany jest jej adres, tak aby inna funkcja wiedziała gdzie znaleźć daną zmienną.

Wskaźniki można wykorzystać w następujący sposób:

  • Deklaracja wskaźnika do obiektu określonego typu (Typ *NazwaZmiennej) np. char *Znak;
  • Pobranie wartości z adresu zmiennej ( *NazwaZmiennej) np. *Znak;
  • Wyciągnięcie adresu podanej zmiennej ( &NazwaZmiennej) np. &Znak;
Poniżej przedstawię różne programy prezentujące możliwości pracy z wskaźnikami.


Program 1


Najbardziej podstawowe operacje, pobranie zmiennej w miejsca zapisanego, wyświetlenie adresu oraz wartości:

#include <stdio.h>
 
int main (void)
{
   char Znak = 'K';
   printf("Wartość w zmiennej Znak: %c\n", Znak);
   printf("Adres Znak: %p\n", &Znak);
   return 0;
}

Program 2


W tym programie zaprezentuję odwołanie się przez jedną zmienną do innej wykorzystując do tego wskaźnik.

#include <stdio.h>
 
int main (void)
{
   char Znak = 'K';
   char *wskaznik;
   //Pokazanie na zmienną Znak, dokładnie na jej adres
   wskaznik = &Znak;
 
   //Pobranie danej zapisanej pod zmienną Znak
   printf("Wartość w zmiennej Znak: %c\n", *wskaznik);
   //Wyświetlenie adresu
   printf("Adres Znak: %p\n", wskaznik);
   return 0;
}

Program 3


W tym przykładzie zaprezentuje wykonywanie operacji na wskaźnikach. Często są one dokonywane w zewnętrznych funkcjach których odwołania znajdują się jedynie w programie głównym. 

Dla takich zmiennych operacje wykonywane są lokalnie wewnątrz funkcji. W przypadku przekazywania wskaźnika do funkcji zostaje utworzona kopia wskaźnika, na której można dokonywać operacji. Obiekty na jakie wskazuje wskaźnik pozwalają na zlokalizowanie ich w pamięci, dzięki temu wszelkie zmiany mogą być dokonywane na oryginale nie na kopii. Operacje tylko na kopii dokonuje się poprzez przekazywanie zwykłych zmiennych.

 #include <stdio.h>
 
 void ZmianaWskaznik (char * );
 void ZmianaWartosc (char);
 
 int main (void)
 {
   int znak='I';
 
   //
   printf ("znak1= %d, %c\n", znak, znak);
 
   ZmianaWartosc(znak);
   printf ("znak2= %d, %c\n", znak, znak);
 
   ZmianaWskaznik(&znak);
   printf ("znak3= %d, %c\n", znak, znak);
 
   return 0;
 }
 
void ZmianaWartosc (char znak)
 {
   znak = 'P';
 }
 void ZmianaWskaznik (char *znak)
 {
   (*znak) = 'K';
 }

Jak można zaobserwować podczas wykonywania programu, po wejściu w ZmianaWartosc, zmienna znak zostaje zmieniona tylko lokalnie w funkcji. Po jej opuszczeniu nie zostaje ona na stałe wpisana do zmiennej znak w funkcji main. Natomiast ZmianaWskaznik daje możliwość ponownego zdefiniowania zmiennej na której dokonuje się operacji.

Program 4


Ten punkt zawiera wywołanie wskaźnika o funkcji.

 #include <stdio.h>
 
float PobierzLiczbe(float);
 
int main (void)
{
   float (*wskaznik)(float);
   wskaznik =& PobierzLiczbe;
   printf("Wartosc kwadratu wartosci to: %.2f", wskaznik(10.67));
   return 0;
}
 
float PobierzLiczbe(float x)
{
    return x*x;
}

Program 5


Istnieje możliwość zdefiniowania wskaźników jako stałe. Występują dwa rodzaje pierwszy z nich jest to wskaźnik na stałą wartość, drugi rodzaj to stałe wskaźniki.

const char *a; lub char const *a;

char *const a;

Deklaracja stałej działa tak samo w przypadku wskaźników co zmiennych. Nie można zmieniać ich wartości w późniejszym etapie programu.

 #include <stdio.h>
 
int main()
{
     //Zmienna int
     int i=0;
 
     //Wskaźnik na stałą wartość
     //nie można zmienić deklaracji
     const int *a=&i;
 
     //Stały wskaźnik może być zmieniany
     int * const b=&i;
 
     *b = 2;
     a = b;
 
     printf("Wartosc b: %d\n", *b);
     printf("Wartosc a: %d\n", *a);
 
     return 0;
}