1/5
Język C
Instrukcja
laboratoryjna
Temat: Wskaźniki.
6
Przygotował: mgr inż . Maciej Lasota 1)
Wskaźniki.
Wskaźniki (zmienne wskaź nikowe) stanowią jedno z fundamentalnych pojęć języka C. Wskaźnik jest to zmienna przechowująca adres (znajdujący się w pamięci operacyjnej komputera) innej zmiennej, tablicy lub funkcji (zadeklarowanej w programie).
W języku C często wykorzystuje się wskaźniki, ze względu na to że jest to czasami jedyny sposób przedstawienia algorytmu obliczenia, częściowo zaś dlatego że ich użycie zwykle prowadzi do bardziej zwartego i efektywnego kodu. Deklaracja zmiennej wskaźnikowej polega na podaniu typu danych na jaki będzie wskaźnik wskazywał oraz podaniu gwiazdki „*”
przed nazwą zmiennej. Często stosuje się ujednolicone nazewnictwo zmiennych wskaźnikowych (np. dopisując do każdej zmiennej _ptr, _wsk itp.) w celu wyeliminowania późniejszych pomyłek.
Deklaracja zmiennej wskaźnikowej:
[typ danych] *[nazwa zmiennej wskaź nikowej];
Przykład:
int wiek;
//zwykle zmienne
char znak;
//zwykle zmienne
int *wiek_wsk;
//zmienne wskaznikowe
char *znak_wsk;
//zmienne wskaznikowe
Do zarządzania wskaźnikami wykorzystujemy dwa specjalne operatory. Pierwszym operatorem jest operator gwiazdki „*”, drugim zaś operator ampersand „&”.
•
„*” - operator „dereferencji” , czyli operator odwołania się danych wskazywanych przez dany wskaźnik.
•
„&” - operator pobrania adresu (zmiennej, struktury, tablicy itp.).
2/5
Przykład:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int temp;
int *wskaznik;
temp = 100;
printf("Liczba w zmiennej TEMP: %d\n",temp); wskaznik = &temp;
// przypisujemy wskaznikowi
// adres zmiennej TEMP
*wskaznik = 200;
// pod adres wskaznika
// przypisujemy wartosc 200
printf("Liczba wskazywana przez
wskaznik: %d\n",*wskaznik);
return (0);
}
2)
Wskaźniki a tablice jednowymiarowe.
W języku C zacierają się różnice istniejące pomiędzy wskaźnikami i tablicami, w wielu przypadkach traktowane są tak samo. Wykonywana jest automatyczna konwersja między nimi. Elementy tablicy podczas tworzenia (uruchamiania programu) przypisywane są do kolejnych adresów w pamięci. Oznacza to że pierwszy element tablicy może znajdować się pod adresem 0xFF1000, natomiast kolejne elementy analogicznie pod adresami 0xFF1001, 0xFF1002, ... itd.
Taki sposób alokacji pamięci dla tablic w programach napisanych w języku C, pozwala na odnalezienie danego elementu tablicy za pomocą indeksów lub za pomocą wskaźników.
Przykład:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int tab[4]={20,40,50,100};
int *wsk;
3/5
wsk = &tab[0];
printf("Element pierwszy tablicy --> %d\n",*wsk); wsk = wsk + 1;
printf("Element drugi tablicy --> %d\n",*wsk); wsk++;
printf("Element trzeci tablicy --> %d\n",*wsk); wsk++;
*wsk = 200;
printf("Element czwarty tablicy --> %d\n",*wsk); return (0);
}
3)
Wskaźniki a tablice wielowymiarowe.
W języku C tablice wielowymiarowe, reprezentowane są jako tablice tablic (każdy element tablicy zawiera wskaźnik na tablicę). Zwiększenie liczby wymiarów tablicy zwiększa równocześnie poziom skomplikowania z punktu widzenia wskaźników.
Przykład:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int macierz[4][4] = { {3,2,1,0}, {5,9,0,3},
{1,2,8,4}, {2,5,6,7} };
printf("macierz: \t%p\t\tmacierz+1:
\t%p\n",macierz,macierz+1);
printf("macierz[0]: \t%p\t\tmacierz[0]+1:
\t%p\n",macierz[0],macierz[0]+1);
printf("*macierz: \t%p\t\t*macierz+1:
\t%p \n",*macierz,*macierz+1);
printf("\n");
printf("macierz[0][0]: \t%d\n",macierz[0][0]); printf("macierz[1][1]: \t%d\n",macierz[1][1]); printf("macierz[2][3]: \t%d\n",macierz[2][3]); printf("\n");
4/5
printf("*macierz[0]: \t%d\n",*macierz[0]); printf("*macierz[1]: \t%d\n",*macierz[1]); printf("*macierz[2]: \t%d\n",*macierz[2]); printf("\n");
printf("**macierz:
\t%d\n",*macierz[0]);
printf("*(*macierz+1): \t%d\n",*(*macierz+1)); printf("*(*macierz+2): \t%d\n",*(*macierz+2)); printf("\n");
printf("**macierz: \t\t%d\n",*macierz[0]); printf("*(*(macierz+1)+1): \t%d\n",*(*(macierz+1)+1)); printf("*(*(macierz+2)+3): \t%d\n",*(*(macierz+2)+3)); return (0);
}
4)
Wskaźniki a funkcje.
W języku C parametry do funkcji przekazywane są zawsze przez wartość (z wyją tkiem przekazywania tablic). Oznacza to, że w ciele funkcji operujemy jedynie na kopiach zmiennych. Czasami jednak w programie przydatna jest możliwość modyfikacji przekazywanych zmiennych.
Przekazując do funkcji zamiast zwykłych zmiennych wskaźniki do tych zmiennych, mamy możliwość modyfikacji oryginalnych wartości przechowywanych przez zmienne w ciele funkcji.
Przykład:
#include <stdio.h>
#include <stdlib.h>
void sum(int *k, int *l, int *s)
{
*s = (*k + *l);
}
int main()
{
int a,b;
int suma;
printf("Podaj liczbe a: ");
scanf("%d",&a);
printf("Podaj liczbe b: ");
scanf("%d",&b);
5/5
sum(&a,&b,&suma);
printf("Suma: (%d + %d) = %d\n",a,b,suma); return (0);
}
5)
Wskaźniki a struktury danych.
W przypadku, gdy mamy zadeklarowany wskaźnik na strukturę danych, dostęp do poszczególnych składowych struktury odbywa się za pomocą tzw. notacji strzałkowej.
Notacja ta polega na podaniu wskaźnika do struktury, „->” (strzałki) oraz składowej do, której się odwołujemy
Przykład:
struct data
{
int dzien;
int miesiac;
int rok;
} data_urodzenia;
struct data *wsk;
wsk = &data_urodzenia;
scanf(”%d”,&wsk->dzien);
scanf(”%d”,&wsk->miesiac);
scanf(”%d”,&wsk->rok);
printf(”Data urodzenia: %d-%d-%d\n”
,wsk->dzien
,wsk->miesiac
,wsk->rok);