← Kursa Dön
📄 Text · 15 min

Temel Veri Tipleri

Programlama bir nevi kutulara eşya yerleştirmeye benzer. Küçük bir yüzük için kocaman bir bavul kullanmazsın, değil mi? C++'ta veri tipleri de tam olarak bu mantıkla çalışır: her veri tipi farklı boyutta bir "kutu" ve içine koyabileceğin şeylerin türü ve büyüklüğü o kutuya göre değişir.

Bu derste C++'ın temel yapı taşları olan veri tiplerini tanıyacağız. Hangi tipi ne zaman kullanman gerektiğini, bellekte ne kadar yer kapladıklarını ve aralarındaki farkları öğreneceksin.


Neden Veri Tipleri Önemli?

Bilgisayarın belleği sınırlıdır. Her değişken tanımladığında, bellekten bir parça ayırıyorsun. Eğer sadece bir kişinin yaşını tutacaksan, 8 byte'lık bir long long kullanmak israf olur. Ama bir galaksideki yıldız sayısını tutacaksan, short yetmez.

C++ "statik tipli" (statically typed) bir dildir. Yani bir değişkenin tipini en baştan belirlersin ve o tip programın sonuna kadar değişmez. Python gibi dillerde tip otomatik belirlenir ama C++'ta sen söylersin.

Bu hem avantaj hem sorumluluk: derleyici hataları erkenden yakalar, ama sen de doğru tipi seçmek zorundasın.


Tam Sayı Tipleri (Integer Types)

Tam sayılar, ondalık kısmı olmayan sayılardır: 1, 42, -7, 0 gibi. C++ sana farklı boyutlarda tam sayı kutuları sunar.

int — Günlük Kullanımın Yıldızı

int en yaygın kullanılan tam sayı tipidir. Çoğu platformda 4 byte (32 bit) yer kaplar.

#include <iostream>

int main() {
    int yas = 25;
    int sicaklik = -5;
    int ogrenci_sayisi = 1500;

    std::cout << "Yas: " << yas << std::endl;
    std::cout << "Sicaklik: " << sicaklik << std::endl;
    std::cout << "Ogrenci: " << ogrenci_sayisi << std::endl;

    return 0;
}

int yaklaşık -2.1 milyar ile +2.1 milyar arasında değer tutabilir. Günlük programlamada bu aralık çoğu iş için fazlasıyla yeterlidir.

short — Küçük Kutu

short genelde 2 byte (16 bit) yer kaplar. -32,768 ile 32,767 arasında değer tutar.

#include <iostream>

int main() {
    short kucuk_sayi = 30000;
    // short tasma = 40000;  // Uyari! 32767'yi asar

    std::cout << "Kucuk sayi: " << kucuk_sayi << std::endl;
    return 0;
}

Bellek çok kısıtlı ortamlarda (gömülü sistemler gibi) veya binlerce küçük sayı tutman gerektiğinde short işine yarar. Ama modern bilgisayarlarda genelde int kullanırsın.

long ve long long — Büyük Sayılar İçin

long en az 4 byte, long long en az 8 byte yer kaplar. Çok büyük sayılarla çalışırken long long tercih edilir.

#include <iostream>

int main() {
    long buyuk = 2000000000L;
    long long cok_buyuk = 9000000000000000000LL;

    std::cout << "long: " << buyuk << std::endl;
    std::cout << "long long: " << cok_buyuk << std::endl;

    return 0;
}

long long ile yaklaşık ±9.2 kentilyon (9.2 × 10¹⁸) arasında değer tutabilirsin. Finansal hesaplamalar, büyük veri setleri veya bilimsel hesaplamalar için idealdir.

💡 İpucu: Sayı sabitlerinin (literal) sonuna L veya LL eklemek, derleyiciye o sayının long veya long long olduğunu söyler. 42L bir long, 42LL bir long long'dur.

Tam Sayı Tipleri Karşılaştırma Tablosu

