C Xotira Manzili va Ko’rsatkichlar

Ko’rsatkich - xotira uyasining unikal (xotira) manzilini saqlaydigan o’zgaruvchi. Ko’rsatkich operativ xotiradagi biron-bir o’zgaruvchi mavjud bo’lishi mumkin bo’lgan biron-bir joyni belgilaydi. Ko’rsatkichlarning qiymatlarini o’zgartirishni shunday turli variantlarda qo’llash mumkinki, bu dasturning moslashuvchanligini oshiradi. Ko’rsatkich odatda turga ega bo’lib quyidagicha e’lon qilinadi:

	<turning nomi>*<ko’rsatkichning nomi> = <dastlabki qiymat>

Misol uchun:

int *pr; 
char *alfa;

Bu holda ko’rsatkichlar noaniq qiymatga ega bo’ladi. Ko’rsatkichlar ta’riflanganda ularning turlari ko’rsatilishi shart. Ko’rsatkichlarni inisializasiya qilish, ya’ni boshlang’ich qiymatlarini kiritish mumkin. Ma’lum turdagi biron-bir o’zgaruvchi manzili yoki NULL qiymat dastlabki qiymat bo’lishi mumkin. Ko’rsatkichlarga boshlang’ich maxsus NULL qiymati berilsa, bunday ko’rsatkich bo’sh ko’rsatkich deb ataladi. Biron-bir o’zgaruvchi manzilini olish hamda uni ko’rsatkichga qiymat sifatida berish uchun «&» operatori qo’llanadi.

Misol:

int I = 100; int*p = &I;
unsigned longint *ul = NULL;

Misol:

#include <stdio.h>
int main()
{
      int i = 123;
      int *p = &i;
      printf("\n i = %d p = %p", i, p);
      int j = 456; p = &j;
      printf("\n j = %d p = %p", j, p);
      return 0;
}

Natija:

i = 123 
p = 0012FF60 
j = 456 
p = 0012FF48

Teskari operator - «*» bo’lib, ko’rsatkichda saqlanayotgan manzil bo’yicha uya qiymatiga murojaat qilish imkonini beradi.

Misol:

int I = 100; 
int*p = &I int J = *p;

Misol:

#include <stdio.h>
int main()
{
    int i = 123;
    int *si = &i;
    printf("\n i = %d *si = %d",i,*si);
    i = 456;
    printf("\n i = %d *si = %d",i,*si); 
    *si = 0;
    printf("\n i = %d *si = %d",i,*si);
    return 0;
}

Natija:

i = 123 *si = 123 
i = 456 *si = 456 
i = 0 *si = 0

Ko’rsatkichlar xossalari

Ko’rsatkichlar ustida o’tkaziladigan operasiyalar. Ko’rsatkichlar ustida unar operasiyalar bajarish mumkin: inkrement (++) va dekrement (--) operasiyalarini bajarishda, ko’rsatkich qiymati ko’rsatkich murojaat qilgan tur uzunligiga ko’payadi yoki kamayadi.

Misol:

int*ptr, a[10];
ptr = &a[5];
ptr++; / *= a[6]*/ elementining manziliga
ptr--; /* = a[5]*/ elementining manziliga

Qo’shish va ayirish binar operasiyalarida ko’rsatkich va int turining qiymati ishtirok etishi mumkin. Bu operasiya natijasida ko’rsatkich qiymati dastlabkisidan ko’rsatilgan elementlar soniga ko’proq yoki kamroq bo’ladi.

Misol:

int*ptr1, *ptr2, a[10];
int i = 2;
ptr1 = a+(i+4); /* = a[6]*/ elementining manziliga
ptr2 = ptr1-i; /* = a[4]*/ elementining manziliga

Ayirish operasiyasida bitta turga mansub bo’lgan ikkita ko’rsatkich ishtirok etishi mumkin. Operasiya natijasi int turiga ega hamda kamayuvchi va ayiruvchi o’rtasidagi dastlabki tur elementlarining soniga teng, bundan tashqari agar birinchi manzil kichikroq bo’lsa, u holda natija manfiy qiymatga ega bo’ladi.

Misol:

int *ptr1, *ptr2, a[10];
int i;
ptr1 = a + 4;
ptr2 = a + 9;
i = ptr1 - ptr2; /* = 5 */
i = ptr1 -ptr2; /* = -5 */

Bir turga taalluqli bo’lgan ikkita ko’rsatkich qiymatlarini = = , ! = , <, < = , >, > = amallari yordamida o’zaro qiyoslash mumkin. Bunda ko’rsatkichlarning qiymatlari shunchaki butun sonlar sifatida olib qaraladi, qiyoslash natijasi esa 0 (yolg’on) yoki 1 (rost) ga teng bo’ladi.

Misol:

int *ptr1, *ptr2, a[10];
ptr1 = a + 5; 
ptr2 = a + 7;
if(ptr1 > ptr2) a[3] = 4;

Bu misolda ptr1 ning qiymati ptr2 ning qiymatidan kamroq, shuning uchun a[3] =4 operatori bajarilmay qoladi.

