Bölüm 2: Diziler ve Yapılar

C ile Veri Yapıları ve Algoritmalar · Çalışma Soruları
Dizi ve işaretçiDinamik diziAdres hesabıÜçgen ve kuşak matrisstruct ve hizalamaDizgelerMatris çarpımı
Sercan KÜLCÜ

Çoktan Seçmeli · Dizi ADT

Soru 1: İşaretçiyle İndis

int a[8]; int *p = a + 2; tanımlarından sonra p[3] ve *(p - 1) hangi öğelerdir?

C: p, a[2]'yi gösterir. p[3] ≡ *(p + 3) ≡ a[2 + 3] = a[5]; *(p - 1) = a[1]. İşaretçi aritmetiği öğe sayar: p + 3, 3·sizeof(int) bayt ileridedir. A ve D, p'nin a'nın başını gösterdiğini varsayar.

Çoktan Seçmeli · Dizi ADT

Soru 2: Parametrede sizeof

int 4 bayt, işaretçi 8 bayt olan bir sistemde program ne yazdırır?

void f(int a[]) {
  printf("%zu\n", sizeof a / sizeof a[0]);
}
int main(void) {
  int d[10];
  printf("%zu ", sizeof d / sizeof d[0]);
  f(d);
  return 0;
}

B: main'de d gerçek bir dizidir: 40 / 4 = 10. Parametredeki int a[] ise int *a ile aynıdır; sizeof a işaretçinin boyutu (8) olur: 8 / 4 = 2. Dizi fonksiyona kopyalanmaz, yalnızca adresi geçer; bu yüzden boyut ayrı bir parametreyle gönderilir. Derleyici de bu satır için uyarı verir.

Çıktı Sorusu · Dizi ADT

Soru 3: İşaretçi Aritmetiği

Parça ne yazdırır? (char *)q - (char *)(d + 1) kaç olurdu (int 4 bayt)?

int d[] = {10, 20, 30, 40, 50};
int *p = d + 1, *q = &d[4];
printf("%td\n", q - p);
printf("%d\n", *p + 1);
printf("%d\n", *(p + 1));
p += 2;
*p = 7;
printf("%d %d\n", d[3], p[-1]);
Cevabı göster
3
21
30
7 30
  • q - p: d[4] ile d[1] arasında 3 öğe (bayt değil).
  • *p + 1: önce *p = 20, sonra + 1 → 21. *(p + 1) ise d[2] = 30'dur; parantez önceliği değiştirir.
  • p += 2 → p = &d[3]; *p = 7 d[3]'ü değiştirir. p[-1] = d[2] = 30.

Bayt farkı 3 · 4 = 12'dir: char * aritmetiği bayt sayar.

Çoktan Seçmeli · Dinamik Diziler

Soru 4: realloc ile Büyütmek

n öğeli dinamik dizi a, m > n öğeye büyütülecek. Hangisi hem eski öğeleri korur hem de bellek ayrılamazsa eski bloğu kaybetmez?

B: realloc başarısız olursa NULL döner ve eski blok yerinde kalır; sonuç önce geçici değişkene alınmalıdır. A'da NULL a'nın üzerine yazılır, eski blok sızar. C eski öğeleri kopyalamaz ve eski bloğu bırakmaz; D eski verileri yok eder.

Adım Adım Çalıştırma · Dinamik Diziler

Soru 5: Sabit Artışla Büyüyen Dizi

ekle kapasiteyi ikiye katlamak yerine 2 artırıyor. Boş diziye 6 öğe eklenince kaç kopya yapılır? n eklemede maliyet nasıl büyür?

veri (kap = 0, boyut = 0)NULL

Boş dizi {NULL, 0, 0}. Sırayla 6, 1, 8, 3, 5, 2 eklenecek.

veri (kap = 2, boyut = 1)6010 öğe kopyalandı

Dolu (0 == 0): kap 0 → 2. NULL'dan realloc, malloc gibi davranır. 6 yazılır.

veri (kap = 2, boyut = 2)6011

Yer var: 1 doğrudan yazılır.

veri (kap = 4, boyut = 3)60118232 öğe kopyalandı