TipMinimum BoyutTipik BoyutAralık (tipik)
short2 byte2 byte-32,768 → 32,767
int2 byte4 byte-2.1 milyar → 2.1 milyar
long4 byte4 veya 8 bytePlatform bağımlı
long long8 byte8 byte±9.2 × 10¹⁸

⚠️ Dikkat: C++ standardı bu tiplerin *minimum* boyutlarını garanti eder, tam boyutlarını değil. Yani int bir platformda 2 byte, başka bir platformda 4 byte olabilir. Kesin boyut istiyorsan <cstdint> başlık dosyasındaki tipleri kullan.


Sabit Boyutlu Tam Sayılar (Fixed-Width Integers)

Platformdan bağımsız, kesin boyut istiyorsan <cstdint> başlık dosyasını kullanabilirsin:

#include <iostream>
#include <cstdint>

int main() {
    int8_t   kucuk   = 127;         // Tam 1 byte
    int16_t  orta    = 32000;       // Tam 2 byte
    int32_t  buyuk   = 2000000000;  // Tam 4 byte
    int64_t  dev     = 9000000000000000000LL;  // Tam 8 byte

    std::cout << "int8:  " << static_cast<int>(kucuk) << std::endl;
    std::cout << "int16: " << orta << std::endl;
    std::cout << "int32: " << buyuk << std::endl;
    std::cout << "int64: " << dev << std::endl;

    return 0;
}

Bu tipler özellikle ağ programlama, dosya formatları ve platformlar arası taşınabilirlik gereken durumlarda çok işe yarar.


signed vs unsigned — İşaretli ve İşaretsiz

Varsayılan olarak tam sayı tipleri "signed"dır, yani hem pozitif hem negatif değer tutabilirler. unsigned anahtar kelimesiyle sadece pozitif (ve sıfır) değer tutan bir tip elde edersin.

#include <iostream>

int main() {
    int normal = -42;              // -2.1 milyar ile +2.1 milyar
    unsigned int pozitif = 42;     // 0 ile ~4.2 milyar

    std::cout << "signed: " << normal << std::endl;
    std::cout << "unsigned: " << pozitif << std::endl;

    // Tehlikeli durum:
    unsigned int dikkat = 0;
    dikkat = dikkat - 1;  // 0'dan 1 cikarinca ne olur?
    std::cout << "Surpriz: " << dikkat << std::endl;  // 4294967295!

    return 0;
}

unsigned bir değişkenden 0'ın altına inersen, sayı taşması (overflow) olur ve çok büyük bir pozitif sayı elde edersin. Bu, C++'taki en sinsi hatalardan biridir.

Ne Zaman unsigned Kullanmalı?

  • Bit manipülasyonu yapıyorsan

  • Bir dizinin boyutu gibi doğası gereği negatif olamayacak değerler için

  • Standart kütüphanenin size_t gibi tipleriyle çalışırken

Ama genel kurala dikkat: emin değilsen `signed` (yani normal `int`) kullan. Unsigned ile signed karıştırmak karşılaştırma hatalarına yol açar.

⚠️ Dikkat: unsigned int ile int karşılaştırması beklenmedik sonuçlar doğurabilir. Derleyiciler genelde bu konuda uyarı verir — uyarıları ciddiye al!


Ondalıklı Sayı Tipleri (Floating-Point Types)

Gerçek dünyada her şey tam sayı değildir. Sıcaklık 36.6 derece olabilir, pi sayısı 3.14159... diye devam eder. İşte bu tür sayılar için ondalıklı (floating-point) tipler kullanırız.

float — Tek Hassasiyet (Single Precision)

float 4 byte yer kaplar ve yaklaşık 6-7 basamak hassasiyet sağlar.

#include <iostream>
#include <iomanip>

int main() {
    float pi = 3.14159265f;  // 'f' soneki float oldugunu belirtir
    float sicaklik = 36.6f;

    std::cout << std::setprecision(10);
    std::cout << "Pi (float): " << pi << std::endl;
    // Cikti: 3.141592741 — 7. basamaktan sonra sapma baslar!

    return 0;
}

