4-bo‘lim

O'zgaruvchilar va ma'lumot turlari

int, float, double, char turlari, ularning xotiradagi hajmi va chegaralari, doimiylar, turlarni o'zgartirish va toshib ketish xavfi.

🕑 16 daqiqa o‘qish 📄 782 so‘z 👁 3 marta ko‘rilgan
Ushbu bo‘lim mundarijasi
  1. O'zgaruvchi e'lon qilish
  2. Asosiy ma'lumot turlari
  3. sizeof - hajmni bilish
  4. signed va unsigned
  5. Toshib ketish (overflow)
  6. Haqiqiy sonlar va aniqlik
  7. char - belgi yoki kichik son
  8. Doimiylar
  9. Turlarni o'zgartirish
  10. Turlar jadvali - qisqacha
  11. Xulosa

C - qat'iy turlangan til. Har bir o'zgaruvchi yaratilishidan oldin uning turi e'lon qilinishi shart.

O'zgaruvchi e'lon qilish #

C
int yosh;              /* e'lon qilish */
yosh = 25;             /* qiymat berish */

int talaba_soni = 30;  /* ikkalasi birga */

int a = 1, b = 2, c = 3;   /* bir qatorda bir nechtasi */
Qiymat berilmagan o'zgaruvchi
C
int yosh;
printf("%d\n", yosh);   /* XAVFLI: qiymat noma'lum */

Python'da bu xatolik beradi. C da esa o'zgaruvchi xotiradagi eski axlatni oladi - u har safar boshqacha bo'lishi mumkin.

Qoida: o'zgaruvchini yaratganda darhol qiymat bering.

C
int yosh = 0;   /* xavfsiz */

Asosiy ma'lumot turlari #

Turlar xotirada qancha joy egallaydi (64-bitli tizim) char 1 bayt - bitta belgi yoki -128..127 short 2 bayt - -32 768..32 767 int 4 bayt - taxminan ±2 milliard long long 8 bayt - taxminan ±9 kvintillion float 4 bayt - ~7 raqam aniqlik double 8 bayt - ~15 raqam aniqlik Har bir katakcha - bir bayt (8 bit)
Kattaroq tur - kengroq oraliq, lekin ko'proq xotira
C
#include <stdio.h>

int main(void) {
    char harf = 'A';
    int yosh = 25;
    long long aholi = 37000000LL;
    float ortacha = 4.6f;
    double aniq_qiymat = 3.14159265358979;

    printf("char      : %c\n", harf);
    printf("int       : %d\n", yosh);
    printf("long long : %lld\n", aholi);
    printf("float     : %.2f\n", ortacha);
    printf("double    : %.10f\n", aniq_qiymat);

    return 0;
}
Natija
char      : A
int       : 25
long long : 37000000
float     : 4.60
double    : 3.1415926536

sizeof - hajmni bilish #

C
#include <stdio.h>

int main(void) {
    printf("char      : %zu bayt\n", sizeof(char));
    printf("short     : %zu bayt\n", sizeof(short));
    printf("int       : %zu bayt\n", sizeof(int));
    printf("long      : %zu bayt\n", sizeof(long));
    printf("long long : %zu bayt\n", sizeof(long long));
    printf("float     : %zu bayt\n", sizeof(float));
    printf("double    : %zu bayt\n", sizeof(double));

    return 0;
}
Natija
char      : 1 bayt
short     : 2 bayt
int       : 4 bayt
long      : 8 bayt
long long : 8 bayt
float     : 4 bayt
double    : 8 bayt
Hajmlar kafolatlanmagan

Yuqoridagi natija 64-bitli Linux uchun. Windows'da long 4 bayt bo'ladi, mikrokontrollerda int 2 bayt bo'lishi mumkin.

Standart faqat minimal chegaralarni kafolatlaydi: charshortintlonglong long.

Shuning uchun aniq hajm kerak bo'lsa, <stdint.h> dagi turlarni ishlating: int8_t, int16_t, int32_t, int64_t - nomidagi raqam bitlar sonini bildiradi va har qanday platformada bir xil.

signed va unsigned #

unsigned manfiy sonlarni tashlab, musbat oraliqni ikki barobar kengaytiradi.

C
#include <stdio.h>
#include <limits.h>

