&operatoru ilə ünvan almaq və*ilə göstəricinin göstərdiyi qiyməti oxumaq və dəyişmək- Funksiyaya göstərici ötürərək çağıran tərəfin dəyişənlərini dəyişmək
- Göstərici arifmetikasını və
arr[i]ilə*(arr + i)ifadələrinin eyni olduğunu izah etmək NULLvə ilkin qiymət verilməmiş göstəricilərin təhlükəsini tanımaq
Dostuna evinin yerini göstərmək üçün evi götürüb aparmırsan — sadəcə ünvanı deyirsən: «Bakı, Nizami küçəsi, 25». Ünvanı bilən adam evi tapa, içəri girə və hətta orada nəyisə dəyişə bilər. Kompüterin yaddaşı da belədir: hər dəyişən müəyyən ünvanda yaşayır. Ünvanı saxlayan dəyişənə göstərici deyilir. Göstəricilər C-nin ən güclü və eyni zamanda ən çox qorxulan mövzusudur, amma ideyası elə bu ünvan qədər sadədir.
Ünvan və göstərici
Qiyməti başqa dəyişənin yaddaşdakı ünvanı olan dəyişən. int *p; — «p int tipli qiymətin ünvanını saxlayır» deməkdir.
| Yazılış | Mənası |
|---|---|
int *p; | int-ə göstərici elan edir |
&x | x dəyişəninin ünvanı |
p = &x; | p indi x-i göstərir |
*p | p-nin göstərdiyi ünvandakı qiymət (müraciət, ingiliscə dereference) |
NULL | heç nəyi göstərməyən göstərici |
#include <stdio.h>
int main(void) {
int x = 10;
int *p = &x;
printf("x = %d\n", x);
printf("*p = %d\n", *p);
*p = 25;
printf("x = %d\n", x);
printf("Same address? %d\n", p == &x);
return 0;
}x = 10 *p = 10 x = 25 Same address? 1
*p = 25; x-in adını çəkmədən onun qiymətini dəyişdi, çünki p onun ünvanını saxlayır.Ünvanın özünü %p spesifikatoru ilə çap etmək olar. O, adətən 0x7ffd... kimi on altılıq ədəd şəklində görünür və proqram hər dəfə işə salınanda fərqli ola bilər:
int x = 10;
int *p = &x;
printf("Address of x: %p\n", (void *) &x);
printf("Value of p: %p\n", (void *) p);Funksiyaya göstərici ötürmək: swap
Xatırla: C-də funksiya arqumentlərin surətini alır, ona görə adi parametrlə iki dəyişənin qiymətini dəyişdirmək mümkün deyil. Həll yolu — funksiyaya dəyişənlərin ünvanlarını vermək. Funksiya ünvan vasitəsilə orijinal dəyişənlərə çatır. scanf("%d", &age) məhz buna görə & tələb edir.
#include <stdio.h>
void swap(int *a, int *b) {
int temp = *a;
*a = *b;
*b = temp;
}
int main(void) {
int x = 3, y = 8;
printf("Before: x = %d, y = %d\n", x, y);
swap(&x, &y);
printf("After: x = %d, y = %d\n", x, y);
return 0;
}Before: x = 3, y = 8 After: x = 8, y = 3
Göstəricilər funksiyaya bir neçə nəticə «qaytarmağa» da imkan verir: return yalnız bir qiymət qaytarır, amma funksiya nəticələri ona verilmiş ünvanlara yaza bilər. Aşağıdakı funksiya Bakıda bir həftənin temperaturları arasında ən kiçik və ən böyük qiyməti tapır:
#include <stdio.h>
void min_max(const int *arr, int n, int *min, int *max) {
*min = arr[0];
*max = arr[0];
for (int i = 1; i < n; i++) {
if (arr[i] < *min) *min = arr[i];
if (arr[i] > *max) *max = arr[i];
}
}
int main(void) {
int temps[5] = {18, 25, 21, 30, 16};
int low, high;
min_max(temps, 5, &low, &high);
printf("Min: %d, max: %d\n", low, high);
return 0;
}Min: 16, max: 30
Göstərici arifmetikası və massivlər
Massivin adı ifadələrdə onun ilk elementinin ünvanına çevrilir, ona görə int *p = arr; yazmaq olar. Göstəriciyə 1 əlavə edəndə o, 1 bayt yox, bir element irəli gedir: int * üçün adətən 4 bayt. Deməli, *(p + 2) üçüncü elementdir, arr[i] yazılışı isə sadəcə *(arr + i) ifadəsinin qısa formasıdır. Funksiyaya massiv ötürəndə əslində ilk elementin göstəricisi ötürülür — funksiyanın orijinal massivi dəyişə bilməsinin və parametrdə sizeof fəndinin işləməməsinin səbəbi budur.
#include <stdio.h>
int main(void) {
int arr[4] = {10, 20, 30, 40};
int *p = arr;
printf("%d\n", *p);
printf("%d\n", *(p + 2));
p++;
printf("%d\n", *p);
printf("%d\n", arr[3] == *(arr + 3));
int sum = 0;
for (int *q = arr; q < arr + 4; q++) {
sum += *q;
}
printf("Sum: %d\n", sum);
return 0;
}10 30 20 1 Sum: 100
p++ göstəricini növbəti elementə keçirdi. Son dövr massivi indeks əvəzinə göstərici ilə gəzir.Təhlükəli göstəricilər
- İlkin qiyməti verilməmiş göstərici təsadüfi ünvanı saxlayır. Ona yazmaq başqa məlumatı korlaya bilər. Göstəriciyə həmişə ilkin qiymət olaraq ya dəyişənin ünvanını, ya da
NULLver. - **
NULLgöstəricisinə müraciət** (*p,pisəNULL-dur) adətən proqramı dərhal çökdürür. İstifadədən əvvəl yoxla:if (p != NULL). - Asılı qalan göstərici artıq mövcud olmayan dəyişəni göstərir. Məsələn, funksiya öz lokal dəyişəninin ünvanını qaytarsa, funksiya bitəndə o dəyişən yox olur.
int *make_number(void) {
int local = 5;
return &local;
}local funksiya bitəndə yox olur, qaytarılan ünvan isə «boşluğu» göstərir. Nəticə gözlənilməzdir.Əsas fikirlər
- Göstərici ünvan saxlayır:
int *p = &x;—px-in ünvanıdır. &ünvanı verir,*ünvandakı qiyməti oxuyur və ya dəyişir.- Funksiya göstərici alanda çağıran tərəfin dəyişənlərini dəyişə bilər (
swap,scanf). p + 1bir element irəli gedir;arr[i]—*(arr + i)deməkdir.- Göstəriciyə həmişə ilkin qiymət ver,
NULL-u yoxla və lokal dəyişənin ünvanını qaytarma.
Özünü yoxla
10 sual. Hər düzgün cavab XP qazandırır.
int x = 4; int *p = &x; *p = 9; sətirlərindən sonra x neçədir?