Programowanie w C
Wykład 2
• Wskaźniki – cd
Tematyka
Wskaźniki w argumentach funkcji
void fun(float f) {
f /= 3.3;
}
float fun(float
*f
) {
*f
/= 3.3;
}
void main() {
float fvar = 13.3;
fun(fvar);
printf(”%d”,fvar);
// 13.3
fun(
&fvar
);
printf(”%d”,fvar);
// 4.03
}
Przesyłanie argumentów
przez wskaźnik.
Zmiana wewnątrz funkcji
wartości przesyłanego
argumentu.
Przesyłanie
argumentów przez
wartość.
Funkcja nie zmienia
wartości przesyłanego
argumentu.
void f1(int *pi, int rozm);
void f2(int *pi, int rozm);
void f3(int t[], int rozm);
void main(){
int tab[5]={1,2,3,4,5};
f1(tab,5);
f2(tab,5);
f3(tab,5);
}
void f1(
int *pi
, int rozm){
printf("\nfunkcja f1\t");
for(int i=0;i<rozm;i++)
printf("%d\t",
*(pi++)
);
}
void f2(
int *pi
, int rozm){
printf("\nfunkcja f2\t");
for(int i=0;i<rozm;i++)
printf("%d\t",
pi[i]
);
}
void f3(
int t[]
, int rozm){
printf("\nfunkcja f3\t");
for(int i=0;i<rozm;i++)
printf("%d\t",
t[i]
);
}
Przesyłanie tablic
do funkcji
Funkcje są wywoływane przez podanie
nazwy tablicy
Przesłany adres tablicy odebrany
jako tablica
Przesłany adres tablicy inicjalizuje
lokalny wskaźnik
pi
. Wewnątrz funkcji
- zapis wskaźnikowy
Przesłany adres tablicy inicjalizuje
lokalny wskaźnik
pi
. Wewnątrz funkcji
- zapis tablicowy
Przesyłanie tablic do funkcji – cd
• Odebranie tablicy jako tablicy – czytelność funkcji
• Odebranie tablicy jako adresu inicjującego wskaźnik – funkcja działa szybciej
• Odebranie tablicy jako adresu – łatwiejsze przekazywanie tablic
wielowymiarowych (rozmiary tablicy nie muszą być znane w momencie
wywołania funkcji)
Wskaźniki do stałych
Wskaźniki do stałych mogą zawierać adresy dowolnych
zmiennych i mogą być modyfikowane w programie, ale nie
można za ich pomocą modyfikować zmiennych wskazywanych.
const int stala = 10;
// definicja stałej typu int
const int *wsk_st;
// wskaźnik do stałej typu int
void main() {
int i = 5;
const int *w = &i;
// wskaźnik zainicjowany
wsk_st = &i;
// inicjacja adresem zmiennej automatycznej i
printf(”%d\n”, *wsk_st);
// 5
printf(”%d\n”, *w);
// 5
// *w = *w + 5;
// błąd kompilatora !
// *wsk_st+= 7;
// nie można modyfikować stałej
wsk_st = &stala;
// wskaźnik inicjowany adresem stałej
w = &stala;
// wskaźnik inicjowany adresem stałej
printf(”%d\n”, *wsk_st); // 10
printf(”%d\n”, *w);
// 10
}
Stałe wskaźniki
Stały wskaźnik to wskaźnik, który zawsze pokazuje na to samo.
Wskaźnik tego typu musi być zainicjowany w miejscu definicji -
tak jak każda stała.
W programie nie można już modyfikować jego wartości.
Za pomocą wskaźnika stałego można jednak modyfikować
zawartość zmiennej wskazywanej, ale tylko tej, której adresem
wskaźnik został zainicjowany.
const int st = 4;
// stała
int zm = 10;
// definicja zmiennej
int * const w = &zm;
// stały wskaźnik do zmiennej zm
// int * const x = &st;
// błąd – wskaźnik musi wskazywać na stałą
const int * const x = &st; // dobrze - stały wskaźnik do stałej
int i = 7;
int * const wi = &i;
// stały wskaźnik do zmiennej lokalnej i
int * const pz = &zm;
// stały wskaźnik do zmiennej zm
printf(”%d\n”, *wi);
// i=7 = i
printf(”%d %d\n”, *pz, *w);// 10 i 10; zm=10
*wi +=8;
// i = 7 + 8 = 15
printf(”%d\n”, i);
// i =15
// wi = &zm;
// błąd – nie wolno zmieniać stałej wi
*pz += 2;
// zm = 10 + 2
printf(”%d\n”, zm);
// zm = 12
Wskaźniki do funkcji
typ_zwracany
(*wsk_do_funkcji)
([argumenty_funkcji]);
void f1();
void f2();
void blad();
void main(){
void (*pf)()
=blad;
int i;
scanf("%d", &i);
if(i==1) pf=f1;
else if(i==2) pf=f2;
(*pf)()
;
}
void f1(){
printf("funkcja f1\n");
}
void f2(){
printf("funkcja f2\n");
}
void blad(){
printf("blad\n");
}
Wskaźniki do funkcji – cd
Nazwa funkcji jest adresem jej początku (adresem miejsca w pamięci, gdzie
zaczyna się kod tej funkcji).
Zastosowanie wskaźników do funkcji:
• Przesyłanie argumentów do funkcji. Adres funkcji można wysłać jako
argument.
• Tworzenie tablic ze wskaźników do funkcji.
void f1();
void f2();
void blad();
void funkcja(int i, void (*pf)())
;
void main(){
void (*pf)()=NULL;
int i;
scanf("%d", &i);
funkcja(i,pf)
;
}
void funkcja(int i, void (*pf)()){
pf=blad;
if(i==1) pf=f1;
else if(i==2) pf=f2;
(*pf)();
}
void f1(){
printf("funkcja f1\n");
}
void f2(){
printf("funkcja f2\n");
}
void blad(){
printf("blad\n");
}
Przesyłanie argumentów do funkcji
Tablice wskaźników
typ_wskazywany
*
tablica
[rozmiar]
;
//typ_wskazywany
*(
tablica
[rozmiar])
; zapis równoważny
double *tablica[10];
Jak przydzielić pamięć dla tablicy dwuwymiarowej?
void f1();
void f2();
void blad();
void main(){
void (*pt[3])()={f1,f2,blad};
for(int i=0;i<3;i++)
(*pt[i])();
}
void f1(){
printf("funkcja f1\n");
}
void f2(){
printf("funkcja f2\n");
}
void blad(){
printf("blad\n");
}
Tablica wskaźników do funkcji
Tablice wskaźników - cd
Funkcje malloc, calloc, free
W języku C/C++ istnieją standardowe funkcje umożliwiające
dynamiczną alokację pamięci (malloc i calloc) oraz funkcja
zwalniająca przydzieloną pamięć (free). Prototypy funkcji:
void *malloc(size_t K);
// alokacja K bajtów
void *calloc(size_t N, size_t K);
// alokacja N razy po K
bajtów
void free(void *x);
// zwolnienie obszaru
• Funkcje malloc i calloc przydzielają spójne obszary pamięci,
których rozmiary nie przekraczają 64 KB (size_t jest
zdefiniowany jako unsigned) i zwracają wskazanie do
przydzielonego obszaru.
• Jeżeli alokacja nie jest możliwa, to zwracany jest wskaźnik
NULL. Funkcja calloc dodatkowo zeruje przydzieloną pamięć.
Funkcja free zwraca do systemu przydzieloną pamięć.
• Funkcje malloc i calloc zwracają wskaźniki do typu void
dlatego niezbędne są konwersje typu przy podstawieniach do
wskaźników innych typów.
• Należy uważać, aby za pomocą funkcji free nie zwalniać
pamięci, która nie została przydzielona.
Dynamiczna alokacja pamięci
void main()
{
int i;
char* ps = NULL; //wskaźnik do char
ps = (char*) malloc(5 * sizeof(char)); //alokacja pamięci na
//elementów typu char
if (ps)
{
strcpy(ps, "Ola");
for (i = 0; i < strlen(ps); i++)
printf("%c\n", *(ps + i)); //wypisanie i-tego
//elementu tablicy
free(ps);
//zwolnienie pamięci
ps = NULL;
}
}
Przykład:
Funkcje malloc, calloc, free
Dynamiczna alokacja pamięci - cd