Dolu: kap 2 → 4; realloc eski 2 öğeyi yeni bloğa taşır.

veri (kap = 4, boyut = 4)60118233

Yer var: 3 yazılır.

veri (kap = 6, boyut = 5)601182335454 öğe kopyalandı

Dolu: kap 4 → 6; 4 kopya daha.

veri (kap = 6, boyut = 6)601182335425

6 eklemede 2 + 4 = 6 kopya. Her 2 eklemede bir büyütme: n eklemede ≈ n²/4 kopya (n = 1000 için 249 500) → O(n²); ikiye katlamada 1023'ü geçmez.

int ekle(DinDizi *d, int x) {
  if (d->boyut == d->kap) {
    int yeni = d->kap + 2;  /* sabit */
    int *t = realloc(d->veri,
                     yeni * sizeof *t);
    if (t == NULL) return 0;
    d->veri = t;
    d->kap = yeni;
  }
  d->veri[d->boyut++] = x;
  return 1;
}

Hata Bulma · Dinamik Diziler

Soru 6: 2B Diziyi Bırakmak

dizi2b(3, 4) ile ayrılan diziyi bırakan bu fonksiyonun hatası nedir? Doğrusu nasıl yazılır; toplam kaç free gerekir?

void sil2b(int **x, int satir) {
  int i;
  free(x);
  for (i = 0; i < satir; i++)
    free(x[i]);
}
Cevabı göster

free(x) işaretçi dizisini bırakır; ardından x[i] okumak free edilmiş belleğe erişimdir (tanımsız davranış). Program çoğu zaman çalışıyor gibi görünür; bu hatayı daha sinsi yapar.

void sil2b(int **x, int satir) {
  int i;
  for (i = 0; i < satir; i++)
    free(x[i]);    /* once satirlar */
  free(x);         /* sonra dizi */
}

dizi2b(3, 4) 1 + 3 = 4 malloc yapar; 4 free gerekir (sayaçla doğrulandı). Yalnız free(x) yazılsaydı satırlar sızardı.

Çoktan Seçmeli · Çok Boyutlu Diziler

Soru 7: Sütun Öncelikli Adres

float m[6][5] dizisi α = 1000 adresinden başlıyor, sizeof(float) = 4. Dizi sütun öncelikli saklansaydı &m[2][3] kaç olurdu?

