Pokazivači su osnovni koncept u jeziku C koji omogućava direktno manipulisanje memorijom. Pokazivači su promenljive koje sadrže adresu u memoriji kao svoju vrednost, umesto konkretne vrednosti. Ovo omogućava dinamičko alociranje memorije, pristupanje podacima na izabranim lokacijama u memoriji i efikasno rukovanje kompleksnim podacima.
Format ispisa pokazivača je %p
.
Type *variable1; // u opstem slucaju
int *variable2; // pokazivac na int
int* a, b; // <=> int *a, b;
int a = 10;
int *pointer = &a;
Operator adrese u jeziku C označava adresu u memoriji promenljive ili funkcije. Simbol ovog operatora je &.
Na primer, ako imamo promenljivu x, &x će vratiti adresu u memoriji gde je smeštena vrednost promenljive x. Adresa je obično izražena u heksadecimalnom formatu.
VAŽNO!!! Operator adrese je unarni operator. Iako se koristi isti simbol, kao za bitovsko AND, jezik C zna da razlikuje ova dva operatora jer je jedan binarni a drugi unarni. Praksa je da se ovaj operator ne razdvaja od imena promenljive. Ovaj operator ima veći prioritet od aritmetičkih operatora. Ovde možete pogledati prioritete operatora.
int a = 10;
int *pointer = &a;
*pointer = 20;
printf("%d\n", a); // ispisace 20
VAŽNO!!! Operator dereferenciranja je unarni operator. Iako se koristi isti simbol, kao za množenje, jezik C zna da razlikuje ova dva operatora jer je jedan binarni a drugi unarni. Praksa je da se ovaj operator ne razdvaja od imena promenljive. Ovaj operator ima veći prioritet od aritmetičkih operatora. Ovde možete pogledati prioritete operatora.
Operator dereferenciranja se na neki način može smatrati inverznom funkcijom operatora adrese. Primenom operatora dereferenciranja se pristupa memorijskoj lokacija na koju “pokazuje” adresa koja se čuva u promenljivom pokazivača (u ovom slučaju, promenljivoj pointer) i na taj način je moguće izmeniti ili uzeti vrednost sa te adrese. Ovo je korisno ukoliko želimo da dinamički alociramo memoriju (biće reči o tome na nekim od sledećih vežbi) ili pristupamo i menjamo vrednosti promenljivih jedne funkcije u nekoj drugoj funkciji.
Pogrešno:
#include <stdio.h>
void swap_wrong(int x, int y) { // nove lokalne promenljive koje su vidljive samo u ovoj funkciji
int tmp;
printf("Adresa x u swap_wrong: %p\n", &x); // adrese ce biti razlicite u odnosu na promenljive iz main funkcije
printf("Adresa y u swap_wrong: %p\n", &y);
tmp = x;
x = y;
y = tmp;
}
int main() {
int x = 10, y = 20;
printf("Adresa x u main: %p\n", &x);
printf("Adresa y u main: %p\n", &y);
swap_wrong(x, y); // prosedjuju se vrednosti promenljivih
printf("x = %d, y = %d\n", x, y);
}
Ispravno:
void swap(int *px, int *py) { // posto su prosledjene adrese, lako mozemo pristupiti i izmeniti vrednosti koje se nalaze na ovim adresama
int tmp;
printf("Adresa x u swap_wrong: %p\n", px); // adrese ce biti iste kao u main funkciji
printf("Adresa y u swap_wrong: %p\n", py);
tmp = *px;
*px = *py;
*py = tmp;
}
int main() {
int x = 10, y = 20;
printf("Adresa x u main: %p\n", &x);
printf("Adresa y u main: %p\n", &y);
swap(&x, &y); // prosedjuju se adrese promenljivih
printf("x = %d, y = %d\n", x, y);
}
Napisati funkciju koja istovremeno vraća dve vrednosti - količnik i ostatak dva data broja.
#include <stdio.h>
void div_and_mod(int x, int y, int* div, int* mod) {
printf("Kolicnik postavljam na adresu: %p\n", div);
printf("Ostatak postavljam na adresu : %p\n", mod);
*div = x / y;
*mod = x % y;
}
int main() {
int div, mod;
printf("Adresa promenljive div je %p\n", &div);
printf("Adresa promenljive mod je %p\n", &mod);
div_and_mod(5, 2, &div, &mod);
printf("Vrednost promenljive div je %d\n", div);
printf("Vrednost promenljive mod je %d\n", mod);
}
#include <stdio.h>
int main() {
char s[] = "abcde";
int t[] = {1, 2, 3, 4, 5};
char* ps = &s[0]; // isto je kao da stavimo char *ps = s;
int* pt = &t[0]; // <=> int *pt = t;
printf("ps = %p\n", ps);
printf("ps+1 = %p\n", ps+1); // povecava i smanjuje za velicinu tipa a ne za 1
// u ovom slucaju ce biti za 1 jer jedan char zauzima 1 byte u memoriji
printf("ps+2 = %p\n", ps+2);
printf("ps-1 = %p\n", ps-1);
printf("ps-2 = %p\n", ps-2);
printf("pt = %p\n", pt);
printf("pt+1 = %p\n", pt+1); // povecava i smanjuje za velicinu tipa a ne za 1
// povecace za 4 jer je jedan int velicine 4 byte
// isto vazi i za oduzimanje
printf("pt+2 = %p\n", pt+2);
printf("pt-1 = %p\n", pt-1);
printf("pt-2 = %p\n", pt-2);
ps = &s[3];
printf("s = %p\n", s);
printf("ps = %p\n", ps);
printf("ps - s = %d\n", ps - s); // 3
pt = &t[3];
printf("t = %p\n", t);
printf("pt = %p\n", pt);
printf("pt - t = %d\n", pt - t); // 3
return 0;
}
#include <stdio.h>
int main() {
char s[] = "abcde";
char* ps = &s[0]; // isto je kao da stavimo char *ps = s;
// 1. nacin prolaska kroz niz
for (int i = 0; i < 5; i++) {
putchar(s[i]); // standardno koriscenje niza
}
putchar('\n');
// 2. nacin prolaska kroz niz
for (int i = 0; i < 5; i++) {
putchar(ps[i]); // koriscenje pokazivaca kao niz
}
putchar('\n');
// 3. nacin prolaska kroz niz
for (int i = 0; i < 5; i++) {
putchar(*(ps + i)); // primena pointerske aritmetike
}
putchar('\n');
// 4. nacin prolaska kroz niz
// primena pointerske aritmetike
for (char *pps = ps; *pps; pps++) { // '\0' je false
putchar(*pps);
}
putchar('\n');
printf("s == ps je %s\n", (s == ps) ? "true" : "false" );
printf("Adresa pocetka niza i adresa prvog elementa su iste jer je s == &s[0] zapravo %s", (s == &s[0]) ? "true" : "false" );
printf("sizeof(s) = %ld\n", sizeof(s)); // duzina niza * sizeof(tip niza)
printf("sizeof(ps) = %ld\n", sizeof(ps)); // najcesce 8 bajtova
// NAPOMENA: ukoliko se funkcijama prosledjuje niz, zapravo se ne prosledjuje ceo niz nego pokazivac na niz
// zbog toga su promene nad nizom koje su izvrsene u nekoj funkciji, vidljive i van nje
return 0;
}