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.