int main(void) {
    printf("int          : %d ... %d\n", INT_MIN, INT_MAX);
    printf("unsigned int : 0 ... %u\n", UINT_MAX);
    printf("char         : %d ... %d\n", CHAR_MIN, CHAR_MAX);

    return 0;
}
Natija
int          : -2147483648 ... 2147483647
unsigned int : 0 ... 4294967295
char         : -128 ... 127
unsigned bilan ehtiyot bo'ling
C
unsigned int son = 0;
son = son - 1;      /* nol emas! */

unsigned manfiy bo'la olmaydi, shuning uchun natija eng katta qiymatga «aylanib ketadi»: 4294967295.

Bu ayniqsa sikllarda xavfli:

C
for (unsigned int i = 10; i >= 0; i--) {   /* CHEKSIZ SIKL! */
    printf("%u\n", i);
}

i >= 0 sharti unsigned uchun har doim rost - sikl hech qachon tugamaydi.

Toshib ketish (overflow) #

C
#include <stdio.h>
#include <limits.h>

int main(void) {
    int katta = INT_MAX;

    printf("Eng katta int : %d\n", katta);
    printf("Unga 1 qo'shsak: %d\n", katta + 1);

    return 0;
}
Natija
Eng katta int : 2147483647
Unga 1 qo'shsak: -2147483648
Bu aslida aniqlanmagan xatti-harakat

Yuqoridagi natija ko'p kompilyatorlarda shunday chiqadi, lekin standart bo'yicha int toshib ketishi - aniqlanmagan xatti-harakat (undefined behaviour). Kompilyator xohlagan ishni qilishi mumkin.

Katta sonlar bilan ishlaganda long long ishlating yoki chegarani oldindan tekshiring:

C
if (a > INT_MAX - b) {
    printf("Toshib ketadi!\n");
}

Haqiqiy sonlar va aniqlik #

C
#include <stdio.h>

int main(void) {
    float f = 0.1f;
    double d = 0.1;

    printf("float  0.1 = %.20f\n", f);
    printf("double 0.1 = %.20f\n", d);

    printf("0.1 + 0.2 == 0.3 ? %s\n", (0.1 + 0.2 == 0.3) ? "ha" : "yo'q");

    return 0;
}
Natija
float  0.1 = 0.10000000149011611938
double 0.1 = 0.10000000000000000555
0.1 + 0.2 == 0.3 ? yo'q
Haqiqiy sonlarni == bilan solishtirmang

0.1 ni ikkilik sanoq sistemasida aniq ifodalab bo'lmaydi - xuddi 1/3 ni o'nlik kasrda aniq yozib bo'lmagani kabi.

To'g'ri usul - farqni tekshirish:

C
#include <math.h>

if (fabs(a - b) < 0.000001) {
    printf("Deyarli teng\n");
}

Pul bilan ishlaganda esa double umuman ishlatmang - summani tiyinda butun son sifatida saqlang.

char - belgi yoki kichik son #

C
#include <stdio.h>

int main(void) {
    char harf = 'A';

    printf("Belgi sifatida : %c\n", harf);
    printf("Son sifatida   : %d\n", harf);
    printf("Keyingi harf   : %c\n", harf + 1);

    return 0;
}
Natija
Belgi sifatida : A
Son sifatida   : 65
Keyingi harf   : B
ASCII jadvali

char aslida kichik butun son. 'A' - bu 65 raqami uchun qulay yozuv.

BelgiKod
'0'48
'9'57
'A'65
'Z'90
'a'97
'z'122

Shu sababli quyidagi hiyla ishlaydi:

C
char raqam_belgisi = '7';
int raqam = raqam_belgisi - '0';   /* 55 - 48 = 7 */

Doimiylar #

Uch xil usul bor:

C
#define PI 3.14159            /* preprotsessor - turi yo'q */

const double TEZLIK = 299792458.0;   /* haqiqiy o'zgarmas o'zgaruvchi */

enum { MAKS_TALABA = 50 };    /* butun sonli doimiy */
C
#include <stdio.h>

#define PI 3.14159