Gördüğün gibi, float 7. basamaktan sonra "sallamaya" başlıyor. Bu normal — floating-point sayılar doğası gereği yaklaşık değerlerdir.

double — Çift Hassasiyet (Double Precision)

double 8 byte yer kaplar ve yaklaşık 15-16 basamak hassasiyet sağlar. C++'ta ondalıklı sayılar için varsayılan tip double'dır.

#include <iostream>
#include <iomanip>

int main() {
    double pi = 3.141592653589793;
    float pi_f = 3.141592653589793f;

    std::cout << std::setprecision(16);
    std::cout << "Pi (double): " << pi << std::endl;
    std::cout << "Pi (float):  " << pi_f << std::endl;

    return 0;
}

long double — Ekstra Hassasiyet

long double platformdan platforma değişir (8, 12 veya 16 byte olabilir). Çoğu programcı double ile yetinir, long double çok nadir kullanılır.

float vs double Karşılaştırma

Özellikfloatdouble
Boyut4 byte8 byte
Hassasiyet~7 basamak~15 basamak
Aralık±3.4 × 10³⁸±1.7 × 10³⁰⁸
KullanımGrafik, oyun, GPUGenel amaçlı, bilimsel

💡 İpucu: Emin değilsen double kullan. float sadece belleğin çok kısıtlı olduğu veya GPU hesaplaması yaptığın durumlarda tercih edilir. Derleyici de zaten ondalıklı sabitleri varsayılan olarak double kabul eder.

Floating-Point Tuzakları

Ondalıklı sayılarla çalışırken en önemli kural: tam eşitlik karşılaştırması yapma!

#include <iostream>
#include <cmath>

int main() {
    double a = 0.1 + 0.2;
    double b = 0.3;

    // YANLIS — beklenmedik sonuc verebilir
    if (a == b) {
        std::cout << "Esit" << std::endl;
    } else {
        std::cout << "Esit degil!" << std::endl;  // Bu calisir!
    }

    // DOGRU — epsilon ile karsilastir
    double epsilon = 1e-9;
    if (std::abs(a - b) < epsilon) {
        std::cout << "Yaklasik esit" << std::endl;  // Bu calisir
    }

    return 0;
}

0.1 + 0.2 tam olarak 0.3 etmez! Bu, floating-point aritmetiğinin doğasından kaynaklanır. İkili (binary) sistemde 0.1 sonsuz tekrarlı bir sayıdır — tıpkı 1/3'ün onluk sistemde 0.333... olması gibi.


Karakter Tipi — char

char tek bir karakter tutar ve 1 byte (8 bit) yer kaplar. Karakterler aslında sayı olarak saklanır — ASCII tablosuna göre.

#include <iostream>

int main() {
    char harf = 'A';
    char rakam = '7';
    char ozel = '\n';  // Yeni satir karakteri

    std::cout << "Harf: " << harf << std::endl;
    std::cout << "ASCII degeri: " << static_cast<int>(harf) << std::endl;
    // Cikti: 65

    // char aslinda bir sayi!
    char sonraki = harf + 1;
    std::cout << "Sonraki: " << sonraki << std::endl;
    // Cikti: B

    return 0;
}

char ile aritmetik yapabilirsin çünkü temelde bir sayıdır. 'A' + 1 sana 'B' verir, çünkü ASCII tablosunda A=65, B=66.

Özel Karakterler (Escape Sequences)

Kaçış DizisiAnlamı
\nYeni satır
\tTab
\\Ters eğik çizgi
\'Tek tırnak
\"Çift tırnak
\0Null karakter (string sonu)

char8_t, char16_t, char32_t — Unicode Destekleri

Modern C++ Unicode için ek karakter tipleri sunar:

#include <iostream>

int main() {
    char ascii = 'A';           // 1 byte, ASCII
    char16_t unicode16 = u'Ş';  // 2 byte, UTF-16
    char32_t unicode32 = U'🎮'; // 4 byte, UTF-32

    std::cout << "ASCII boyut: " << sizeof(ascii) << std::endl;
    std::cout << "char16 boyut: " << sizeof(unicode16) << std::endl;
    std::cout << "char32 boyut: " << sizeof(unicode32) << std::endl;

    return 0;
}

