SEN2001 · 5. hafta · Data Types

Veri tipleri I: primitive, string, enum ve dizi adresleme

Primitive tipler, string tasarımı, enumeration, dizi kategorileri, row-major ve column-major adres formülleri ve associative array. Adres hesabı vizede garanti puan.

data typeprimitive typeintegerfloating-pointbooleancharacterUnicodestringimmutableenumeration typesubrangearraysubscriptstatic arrayfixed stack-dynamicstack-dynamicfixed heap-dynamicheap-dynamicrow-major ordercolumn-major orderaccess functionjagged arraysliceassociative array

Veri tipi, bir değer kümesi ve bu değerler üzerinde tanımlı işlemler kümesidir. Bu sayfa tiplerin “tek başına” olanlarını ve dizileri kapsar. Vizede en garanti soru: iki boyutlu dizinin adresini hesapla. Formülü bilen ve alt sınırları unutmayan herkes alır.

Altın kurallar:

  1. Row-major’da satır indeksi sütun sayısıyla çarpılır, column-major’da sütun indeksi satır sayısıyla.
  2. Alt sınır 0 değilse önce çıkar.
  3. Emin değilsen önde kaç eleman olduğunu say. Formül zaten bunu yapar.
  4. Floating-point yaklaşıktır, int taşar.

Primitive tipler

Başka tiplerle tanımlanmayan tiplerdir. Çoğu doğrudan donanıma karşılık gelir.

TipNot
IntegerJava’da byte, short, int, long (8/16/32/64 bit, işaretli). C/C++‘ta ayrıca unsigned. Negatifler ikiye tümleyen (two’s complement) ile tutulur
Floating-pointGerçel sayıların yaklaşık modeli. IEEE 754: float 32 bit, double 64 bit
DecimalOndalık tabanda tam temsil (iş uygulamaları, para). COBOL, C# decimal. Bellek israfı ve sınırlı aralık
Booleantrue/false. Okunabilirliği artırır. C89’da yok, int kullanılır (0 false)
CharacterSayısal kod olarak tutulur. ASCII 8 bit; Java ve C# Unicode (UTF-16) kullanır
System.out.println('A' + 1);   // char int'e yükselir
char c = 'A'; c++;
System.out.println(c);
System.out.println(0.1 + 0.2 == 0.3);
System.out.println(0.1 + 0.2);
int x = Integer.MAX_VALUE; x++;
System.out.println(x);
byte b = (byte) 130;
System.out.println(b);
66
B
false
0.30000000000000004
-2147483648
-126

130, byte aralığına (-128..127) sığmaz; 256 çıkarılır: -126. Taşma ve yaklaşıklık iki ayrı tuzak: int sessizce sarar, double sessizce yuvarlar.

String tipleri

Tasarım soruları: (1) string primitive mi, karakter dizisi mi? (2) uzunluğu statik mi, dinamik mi?

Uzunluk seçeneğiÖrnek
Static lengthJava String (nesne yaratılınca sabit), COBOL
Limited dynamic lengthC’de char s[10]: en fazla 9 karakter, sonu '\0' ile işaretli
Dynamic lengthPerl, JavaScript, C++ std::string

C’de string ayrı bir tip değildir, '\0' ile biten char dizisidir. strcpy(dest, src) hedefin boyutunu kontrol etmez; taşma güvenlik açığıdır (buffer overflow). Java’da String immutable:

String s = "ab"; String t = s; s = s + "c";
System.out.println(t + " " + s);
StringBuilder sb = new StringBuilder("ab"); StringBuilder sb2 = sb;
sb.append("c");
System.out.println(sb2);
System.out.println(new String("hi") == "hi");
System.out.println(new String("hi").equals("hi"));
ab abc
abc
false
true

Enumeration ve subrange