int main(void) {
    const double AYLANMA_TEZLIK = 1.5;
    double radius = 3.0;

    printf("Aylana yuzasi: %.4f\n", PI * radius * radius);
    printf("Tezlik: %.1f\n", AYLANMA_TEZLIK);

    /* AYLANMA_TEZLIK = 2.0;   XATO: const o'zgartirib bo'lmaydi */

    return 0;
}
Natija
Aylana yuzasi: 28.2743
Tezlik: 1.5
const yoki #define?

const afzalroq, chunki uning turi bor va kompilyator uni tekshiradi. #define esa oddiy matn almashtirish - xatoga yo'l qo'yish osonroq.

Klassik tuzoq:

C
#define KVADRAT(x) x * x

int natija = KVADRAT(2 + 3);   /* 2 + 3 * 2 + 3 = 11, 25 emas! */

17-bo'limda makroslarni to'g'ri yozishni ko'ramiz.

Turlarni o'zgartirish #

C
#include <stdio.h>

int main(void) {
    int jami_ball = 7;
    int talaba_soni = 2;

    printf("Butun bo'lish  : %d\n", jami_ball / talaba_soni);
    printf("To'g'ri o'rtacha: %.2f\n", (double) jami_ball / talaba_soni);

    double narx = 99.87;
    printf("int ga aylantirish: %d\n", (int) narx);

    return 0;
}
Natija
Butun bo'lish  : 3
To'g'ri o'rtacha: 3.50
int ga aylantirish: 99
Butun sonlarni bo'lish qismni tashlab yuboradi

7 / 2 C da 3 ga teng, 3.5 emas. Ikkala operand ham butun son bo'lsa, natija ham butun son bo'ladi va kasr qismi kesib tashlanadi (yaxlitlanmaydi).

Yechim - kamida bittasini haqiqiy songa aylantirish:

C
(double) a / b        /* to'g'ri */
a / (double) b        /* to'g'ri */
(double) (a / b)      /* NOTO'G'RI: avval butun bo'lish bajariladi */

Turlar jadvali - qisqacha #

TurHajmOraliqprintf
char1-128..127%c yoki %d
unsigned char10..255%u
short2±32 ming%hd
int4±2 milliard%d
unsigned int40..4 milliard%u
long long8±9·10¹⁸%lld
float4~7 raqam%f
double8~15 raqam%lf yoki %f
size_t80..%zu
Amaliy topshiriq
  1. Har bir turdan bittadan o'zgaruvchi yaratib, printf bilan chiqaring.
  2. sizeof dasturini o'z kompyuteringizda ishga tushiring - long necha bayt?
  3. INT_MAX ga 1 qo'shib, natijani ko'ring.
  4. unsigned int ga -1 berib, nima chiqishini tekshiring.
  5. 7 / 2 va 7 / 2.0 natijalarini solishtiring.
  6. 'A' dan 'Z' gacha barcha harflarni kodi bilan chiqaring.
  7. '7' - '0' nima uchun 7 berishini tushuntiring.
  8. Doira yuzasini const double PI bilan hisoblang.
  9. 0.1 + 0.2 ni 20 xonagacha chiqaring.
  10. Tug'ilgan yilingizdan yoshingizni hisoblaydigan dastur yozing.

Xulosa #

  • C da har bir o'zgaruvchining turi e'lon qilinishi shart.
  • Qiymat berilmagan o'zgaruvchida axlat bo'ladi - doim boshlang'ich qiymat bering.
  • sizeof turning bayt hajmini beradi; hajmlar platformaga bog'liq.
  • Aniq hajm kerak bo'lsa <stdint.h> dagi int32_t kabi turlarni ishlating.
  • unsigned manfiy bo'la olmaydi - ayirishda «aylanib ketish» xavfi bor.
  • Butun sonlarni bo'lish kasr qismini tashlab yuboradi: 7 / 2 == 3.
  • Haqiqiy sonlarni == bilan solishtirmang - farqni tekshiring.
  • char - bu kichik butun son; 'A' aslida 65.
  • Doimiy uchun #define emas, const afzalroq.

Keyingi bo'limda kiritish va chiqarishni - printf va scanf ni batafsil o'rganamiz.

Xatolik topdingizmi?

Imlo xatosi, ishlamaydigan kod yoki noto‘g‘ri ma‘lumotni ko‘rsangiz - bizga xabar bering. Har bir xabar administrator tomonidan ko‘rib chiqiladi.