Türkçe karakterler veya emoji gibi ASCII dışı karakterlerle çalışıyorsan bu tipleri bilmen faydalı olur. Ama günlük işlerde genelde std::string ve UTF-8 kullanırsın.


Mantıksal Tip — bool

bool sadece iki değer alabilir: true (doğru) veya false (yanlış). Genelde 1 byte yer kaplar.

#include <iostream>

int main() {
    bool aktif = true;
    bool silindi = false;
    bool yetiskin = (18 <= 25);  // true

    std::cout << std::boolalpha;  // true/false yazdirir (1/0 yerine)
    std::cout << "Aktif: " << aktif << std::endl;
    std::cout << "Silindi: " << silindi << std::endl;
    std::cout << "Yetiskin: " << yetiskin << std::endl;

    // bool aritmetikte sayi gibi davranir
    int toplam = aktif + silindi + yetiskin;
    std::cout << "Toplam (true sayisi): " << toplam << std::endl;
    // true=1, false=0, true=1 → toplam=2

    return 0;
}

bool aritmetik ifadelerde true → 1, false → 0 olarak davranır. Koşul ifadelerinde (if, while) en çok kullanılan tiptir.

💡 İpucu: std::boolalpha manipülatörünü kullanmazsan, cout bool değerleri 1 ve 0 olarak yazdırır. Okunabilirlik için boolalpha tercih edilir.


sizeof() Operatörü

sizeof() bir tipin veya değişkenin bellekte kaç byte yer kapladığını söyler. Derleme zamanında (compile-time) hesaplanır, yani programın çalışma hızını etkilemez.

#include <iostream>

int main() {
    std::cout << "char:      " << sizeof(char) << " byte" << std::endl;
    std::cout << "short:     " << sizeof(short) << " byte" << std::endl;
    std::cout << "int:       " << sizeof(int) << " byte" << std::endl;
    std::cout << "long:      " << sizeof(long) << " byte" << std::endl;
    std::cout << "long long: " << sizeof(long long) << " byte" << std::endl;
    std::cout << "float:     " << sizeof(float) << " byte" << std::endl;
    std::cout << "double:    " << sizeof(double) << " byte" << std::endl;
    std::cout << "bool:      " << sizeof(bool) << " byte" << std::endl;

    // Degiskenle de kullanilabilir
    int x = 42;
    std::cout << "x:         " << sizeof(x) << " byte" << std::endl;

    return 0;
}

Tipik bir 64-bit Linux/Windows sisteminde çıktı şöyle olur:

char:      1 byte
short:     2 byte
int:       4 byte
long:      4 byte (Windows) veya 8 byte (Linux)
long long: 8 byte
float:     4 byte
double:    8 byte
bool:      1 byte

sizeof bir fonksiyon değil, bir operatördür. Tip ismiyle kullanırken parantez zorunludur (sizeof(int)), ama değişkenle kullanırken opsiyoneldir (sizeof x de çalışır — yine de parantez kullanmak daha okunabilir).


Tip Sınırlarını Öğrenmek — numeric_limits

Her tipin alabildiği minimum ve maksimum değerleri <limits> başlık dosyasıyla öğrenebilirsin:

#include <iostream>
#include <limits>

int main() {
    std::cout << "int min: "
              << std::numeric_limits<int>::min() << std::endl;
    std::cout << "int max: "
              << std::numeric_limits<int>::max() << std::endl;

    std::cout << "double min: "
              << std::numeric_limits<double>::min() << std::endl;
    std::cout << "double max: "
              << std::numeric_limits<double>::max() << std::endl;

    std::cout << "float hassasiyet (digits10): "
              << std::numeric_limits<float>::digits10 << std::endl;
    std::cout << "double hassasiyet (digits10): "
              << std::numeric_limits<double>::digits10 << std::endl;

    return 0;
}

