Podstawy
Informatyki
wykład dla studentów
studiów magisterskich
dr inż. Grzegorz Bliźniuk
Instytut Systemów Informatycznych
Wydział Cybernetyki WAT
Warszawa
WYKŁAD 4
2
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wykład 4: Wskaźnikowe typy
danych
podstawy typów wskaźnikowych
operatory wskaźnikowe
wskaźniki a typy tablicowe i napisy
wskaźnikowe parametry funkcji
czas wykładu: 2 godziny lekcyjne
3
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Wskaźnik jest specjalnym typem
danych
Zmienna typu wskaźnikowego
przechowuje wskazanie do
(adres) innego obiektu (zmiennej)
w pamięci operacyjnej
Wskazania poprzez typy
wskaźnikowe można traktować
tak, jak nazwane adresy w
pamięci operacyjnej
W związku z tym wskaźniki mają
określoną specjalną arytmetykę
wskaźników, dzięki którym można
w stosunkowo łatwy sposób
operować na adresach w pamięci
operacyjnej
p = =
wskazanie
q = =
wartość
4
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Deklaracja zmiennej
wskaźnikowej w języku C:
typ
*
zmienna_wskaźnikowa;
znak
gwiazdki
oznacza
wskaźnik
- jest on
bardzo
ważny!!!
zmienna_wskaźniko
wa
= = wskazanie na
zmienną
wskazywany
obiekt
= = bliżej
nieokreślona
zmienna
typu „typ”
5
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Deklaracja wskaźnika na
zmienną całkowitoliczbową
int
*
p
;
p
= = wskazanie na
zmienną
wskazywany
obiekt
= = bliżej
nieokreślona
zmienna
typu int
6
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Deklaracja wskaźnika na
zmienną całkowitoliczbową
int
*
p, q
;
wskaźnik
na zmienną
całkowitoliczbową
zmienna
całkowitoliczbowa
Ustawienie wskazania z p na q:
p = & q
;
znak
& (ampersand)
oznacza ustawienie wskazania
adresowego dla wskaźnika
p
= =
wskazanie
q
= =
wartość_nieznana
7
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Ustawienie wskazania na
zmienną całkowitoliczbową
int
*
p, q
;
p=&q; /*adres w PAO*/
Podstawienie wartości liczby:
q=150; lub:
*
p=150;
p
= =
wskazanie
q
= =
150
ustawienie wartości
przez zmienną
wskazywaną
ustawienie wartości
przez zmienną
wskaźnikową
- ODWOŁANIE NIEJAWNE
do zmiennej
q
8
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podstawy typów wskaźnikowych
Przykład programu ze wskaźnikami:
#include <stdio.h>
main( )
{
int *p, q;
p=&q; /*ustawienie wskazania z p na q*/
*p=150; /*niejawne przypisanie wartości do q*/
printf(„Wartość q wynosi: %d\n”, q);
/*czy można
inaczej?*/
return 0;
}
9
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Operatory wskaźnikowe
Poznaliśmy już dwa podstawowe operatory dla typów
wskaźnikowych. Są to:
operator zwracający wartość przechowywaną pod
konkretnym wskazaniem -
oznaczany gwiazdką -
*
operator zwracający adres zmiennej wskazywanej -
oznaczany „ampersandem” -
&
Poznajmy jeszcze pozostałe cztery operatory dla
zmiennych wskaźnikowych
10
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Arytmetyczne operatory
wskaźnikowe
Arytmetyka wskaźników jest inna niż arytmetyka na
liczbach, ponieważ:
inkrementacja wartości wskaźnika „p” oznacza
przejście do adresu:
„p + liczba bajtów dla wskazywanego przez p”
dekrementacja wartości wskaźnika „p” oznacza
przejście do adresu:
„p - liczba bajtów dla wskazywanego przez p”
Dla wskaźnika do typu
char
będzie to przechodzenie
co 1 bajt
,
Dla wskaźnika do typu
int
będzie to przechodzenie
co 2 bajty
,
Dla wskaźnika do typu
float
- przechodzenie
co 4 bajty
??? Jak to wygląda dla wskaźników do pozostałych typów
11
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Arytmetyczne operatory
wskaźnikowe
Przykład:
int *p, q;
p=&q; /*załóżmy, że p wskazuje na adres: 100*/
*p=200; /*wartość wskazywana przez p == 200*/
p++; /*p wskazuje na adres 102 - dlaczego?*/
p++; /* na jaki adres wskazuje p ?*/
p = p + 12; /*p wskazuje na adres 128 - dlaczego?*/
/* na jaką wartość wskazuje p?*/
Do poćwiczenia:
Wykonaj analogiczne do powyższych działania dla
wskaźników do typów char, float, long, double.
12
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Arytmetyka wskaźników a
arytmetyka liczb
Wykorzystując wskaźniki na liczby trzeba koniecznie rozróżniać
arytmetykę wskaźników od zwykłej arytmetyki liczb:
int *p, q;
p=&q;
q= 150;
*p++; /*zwiększenie adresu o 2 bajty - dlaczego?*/
*p- -; /*zmniejszenie adresu o 2 bajty - wskazanie na q*/
(*p)++; /*inkrementacja wartości wskazywanej przez p
jaka jest teraz wartość zmiennej q?*/
(*p)++; /*a teraz q == 152 !!!! */
operatory
wskaźnikowe
operatory
arytmetyczne
13
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Arytmetyka wskaźników a
arytmetyka liczb
Przykład 1. Wypisywanie wartości wskaźników (adresów w PAO):
#include <stdio.h>
main( )
{
char *cp, c;
int *ip, i;
float *fp, f;
double *dp, d;
cp=&c; /*ustawienie wskaźników*/
ip=&i;
fp=&f;
dp=&d;
/*wypisanie bieżących wartości wskaźników*/
printf(„Wartości wskaźników: %p, %p, %p, %p \n”, cp, ip, fp, dp);
return 0;
}
%p
operator konwersji
dla wypisywania wskaźników
14
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Arytmetyka wskaźników a
arytmetyka liczb
Przykład 2. Pokazanie różnicy pomiędzy arytmetyką liczb i wskaźników:
#include <stdio.h>
main( )
{
int *ip, i;
ip=&i; /*ustawienie wskaźnika*/
i=200; /*ustawienie liczby*/
/*wypisanie bieżących wartości*/
printf(„Wskaźnik: %p, liczba: %d \n”, ip, i);
/*zwiększenie wartości liczby*/
(*ip)++;
/*wypisanie bieżących wartości*/
printf(„Wskaźnik: %p, liczba: %d \n”, ip, i);
/*zwiększenie wskaźnika*/
*ip++;
/*wypisanie bieżących wartości*/
printf(„Wskaźnik: %p, liczba: %d \n”, ip, i);
return 0;
}
15
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a typy tablicowe
Język C w sposób wyjątkowy utożsamia wskaźniki i tablice
Tak faktycznie, to w wyniku deklaracji zmiennej tablicowej,
środowisko języka C tworzy wskaźnik na początek tej tablicy.
Miejsca na pozostałe elementy tablicy są zajmowane w
zależności od rozmiaru tablicy.
Tablica zajmuje spójny obszar pamięci operacyjnej
Tak więc do tablic możemy odnosić się w sposób tradycyjny,
tzn. przy pomocy nazwy zmiennej z indeksem tablicy: tab[i]
lub stosując arytmetykę wskaźników
Takie traktowanie tablic jest szczególnie przydatne dla tzw.
tablic otwartych i łańcuchów znaków - bez wstępnego
określenia ich długości. Środowisko języka C jest w stanie na
bieżąco reagować na aktualne potrzeby programisty w tym
zakresie
Takich cech nie ma większość innych języków
programowania
16
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a typy tablicowe
W poniższym programie przedstawiono klasyczną i
wskaźnikową referencję do elementów tablicy tab:
#include <stdio.h>
main( )
{
int a[5] = {10, 20, 30, 40, 50};
int *p;
p = a; /*przypisanie początku tablicy - DLA WSKAŹNIKÓW
DO TABLIC NIE UŻYWAMY AMPERSANDA!!!*/
/*zwykłe indeksowanie elementów tablicy*/
printf(„%d %d %d %d %d”, a[0], a[1], a[2], a[3], a[4]);
/*dostęp do elementów tablicy poprzez wskaźnik*/
printf(„%d %d %d %d %d”, *p, *(p+1), *(p+2), *(p+3),
*(p+4));
return 0;
}
tutaj działa
arytmetyka
wskaźników
17
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a typy tablicowe
A zatem, kiedy do wskaźnika p podstawiamy wskazanie na
tablicę tab nie używamy znaku & (ampersand). Wynika to
z tego, że zmienna tablicowa jest niejawnie realizowana
przez środowisko języka C jako wskaźnik do początku
tablicy. Wtedy stosujemy podstawienie:
p=tab;
Stosowanie arytmetyki wskaźników przy tablicach jest
możliwe, ale niezbyt wygodne. Lepiej jest wykorzystywać
zwykłe indeksowanie tablic - efekt jest ten sam w obu
przypadkach
Należy zwrócić uwagę na różnicę pomiędzy poniższymi
wyrażeniami:
*p++;
/*zwiększa wskazanie p do następnego elementu*/
*(p+1)
/*daje wskazanie do następnego bez zwiększania p*/
18
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a napisy
Z poprzedniego wykładu wiemy, że napis jest tablicą znaków.
Nie ma więc wielkich nowości przy wykorzystywaniu
wskaźników z tablicami znaków.
Przykład: wypisanie napisu przy pomocy pętli for :
char nap[ ] = „Łańcuch znaków”;
char *nap_wsk;
int i;
/*wypisuj aż do znaku null w łańcuchu*/
for(i=0;nap[i];i++) {
printf(„%c”, nap[i]);
}
/*??? jak to zrobić wykorzystując nap_wsk ???*/
Jaki to rodzaj
pętli - skonfrontuj
z treścią wykładu 1
19
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a napisy
Wskaźniki ze stałymi napisowymi:
char *p=„Stały napis wskazywany przez p”;
printf(p);
Czy pamiętasz, że do wczytywania napisów służy
gets(
)
? Jak wykorzystywać to polecenie?
Przestudiuj polecenia z biblioteki
<ctype.h>
.
Szczególnie:
toupper( )
i
tolower( )
.
20
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźniki a napisy
Postaraj się zrealizować implementację rozwiązań dla
czterech poniższych zadań, wykorzystując wskaźniki do
napisów:
Wczytaj z klawiatury napis o niezdefiniowanej
długości, wczytywanego z klawiatury i wypisz go na
ekranie w kolejności od końca do początku
wczytanego napisu
Wczytaj z klawiatury napis o niezdefiniowanej
długości i wypisz na ekranie zamieniając wszystkie
jego znaki na duże litery
Wczytaj z klawiatury dwa napisy o daj odpowiedź,
czy są one identyczne
Skopiuj napis1 do zmiennej napis2 przechodząc po
pojedynczych znakach i nie zapominając o dodaniu
na koniec napisu wynikowego znaku null, czyli: ‘\0’.
21
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Tablice wskaźników
Możemy w razie potrzeby wykorzystywać tablice wskaźników do
zmiennych tego samego typu, np.:
int *tab_wsk[20]; /*tablica 20-stu wskaźników do int*/
Ustawianie wskazań do różnych zmiennych całkowitoliczbowych:
tab_wsk[2]=&zmienna_int1;
tab_wsk[5]=&inna_zmienna;
Ustawianie wskazań do różnych wartości całkowitoliczbowych:
*tab_wsk[1]=100;
*tab_wsk[3]=300;
Zrealizuj program wypisujący w pętli wartości z tablicy wskaźników
do liczb całkowitych wskazującej na różne zmienne i wartości.
22
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźnikowe parametry funkcji
Zmienne wskaźnikowe mogą być parametrami funkcji i
procedur
Wszystkie funkcje operujące na napisach korzystają właśnie
ze wskaźników do napisów - dlaczego tak jest?
Na wykładzie o tablicach znaków przedstawiono
wykorzystanie funkcji scanf( ) z biblioteki <stdio.h>.
Wczytanie na przykład jakiejś liczby całkowitej liczba
wygląda następująco:
scanf(„%d”, &liczba); /*dlaczego znak & (ampersand)?
*/
Użycie polecenia gets( ):
char *p;
gets(p); /*dlaczego bez znaku & (ampersand)? */
23
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźnikowe parametry funkcji
Przykład: przejście pętlą do końca
łańcucha znaków z
wykorzystaniem arytmetyki
wskaźników:
char *p;
int i;
while(*p) {
/*jakieś czynności w pętli*/
*p++;
}
powtarzanie pętli
do napotkania znaku null
przejście do następnego
znaku
24
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Wskaźnikowe parametry funkcji
Zadanie:
Zaproponuj implementację funkcji wykorzystującej
jako parametr wejściowy wskaźnik do napisu:
char *p
i zwracającej liczbę spacji w napisie wskazywanym
przez ten parametr.
25
Grzegorz Bliźniuk, Podstawy Informatyki, wykład 4
Podsumowanie
Omówiliśmy podstawowe zagadnienia dotyczące
typów wskaźnikowych
Wskaźniki w języku C są inaczej zaimplementowane
niż wskaźniki w innych językach programowania
Wskaźniki są bardzo silnym i bardzo wydajnym
narzędziem dla wprawnego programisty
Są one również bardzo wymagające i „kapryśne” -
należy je stosować z pełną tego świadomością
Na następnym wykładzie poznamy zasady obsługi
plików
Dziękuję za uwagę