D: Sütun öncelikli düzende öğeden önce 3 tam sütun (3 · 6 = 18 öğe) ve sütununda 2 öğe vardır: 1000 + 20 · 4 = 1080. A satır önceliklidir (C'nin kullandığı): 1000 + (2 · 5 + 3) · 4 = 1052. B, sütun uzunluğu yerine satır uzunluğunu (5) kullanır.

Klasik Soru · Çok Boyutlu Diziler

Soru 8: Horner ile Ofset

char K[4][3][6]; dizisi 500 adresinden başlıyor. K[2][1][4]'ün ofsetini Horner yöntemiyle bulunuz; adresi nedir, kaç çarpma yapılır, hangi boyut hesaba girmez?

Cevabı göster

t = 2 → t = 2 · 3 + 1 = 7 → t = 7 · 6 + 4 = 46. char 1 bayt olduğundan adres 500 + 46 = 546.

n − 1 = 2 çarpma yapılır. İlk boyut (4) formüle hiç girmez; yalnızca sınır denetiminde gerekir. Açık formül de aynıdır: 2 · 3 · 6 + 1 · 6 + 4 = 46. Gerçek C dizisinde &K[2][1][4] - &K[0][0][0] 46 verir.

Çoktan Seçmeli · Üçgen ve Kuşak Matrisler

Soru 9: Üst Üçgen Matris

5 × 5 üst üçgen matrisin (j ≥ i) öğeleri satır öncelikli olarak tek boyutlu bir diziye yazılıyor. a13 bu dizinin kaçıncı indisindedir?

A: 0. satırda 5 öğe (indis 0–4) vardır; 1. satır a11, a12, a13 ile 5, 6, 7'ye yazılır. Formül: i·n − i(i−1)/2 + (j − i) = 5 − 0 + 2 = 7. B alt üçgen formülüdür (i(i+1)/2 + j); C tam matristeki konumdur (i·n + j).

Adım Adım Çalıştırma · Üçgen ve Kuşak Matrisler

Soru 10: Kuşak Matriste Erişim

n = 5, a = 2, b = 3 (köşegen dâhil) kuşak matris KusakMatrisKur ile kuruldu. (3, 2), (1, 3), (2, 2), (0, 4) ve (4, 1) için KusakMatrisEris ne döndürür?

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

Kuşaklar −1, 0, 1, 2 (uzunluk 4, 5, 4, 3) → 16 öğe, ARA = [0, 4, 9, 13]. Hücrelerdeki sayı kuşak no j − i.

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

d32: j − i = −1 → alt. i − j = 1 < 2 → ara[−1 + 1] + j = 0 + 2 = 2.

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

d13: j − i = 2 < b = 3 → üst kuşak: ara[2 + 1] + i = 13 + 1 = 14.

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

Köşegen de 'alt' dalında: ara[0 + 1] + j = 4 + 2 = 6.

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

d04: j − i = 4 ≥ b → kuşak dışı, üst sabit bölge: −1.

0123400121-10122-10123-1014-10kusak[] (ARA = [0, 4, 9, 13])0123456789101112131415

d41: i − j = 3 ≥ a = 2 → alt sabit bölge: −2. Her çağrı sabit sayıda işlem: O(1).

int KusakMatrisEris(int i, int j, int n,
        int a, int b, int ara[]) {
  if (i < 0 || j < 0 || i >= n || j >= n)
    return -3;
  else if (j - i >= 1) {        /* ust */
    if (j - i < b)
      return ara[j - i + a - 1] + i;
    else return -1;
  } else if (i - j < a)        /* alt */
    return ara[j - i + a - 1] + j;
  else return -2;
}

Çoktan Seçmeli · Üçgen ve Kuşak Matrisler

Soru 11: Kuşaktaki Öğe Sayısı

6 × 6 bir matriste yalnızca ana köşegen ve onun altındaki iki kuşak saklanacak (a = 3, b = 1). Kuşak dizisi kaç öğe tutar?

D: Kuşak uzunlukları 4 + 5 + 6 = 15; formül n(a + b − 1) − a(a − 1)/2 − b(b − 1)/2 = 18 − 3 − 0 = 15. A her kuşağı n uzunlukta sayar; alt kuşaklar köşegenden uzaklaştıkça birer kısalır.

Çoktan Seçmeli · Üçgen ve Kuşak Matrisler

Soru 12: Kısa Devre

a n öğeli bir dizi ve i == n. Aşağıdaki koşullardan hangisi dizinin dışındaki a[n]'yi okur?

C: & bit düzeyi VE'dir; iki işleneni de hesaplanır, kısa devre yapmaz. && ve || ise soldan sağa değerlendirilir: A'da i < n yanlış olunca sağ taraf hiç hesaplanmaz; B'de i >= n doğru olunca durulur. A ile D aynı derecede güvenlidir.

Çıktı Sorusu · Yapılar

Soru 13: Yapı Ataması

Yapı ataması alanları nasıl kopyalar? Parça ne yazdırır?

typedef struct {
  char ad[8];
  int *not;
} kayit;
int n1 = 70;
kayit a = {"Ali", &n1}, b;
b = a;
strcpy(b.ad, "Can");
*b.not = 90;
printf("%s %d\n", a.ad, *a.not);
Cevabı göster

Çıktı: Ali 90.

  • b = a alan alan kopyalar: ad dizisinin içeriği b'ye kopyalanır, not işaretçisinin ise yalnızca değeri (adres).
  • strcpy(b.ad, "Can") yalnız b'nin kendi dizisini değiştirir; a.ad "Ali" kalır.
  • a.not ve b.not aynı n1'i gösterir; *b.not = 90 n1'i değiştirir, a'dan da 90 okunur.

Buna sığ kopya denir: işaretçi alanlı yapılarda gösterilen veri paylaşılır. *b.not, *(b.not) demektir; . işleci *'dan önceliklidir.

Çoktan Seçmeli · Yapılar

Soru 14: Hizalama ve sizeof

int 4 bayt ve 4 bayta hizalanıyor. struct { char a; int b; char c; } için sizeof tipik olarak kaçtır?

A: a'dan sonra b'yi 4'ün katına hizalamak için 3 bayt dolgu eklenir (0: a, 4–7: b, 8: c); yapı boyutu da en geniş hizalamanın katı olmalıdır: 9 → 12. C alanların ham toplamıdır. B, alanlar { int b; char a, c; } sırasıyla yazılınca elde edilir (4 + 1 + 1 → 8).

Adım Adım Çalıştırma · Dizgeler

Soru 15: Dizgeyi Ters Çevirmek

tersine fonksiyonu "kalem" dizgesini nasıl değiştirir? Program ne yazdırır?

k0a1l2e3m4\05pq

strlen = 5 → q son harfi gösterir; '\0' yerinde kalmalı.

m0a1l2e3k4\05pq

p < q: 'k' ile 'm' yer değiştirir.

m0e1l2a3k4\05pq

p++, q-- → 1 < 3: 'a' ile 'e' yer değiştirir.

m0e1l2a3k4\05p,q

p == q: ortadaki 'l' yerinde kalır, döngü biter.

m0e1l2a3k4\05

n/2 takas → O(n). Boş dizgede q = s − 1 olurdu; dizinin öncesini gösteren işaretçi oluşturmak tanımsızdır, önce strlen(s) == 0 denetlenmelidir.

void tersine(char *s) {
  char *p = s, *q = s + strlen(s) - 1, t;
  while (p < q) {
    t = *p; *p = *q; *q = t;
    p++; q--;
  }
}
/* main: */
char s[] = "kalem";
tersine(s);
printf("%s\n", s);

Hata Bulma · Dizgeler

Soru 16: Dizge Kopyası

Aşağıdaki kodda üç hata var. Hatalar nelerdir ve doğrusu nasıl yazılır?

char *kopyasi(const char *ad) {
  char *s = malloc(strlen(ad));
  strcpy(s, ad);
  return s;
}
/* main: */
char *k = kopyasi("Ali");
if (k == "Ali")
  printf("ayni\n");
Cevabı göster
  • malloc(strlen(ad)) sonlandırıcı '\0' için yer ayırmaz: "Ali" için 3 bayt ayrılır, strcpy 4 bayt yazar → taşma. Doğrusu strlen(ad) + 1.
  • malloc sonucu NULL için denetlenmemiş.
  • k == "Ali" içerikleri değil adresleri karşılaştırır; heap'teki kopya hiçbir zaman sabit dizgenin adresinde değildir. strcmp(k, "Ali") == 0 yazılmalı.
char *s = malloc(strlen(ad) + 1);
if (s == NULL) return NULL;
strcpy(s, ad);
/* ... */
if (strcmp(k, "Ali") == 0)
  printf("ayni\n");
free(k);

Kopya iş bitince free edilmelidir.

Kod Yazma · Matris İşlemleri

Soru 17: Düz Dizide Matris Çarpımı

m × n'lik a ile n × p'lik b satır öncelikli olarak tek boyutlu dizilerde tutuluyor. Çarpımı m × p'lik c'ye yazan mult fonksiyonunu yazınız. 3 × 4 ile 4 × 2 çarpımında kaç çarpma yapılır?

Cevabı göster
void mult(const int *a, const int *b, int *c,
          int m, int n, int p) {
  int i, j, k;
  for (i = 0; i < m; i++)
    for (j = 0; j < p; j++) {
      int s = 0;
      for (k = 0; k < n; k++)
        s += a[i * n + k] * b[k * p + j];
      c[i * p + j] = s;
    }
}

aik satır öncelikli düzende a[i * n + k]'dadır (önünde i tam satır). c'nin m·p hücresinin her biri n çarpım ister: 3 · 4 · 2 = 24 çarpma, 6 hücre → O(m·n·p); kare matriste O(n³).

Son

Bölüm 2: Diziler ve Yapılar — Çalışma Soruları
Konu anlatımı: Diziler ve yapılar sunumu · Ders notu · Terim sözlüğü
1 / 1 Sercan KÜLCÜ, Tüm hakları saklıdır.