Enumeration tipi tüm olası değerleri isimli sabitler olarak listeler. Readability artar (Day.MON, 0’dan iyidir) ve reliability artar (Java ve C#‘ta enum’a aritmetik yapılamaz, aralık dışı değer atanamaz).

enum Day { MON, TUE, WED, THU }
System.out.println(Day.WED.ordinal() + " " + Day.valueOf("THU"));
2 THU

C’de enum değerleri int’tir: MON + 1 geçerlidir, herhangi bir int bir enum değişkenine atanabilir. Güvenlik kaybı.

Subrange tipi (Ada, Pascal) bir sıralı tipin ardışık alt kümesidir: type Weekdays is range Mon..Fri;. Aralık dışına çıkışı derleyici/çalışma zamanı yakalar.

Diziler

Dizi, homojen elemanların, ilk elemana göre konumlarıyla (indis, subscript) erişilen topluluğudur. Tasarım soruları: indis tipleri neler? İndis aralığı kontrol ediliyor mu? Ne zaman bellek ayrılıyor? Jagged mı rectangular mı? Dilimleme (slice) var mı?

Dizi kategorileri

KategoriBoyut ne zaman?Yer ne zaman / nerede?Örnek
StaticDerlemeÇalışmadan önceC static int a[10];
Fixed stack-dynamicDerlemeBildirim işlenince, stackC fonksiyonunda int a[10];
Stack-dynamicÇalışma (sonra sabit)Bildirim işlenince, stackAda Get(N); declare A: array (1..N) ...
Fixed heap-dynamicÇalışma (sonra sabit)Heap, istek üzerineJava new int[n], C malloc
Heap-dynamicDeğişebilirHeapJava ArrayList, JavaScript dizileri

Java ve C# her erişimde indis aralığını kontrol eder; C ve C++ etmez.

int[] a = new int[3];
try { a[3] = 1; } catch (Exception e) { System.out.println(e.getClass().getSimpleName()); }
ArrayIndexOutOfBoundsException

Rectangular dizide her satırın uzunluğu aynı (Fortran, C# int[,]). Jagged dizi dizilerin dizisidir, satır uzunlukları farklı olabilir (Java int[][]).

Dizi adres hesabı

Derleyici bir elemanın adresini bir access function ile hesaplar. Tek boyut, alt sınır lb, eleman boyu size:

addr(a[k])=base+(k−lb)⋅size\text{addr}(a[k]) = \text{base} + (k - lb)\cdot \text{size}

İki boyutlu dizi iki şekilde belleğe yerleşir:

  • Row-major (C, C++, Java, çoğu dil): satır satır. Önce satır 0’ın tüm elemanları, sonra satır 1…
  • Column-major (Fortran): sütun sütun.

m satır, n sütunlu dizi için:

row-major: base+((i−lbr)⋅n+(j−lbc))⋅size\text{row-major: } \text{base} + \big((i - lb_r)\cdot n + (j - lb_c)\big)\cdot \text{size}

column-major: base+((j−lbc)⋅m+(i−lbr))⋅size\text{column-major: } \text{base} + \big((j - lb_c)\cdot m + (i - lb_r)\big)\cdot \text{size}

Çözümlü örnek

int A[6][9], base 3000, int 4 byte, A[4][7].

row-major:  önde 4 tam satır × 9 = 36, + bu satırda 7  → 43 eleman
            3000 + 43 × 4 = 3172
col-major:  önde 7 tam sütun × 6 = 42, + bu sütunda 4  → 46 eleman
            3000 + 46 × 4 = 3184

Alt sınırı 1 olan Fortran dizisi B(1:5, 1:10), 8 byte, base 500, B(3, 4):

alt sınırları çıkar: satır 3-1 = 2, sütun 4-1 = 3
col-major, m = 5:  3 × 5 + 2 = 17 eleman önde
500 + 17 × 8 = 636

TUZAK · n mi m mi? Row-major’da bir satırı atlamak için o satırdaki tüm sütunları atlarsın, yani n (sütun sayısı) ile çarparsın. Column-major’da bir sütunu atlamak için o sütundaki tüm satırları atlarsın, m ile çarparsın. Karıştırırsan sonuç başka bir elemanın adresi olur ve sınavda kontrol edemezsin.

Slice

Slice, bir dizinin alt yapısıdır; yeni bir veri tipi değil, var olan dizinin bir parçasına erişim yoludur. Python a[1:4], Fortran A(2:4). JavaScript’te slice yeni bir dizi kopyalar:

console.log([10, 20, 30, 40, 50].slice(1, 4));
[ 20, 30, 40 ]

Başlangıç dahil, bitiş hariç.

Associative array

Elemanları sırasız ve anahtarla (key) erişilen topluluk. Perl hash (%h), Python dict, JavaScript Map ve nesneleri, Java HashMap.

const m = new Map([["ali", 70], ["ayse", 85]]);
m.set("ali", 90); m.delete("ayse"); m.set("can", 60);
console.log([...m.keys()].join(","), m.get("ali"), m.size);
ali,can 90 2

Var olan anahtara atama değeri günceller, yeni anahtar eleman ekler. Arama hash ile yapıldığı için sıralı aramadan hızlıdır; ama “i’nci eleman” kavramı yoktur.

Sık yapılan hatalar

YanlışDoğrusu
Row-major’da i · mi · n (sütun sayısı)
Alt sınırı 1 olan dizide çıkarma yapmamakÖnce (i - 1), (j - 1)
0.1 + 0.2 == 0.3 truefalse, floating-point yaklaşık
int taşınca hata verirSessizce sarar: MIN_VALUE
t = s; s = s + "c"; → t de değişirString immutable, t eski nesneyi gösterir
== ile String içeriği karşılaştırmakequals kullan
Java new int[n] stack-dynamicFixed heap-dynamic
C dizi sınırını kontrol ederEtmez; Java ve C# eder

Kendini test et

Sınavdaki gibi İngilizce sorular. Önce kâğıt kalemle çöz, sonra cevabı aç.

Soru 1kolay

int A[6][9] is stored in row-major order, indices start at 0, base address 3000, 4-byte integers. What is the address of A[4][7]?

Cevabı göster
3172

Row-major: önce 4 tam satır (4 · 9 = 36 eleman), sonra o satırda 7 eleman: 43 eleman önde. 3000+43⋅4=31723000 + 43 \cdot 4 = 3172. Formül: base + (i · n + j) · size, n = sütun sayısı.

Soru 2orta

Same array int A[6][9], base 3000, 4 bytes, but stored in column-major order. Address of A[4][7]?

Cevabı göster
3184

Column-major: önce 7 tam sütun (7 · 6 = 42 eleman), sonra o sütunda 4 eleman: 46 eleman önde. 3000+46⋅4=31843000 + 46 \cdot 4 = 3184. Column-major'da sütun indeksi satır sayısıyla (m = 6) çarpılır.

Soru 3zor

A Fortran array B(1:5, 1:10) (column-major, lower bounds 1) has 8-byte elements and base address 500. What is the address of B(3, 4)?

Cevabı göster
636

Alt sınırları çıkar: satır 3 - 1 = 2, sütun 4 - 1 = 3. Column-major, m = 5 satır: önde 3 · 5 + 2 = 17 eleman. 500+17⋅8=636500 + 17 \cdot 8 = 636. Alt sınırı çıkarmayı unutmak en yaygın hata.

Soru 4orta

An array is declared with subscripts -3..7, element size 2 bytes, base address 100. What is the address of the element with subscript 2?

Cevabı göster
110

Tek boyut: base + (k - lb) · size = 100 + (2 - (-3)) · 2 = 100 + 10 = 110. Alt sınır negatif olunca çıkarma toplamaya döner.

Soru 5kolay

What is printed in Java?

System.out.println('A' + 1);
char c = 'A';
c++;
System.out.println(c);
Cevabı göster
66 then B

char sayısal bir tiptir. 'A' + 1 ifadesinde char int'e yükseltilir: 65 + 1 = 66 (int basılır). c++ ise değişkenin tipini korur: c char kalır, 'B' basılır.

Soru 6orta

What is printed in Java?

System.out.println(0.1 + 0.2 == 0.3);
Cevabı göster
false

0.1 ve 0.2 ikili tabanda tam temsil edilemez; toplam 0.30000000000000004. Floating-point tipler gerçel sayıların yaklaşık modelidir. Ondalık para hesapları için decimal tipler (C# decimal, Java BigDecimal) vardır.

Soru 7orta

What is printed in Java?

int x = Integer.MAX_VALUE;
x++;
System.out.println(x);
Cevabı göster
-2147483648

int 32-bit ikiye tümleyen (two's complement). En büyük değer 231−12^{31}-1; bir artınca taşar ve en küçük değere döner: −231-2^{31}. Java taşmayı hata olarak bildirmez.

Soru 8orta

What is printed in Java?

String s = "ab";
String t = s;
s = s + "c";
System.out.println(t + " " + s);
Cevabı göster
ab abc

Java String nesneleri immutable (değişmez). s + "c" yeni bir nesne yaratır ve s onu gösterir; t hâlâ eski "ab"'yi gösterir. StringBuilder ile aynı kod (append) iki değişkende de "abc" gösterirdi, çünkü o nesne değişebilir (mutable).

Soru 9orta

What is printed in Java?

System.out.println(new String("hi") == "hi");
System.out.println(new String("hi").equals("hi"));
Cevabı göster
false then true

== referansları (adresleri) karşılaştırır: new her zaman yeni nesne yaratır, adres farklı. equals içerikleri karşılaştırır. String tasarımında "string primitive mi, nesne mi?" sorusunun sonucu bu.

Soru 10kolay

Given enum Day { MON, TUE, WED, THU } in Java, what does Day.WED.ordinal() return? Can you write Day.MON + 1 in Java?

Cevabı göster
2; no, enum values are not integers in Java

ordinal sıfırdan başlar: MON 0, TUE 1, WED 2. Java ve C#'ta enum ayrı bir tiptir, aritmetik yapılamaz ve int'e otomatik dönüşmez (reliability). C'de enum değerleri int'e coercion edilir, MON + 1 geçerlidir.

Soru 11orta

Classify each array by category: (a) a local int a[10]; in a C function; (b) int[] a = new int[n]; in Java; (c) a Java ArrayList; (d) static int a[10]; in C.

Cevabı göster
(a) fixed stack-dynamic (b) fixed heap-dynamic (c) heap-dynamic (d) static

Fixed stack-dynamic: boyut derlemede sabit, yer çağrıda stack'te. Fixed heap-dynamic: boyut çalışmada belirlenir ama sonra değişmez, heap'te. Heap-dynamic: boyut çalışma boyunca büyüyüp küçülebilir. Static: boyut ve yer çalışmadan önce sabit.

Soru 12kolay

What is printed in Java?

int[] a = new int[3];
try { a[3] = 1; }
catch (Exception e) { System.out.println(e.getClass().getSimpleName()); }
Cevabı göster
ArrayIndexOutOfBoundsException

Java her dizi erişiminde indis aralığını kontrol eder (range checking). Geçerli indisler 0..2. C ve C++ kontrol etmez: a[3] başka bir belleğe yazar, tanımsız davranış. Kontrol reliability kazandırır, çalışma maliyeti getirir.

Doğrulama: Java çıktıları JDK ile çalıştırıldı (java verify/SEN2001/W05.java). Adres cevapları node ile formülden hesaplandı ve ayrıca diziyi bellekte gerçekten satır satır / sütun sütun yerleştirip elemanın sırasını sayarak kontrol edildi (verify/SEN2001/05.mjs); associative array ve slice örnekleri JavaScript Map ve slice ile çalıştırıldı.

Deftere not kartı

primitive: int, float/double (yaklaşık!), boolean, char (Unicode) int taşar: MAX_VALUE + 1 = MIN_VALUE. 0.1 + 0.2 != 0.3 Java String immutable, StringBuilder mutable. == adres, equals içerik enum: Java/C# ayrı tip (aritmetik yok); C'de int'e dönüşür dizi kategorileri: static | fixed stack-dyn (C yerel) | stack-dyn (Ada) | fixed heap-dyn (Java new int[n]) | heap-dyn (ArrayList) 1B: base + (k - lb) * size row-major (C, Java): base + ((i - lb_r) * n + (j - lb_c)) * size n = SÜTUN sayısı col-major (Fortran): base + ((j - lb_c) * m + (i - lb_r)) * size m = SATIR sayısı kontrol: "önde kaç eleman var?" diye say Java/C# indis kontrolü yapar, C/C++ yapmaz jagged array: satır uzunlukları farklı (Java dizi dizisi) associative array: anahtar-değer (Perl hash, JS Map, Python dict)