Konstanta ko’rsatkich va konstantaga ko’rsatkichlar. Konstanta ko’rsatkich quyidagicha ta’riflanadi:

    <tur>* const<ko’rsatkich nomi> = <konstanta ifoda>

Misol uchun:

 char* const key_byte = (char*)0x0417.

Bu misolda konstanta ko’rsatkich klaviatura holatini ko’rsatuvchi bayt bilan bog’langandir. Konstanta ko’rsatkich qiymatini o’zgartirish mumkin emas, lekin * amali yordamida xotiradagi ma’lumot qiymatini o’zgartirish mumkin.

Misol uchun:

*key_byte = ’Yo’ 

amali 1047(0x0417) manzil qiymati bilan birga klaviatura holatini ham o’zgartiradi.

Konstantaga ko’rsatkich quyidagicha ta’riflanadi:

	<tur>const*<ko’rsatkich nomi> = <konstanta ifoda>.

Misol uchun:

const int zero = 0; 
int const* p = &zero;

Bu ko’rsatkichga * amalini qo’llash mumkin emas, lekin ko’rsatkichning qiymatini o’zgartirish mumkin. Qiymati o’zgarmaydigan konstantaga ko’rsatkichlar quyidagicha kiritiladi:

	<tur>const* const<ko’rsatkich nomi> = <konstanta ifoda>.

Misol uchun:

const float pi = 3.141593; 
float const* const pp = π

Turlashtirilmagan ko’rsatkich. Turlashtirilmagan (tipiklashtirilmagan) ko’rsatkich void turga ega bo’lib, ixtiyoriy turdagi o’zgaruvchi manzili qiymat sifatida berilishi mumkin. Maxsus void turidagi ko’rsatkichlar ajdodiy ko’rsatkichlar deb atalib har xil turdagi ob’ektlar bilan bog’lanish uchun ishlatiladi.

Misol uchun:

int i = 77;
float euler = 2.18282;
void *vp;
vp = &I;
printf(“%d”, (*(int*)vp);
vp = &euler;
printf(“%f”, (*(float*)vp);

Quyidagi operatorlar ketma-ketligi xatolikka olib keladi:

void *vp;
int *ip;
ip = vp;

Bu xatolik sababi bitta ob’ektga har xil turdagi ko’rsatkichlar bilan murojaat qilish mumkin emas.

Ko’rsatkichlar funksiya parametri sifatida. Ko’rsatkichlar yordamida parametr qiymatini o’zgartirish mumkin. Misol uchun to’rtburchak yuzi va perimetrini berilgan tomonlari bo’yicha hisoblash funksiyasini quyidagicha tasvirlash mumkin.

void pr(float a, float b, float* s, float* p)
{
    *p = 2(a + b);
    *s = a * b;
}

Bu funksiyaga quyidagicha murojaat qilinishi mumkin pr(a, b, &p, &s). Funksiyaga p va s o’zgaruvchilarning manzillari uzatiladi. Funksiya tanasida shu manzillar bo’yicha 2 * (a + b) va a * b qiymatlar yoziladi. Keyingi misolda berilgan ikki o’zgaruvchining qiymatlarini o’zaro almashtirish funksiyasidan foydalaniladi:

#include <stdio.h>
void change(int*a, int*b)//manzil bo'yicha uzatish
{
      int r = *a;
      *a = *b;
      *b = r;
}

int main()
{
      int x = 1,y = 5;
      change(&x, &y);
      printf("x = %d y = %d", x, y);
      return 0;
}

Natija:

x = 5 y = 1

Agar funksiya ichida parametrning o’zgarishini taqiqlash lozim bo’lib qolsa, bu holda const modifikatori qo’llanadi. Bu modifikatorni funksiyada o’zgarishi ko’zda tutilmagan barcha parametrlar oldidan qo’yish tavsiya qilinadi (undagi qaysi parametrlar o’zgaradiyu, qaysilari o’zgarmasligi sarlavhadan ko’rinib turadi).

Ko’rsatkichlar va massivlar

Ko’rsatkich va massiv nomi. Massivlar nomi dasturda konstanta ko’rsatkichdir. Shuning uchun ham int z[4] massiv elementiga *(z+4) shaklda murojaat qilish mumkin. Massivlar bilan ishlanganda qavslarsiz ishlash mumkin. Quyidagi misolda har bir harf alohida bosib chiqariladi:

#include <stdio.h>
int main()
{
      char x[] = "DIXI";
      int i = 0;
      while (*(x+i)! = '\0') 
      printf("\n %c",*(x+i++)); 
      return 0;
}

Kompilyator x[i] qiymatni hisoblaganda (x+i)*sizeof(<>) formula bo’yicha manzilni hisoblab shu manzildagi qiymatni oladi. Agar massiv <tur> x[n][k][m] shaklda ta’riflangan bo’lsa, x[i][j][l] qiymatni hisoblaganda (x+k*j+l)*sizeof(<>) formula bo’yicha manzilni hisoblab shu manzildagi qiymatni oladi.