Standart C Programlama Dili


5.8.2. Dizilere Göstergeler

Daha önce de açıklandığı gibi, bir fonksiyon parametresi olarak tanımlanmış tek boyutlu bir dizinin boyunun belirtilmesine gerek yoktur, çünkü bu bir dizi değil, gerçekte bir göstergedir. Çok-boyutlu bir dizide ne olur? Kural şöyledir: İlki dışında bütün boyutların boyunu belirtmeniz gerekir. Örneğin,

f (int uc_b[][5][7])
{  }

Gelin bunun nedenine bakalım. uc_b[0]’ın 5×7 boyunda iki-boyutlu bir dizi olduğuna dikkat edin, uc_b[1] ilkinden 35 int ileride olan bir sonraki iki-boyutlu dizidir. Yani, uc_b[1] veya *(uc_b+1)—bir gösterge ifadesi—uc_b[0]’ın 35 int ilerisini göstermelidir. Bu, uc_b’nin 5 çarpı 7 (yani 35) elemanlık bir diziye gösterge olduğu anlamına gelir. Yukarıdaki parametre bildirimi şöyle de yazılabilirdi:

int (*uc_b)[5][7];

bu da yukarıdaki ile tamamen aynıdır. Parantezlere dikkat edin. Eğer yazılmasalardı,

int *(uc_b[5][7]);

anlamına gelecek, bu da int göstergelerden oluşan iki-boyutlu bir dizi anlamına gelecekti; bir sonraki altkısmın konusu.

Aşağıdaki örnek çok-boyutlu dizilerin kullanımını özetlemeye çalışmaktadır. Programı inceleyip, onu izleyen çıktıyı doğrulamaya çalışın.

#include <stdio.h>
#include <stddef.h>

int  x[3][5][7];    /* üç-boyutlu bir dizi */

void f
  (int a[][5][7])  /* iki-boyutlu diziye gösterge */
{
  printf("%d\t%zu\n", a[0][0][0],      sizeof a[0][0][0]);
  printf("%p\t%zu\n", (void *)a[0][0], sizeof a[0][0]);
  printf("%p\t%zu\n", (void *)a[0],    sizeof a[0]);
  printf("%p\t%zu\n", (void *)a,       sizeof a);

  printf("\n%d\t%zu\n", x[0][0][0],    sizeof x[0][0][0]);
  printf("%p\t%zu\n", (void *)x[0][0], sizeof x[0][0]);
  printf("%p\t%zu\n", (void *)x[0],    sizeof x[0]);
  printf("%p\t%zu\n", (void *)x,       sizeof x);

  printf("\n%p\t%p\t%td\n", (void *)a[0], (void *)a[1],
    ((char *)a[1]-(char *)a[0]) / (ptrdiff_t)sizeof(int));
  printf("%p\t%p\t%td\n", (void *)x[0], (void *)x[1],
    ((char *)x[1]-(char *)x[0]) / (ptrdiff_t)sizeof(int));
  printf("%p\t%p\t%td\n", (void *)a[0][0], (void *)a[0][1],
    ((char *)a[0][1]-(char *)a[0][0]) / (ptrdiff_t)sizeof(int));
  printf("%p\t%p\t%td\n", (void *)x[0][0], (void *)x[0][1],
    ((char *)x[0][1]-(char *)x[0][0]) / (ptrdiff_t)sizeof(int));
}

int main (void)
{  f(x); return 0;  }

Çıktı şöyledir:

0       4
0x55d3b4520040  28
0x55d3b4520040  140
0x55d3b4520040  8

0       4
0x55d3b4520040  28
0x55d3b4520040  140
0x55d3b4520040  420

0x55d3b4520040  0x55d3b45200cc  35
0x55d3b4520040  0x55d3b45200cc  35
0x55d3b4520040  0x55d3b452005c  7
0x55d3b4520040  0x55d3b452005c  7

printf’lerde kullanılan biçimlendirmelerle ilgili bir kaç not: Kısım 1.7’de gördüğümüz gibi, %p dönüşüm tanımlaması ile bir göstergenin değeri basılır; bizim sistemde gösterge değerleri onaltılı sayılar şeklinde basılmaktadır. %zu dönüşüm tanımlaması ise size_t tipinde işaretsiz bir tamsayı basmak içindir. Altkısım 3.1.3’te de bahsettiğimiz gibi, iki göstergenin farkı hesaplandığında ortaya çıkan değer ptrdiff_t tipindedir. Böyle bir sayıyı bastırmak için ise, %td dönüşüm tanımlaması kullanılır; buradaki t uzunluk belirteci, beklenen argümanın ptrdiff_t boyutunda olduğunu belirtir.