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.