digits10 bir tipin güvenilir şekilde temsil edebileceği ondalık basamak sayısını verir. float için 6, double için 15.


void — "Hiçlik" Tipi

void aslında bir veri tipi değildir — "tip yok" anlamına gelir. Değişken tanımlamak için kullanamazsın ama iki yerde karşına çıkar:

  1. Fonksiyonlar: Değer döndürmeyen fonksiyonlar void döner

  2. Pointer'lar: void* herhangi bir tipe işaret edebilir (ileri konular)

#include <iostream>

void selamla() {  // Deger dondurmuyor
    std::cout << "Merhaba!" << std::endl;
}

int main() {
    selamla();
    // void x = 5;  // HATA! void degisken olamaz
    return 0;
}

void şimdilik sadece "bir fonksiyon değer döndürmüyorsa void yazılır" bilgisi yeterli. İlerleyen derslerde fonksiyonlar konusunda detaylı göreceksin.


Doğru Tipi Nasıl Seçerim?

Pratik bir karar ağacı:

  1. Tam sayı mı?

- Normal aralıkta → int - 2 milyarı aşabilir → long long - Çok küçük ve bellek kritik → short - Kesin boyut lazım → int32_t, int64_t

  1. Ondalıklı sayı mı?

- Genel amaçlı → double - GPU / grafik / bellek kritik → float

  1. Karakter mi?

- ASCII → char - Unicode → char32_t veya std::string (UTF-8)

  1. Evet/Hayır mı?

- → bool

  1. Emin değil misin?

- Tam sayı → int - Ondalıklı → double


Sayı Sabitleri (Literals) ve Ayraçlar

C++14'ten itibaren büyük sayıları okunabilir kılmak için tek tırnak ayraç kullanabilirsin:

#include <iostream>

int main() {
    int milyon = 1'000'000;          // Okunaklı!
    long long buyuk = 9'223'372'036'854'775'807LL;
    double pi = 3.141'592'653'589'793;

    // Farkli tabanlarda sabitler
    int onluk    = 42;       // Decimal
    int sekizlik = 052;      // Octal (0 ile baslar)
    int onaltilik = 0x2A;    // Hexadecimal (0x ile baslar)
    int ikilik   = 0b101010; // Binary (0b ile baslar, C++14)

    std::cout << "Hepsi 42: "
              << onluk << ", " << sekizlik << ", "
              << onaltilik << ", " << ikilik << std::endl;

    return 0;
}

⚠️ Dikkat: Sayının başına yanlışlıkla 0 koyarsan, derleyici onu sekizlik (octal) sayı olarak yorumlar. 010 yazdığında 10 değil 8 elde edersin!


Tip Takma Adları (Type Aliases)

Uzun tip isimlerini kısaltmak için using anahtar kelimesini kullanabilirsin:

#include <iostream>
#include <cstdint>

using Byte = uint8_t;
using Score = int32_t;
using Distance = double;

int main() {
    Byte veri = 255;
    Score puan = 95;
    Distance mesafe = 12.5;

    std::cout << "Veri: " << static_cast<int>(veri) << std::endl;
    std::cout << "Puan: " << puan << std::endl;
    std::cout << "Mesafe: " << mesafe << std::endl;

    return 0;
}

using ile kodun daha okunabilir hale gelir. Eski C tarzı typedef da çalışır ama modern C++'ta using tercih edilir.


Özet

  • int günlük tam sayı işleri için varsayılan tercihtir; long long çok büyük sayılar içindir

  • double ondalıklı sayılar için varsayılandır; float sadece bellek/performans kritik durumlarda kullanılır

  • char tek bir karakter tutar ve aslında bir sayıdır (ASCII değeri)

  • bool sadece true veya false alır; koşullarda vazgeçilmezdir

  • sizeof() herhangi bir tipin veya değişkenin byte cinsinden boyutunu verir

  • unsigned sadece pozitif değer tutar ama taşma riski taşır — emin değilsen signed kullan