12 Ağustos 2020 Çarşamba

C programlama gösterici diziler

GÖSTERİCİ DİZİLERİ

Göstericiler de birer nesne olduguna göre gösterici dizileri de tanımlanabilmelidir.
Elemanları göstericilerden oluşan dizilere “gösterici dizileri” (pointer arrays) denir. Bildirimleri aşağıdaki
şekilde yapılır :

<tür> *<dizi ismi [dizi_uzunluğu];>
Örneğin :
char *s[10];
int *sample[50];
float *kilo[10];

Gösterici dizilerinin bildirimleri normal dizi bildirimlerinden farklı olarak * operatörü ile yapılmaktadır. 

Örneğin:
char str[100];
bildiriminde, str 100 elemanlı char türden bir diziyken
char *str[100];

bildiriminde ise, str 100 elemanlı char türden bir gösterici dizisidir.
Derleyici bir gösterici dizisi tanımlaması ile karşılaşınca diğer dizilerde yaptığı gibi, bellekte belirtilen sayıda
gösteriyi tutabilecek kadar ardışıl yer tahsis eder. 
Örneğin:
char *p[10];

bildirimi ile derleyici, s dizisinin 10 elemanlı ve her elemanın char türden bir gösterici olduğunu anlar.
Kullanılan sistemde göstericilerin uzunluğunun 2 byte olduğunu kabul edersek, 20 byte sürekli bir bölge
tahsis edecektir. Bu durumda;
p[0], p[1], p[2], ...p[9]
dizi elemanlarının her biri char türden bir göstericidir. Elemanlarından her biri diğerinden bağımsız olarak
kullanılabilir ve her bir eleman bir nesnedir. Aşağıdaki örneği inceleyiniz :

main()
{
char *s[10];
int k;
for (k = 0; k < 10; ++k)
s[k] = (char *) malloc(30);
if (s[k] == NULL) {
printf("cannot allocate memory!..\n");
exit(EXIT_FAILURE);
}
printf("ismi giriniz : ");
gets(s[k]);
}

Bu örnekte her elemanı char türden bir gösterici olan, 10 elemanlı bir gösterici dizisi açılmış ve dizinin her
elemanı için, döngü içerisinde malloc fonksiyonu ile 30 byte büyüklüğünde bir bellek bloğu tahsis
edilmiştir.Tahsis edilen blokların başlangıç adresleri gösterici dizisinin elemanlarına yerleştirildikten sonra,
gets fonksiyonu ile klavyeden girilen karakterlerin tahsis edilen bloklara aktarılmıştır. s isimli dizi yerel bir dizi
olduğuna göre, dizi elemanları içerisinde rasgele (garbage values) değerler olduğunu belirtelim. Dolayısıyla
malloc fonksiyonu ile yer ayırmadan yapılan veri aktarımları gösterici hatalarına yol açacaktır.
Dinamik olarak tahsis edilen alanlar, gerektiği zaman yine bir 

döngü yardımıyla serbest bırakılabilir :

for (k = 0; k < 10; ++k)
free(s[k]);

gösterici dizilerine ilk değer verilmesi
Normal dizilere ilkdeğer nasıl veriliyorsa gösterici dizilerine de ilk değer aynı biçimde verilir. 

örneğin:
int *p[] = {
(int *) 0x1FC0,
(int *) 0x1FC2,
(int *) 0x1FC4,
(int *) 0x1FC6,
(int *) 0x1FC8
}

Kuşkusuz ki, gösterici dizisine atanan adreslerin bir amaç doğrultusunda kullanılabilmesi için güvenli
bölgeleri göstermesi gerekir. Bu nedenle uygulamada karakter gösterici dizisi dışındaki gösterici dizilerine ilk
değer verilmesi durumuna pek raslanmaz. Gösterici dizilerine ilk değer verme işlemi genellikle karakter
gösterici dizilerine string ifadeleriyle ilk değer verilmesi biçiminde karşımıza çıkmaktadır.
char türden gösterici dizileri
Uygulamalarda en sık görülen gösterici dizileri char türden olan gösterici dizilerdir.
Daha önce stringler konusunda da gördüğümüz gibi, stringler C derleyicisi tarafından char türden adresler
olarak ele alındığına göre, char türden bir gösterici dizisine stringler aracılığıyla ilk değer verilebilir:

char *aylar[] = {“Ocak",
"Şubat",
"Mart",
"Nisan",
"Mayıs",
"Haziran",
"Temmuz",
"Ağustos",
"Eylül",
"Ekim",
"Kasım",
"Aralık"
};

aylar dizisinin her bir elemanı char türden bir göstericidir. Ve bu gösterici dizisine stringler ile ilk değer
verilmiştir. Başka bir deyişle char türden bir gösterici dizisi olan aylar dizisinin her bir elemanı bir yazıyı
göstermektedir.

char türden gösterici dizilerinin kullanılma nedenleri
1. Program içinde sık kullanılacak yazıların her defasında yazılması yerine bir gösterici dizisinin
elemanlarında saklanması. Aşağıdai örnekte err dizisinin her bir elemanında hata mesajlarına ilişkin yazılar
saklanmıştır.

char *err[] = {“Bellek Yetersiz!”, “Hatalı şifre”, “Dosya bulunamadı”, “Belirtilen dosya zaten var”, “ “sürücü
hazır değil”, "Okunacak dosya açılamıyor", "yazılacak dosya açılamıyor!.." “Belirlenemeyen
hata!”};
Artık programın herhangi bir yerinde yazılardan biri yazdırılmak istenirse, yazdırılacak olan yalnızca gösterici
dizisinin herhangi bir elemanında başlangıç adresi tutulan yazıdır :

if (fp == NULL) {
printf("%s\n", err[5]);
return 5;
}.


2. Bazı yazıların bu şekilde bir algoritmaya bağlı olarak kullanılması :

#include <stdio.h>
int dayofweek(int day, int month, int year);
char *aylar[] = {“Ocak",
"Şubat",
"Mart",
"Nisan",
"Mayıs",
"Haziran",
"Temmuz",
"Ağustos",
"Eylül",
"Ekim",
"Kasım",
"Aralık"
};

char *gunler[] = {"Pazar",
"Pazartesi",
"Salı",
"Çarşamba",
"Perşembe",
"Cuma",
"Cumartesi"
};
void display_date(int day, int mon, int year)
{
printf("%02d ", day);
puts(aylar[mon - 1]);
printf(" %d ", year);
}

Bir yazının belirli bir yazıyla aynı olup olmadığını, strcmp fonksiyonuyla saptayabiliriz. Peki bir yazının bir
grup yazı içinde var olup olmadığını nasıl tespit edebiliriz? Aşağıda tanımlanan getmonth fonksiyonu
kendisine başlangıç adresi gönderilen bir yazının ingilizce ay isimlerinden biri olup olmadığını test etmekte,
eğer böyle ise bu ayın kaçıncı ay olduğu bilgisiyle geri dönmektedir. (1 - 12) Fonksiyon, kendisine gönderilen
argumanda başlangıç adresi tutulan yazı bir ay ismine karşılık gelmiyor ise 0 değeriyle geri dönmektedir.

#include <stdio.h>
#include <string.h>
int getmonth(char *str)
{
char *months[] = {"Jan", Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
int k;
for (k = 0; k < 12; ++k)
if (!stricmp(months[k], str)
return k + 1;
return 0;
}
main()
{
char s[20];
int n = 20;
int result;
while (n-- > 0) {
printf("bir ay ismi giriniz .");
gets(s);
result = getmonth(s);
if (result)
printf("%s yılın %d. ayıdır\n", s, result);
else
printf("%s gecerli bir ay ismi değildir\n");
} return 0;
}

stricmp fonksiyonunun iki yazının karşılaştırmasını büyük harf küçük harf duyarlılığı olmadan yapması
dışında, strcmp fonksiyonundan başka bir farkı bulunmadığını hatırlayalım.
Gösterici dizileri de tıpkı diğer diziler gibi yerel ya da global olabilecektir. Eğer dizinin global olması
durumunda dizi elemanlarının hepsinin içinde 0 değerleri olurken, yerel bir gösterici dizisinin içinde rasgele
değerler olacaktır. Dizinin her bir elemanı içinde bir adres bilgisi olduğuna göre, atama yapılmamış global
gösterici dizilerinin her bir elemanı içinde 0 adresi (NULL adresini) bulunurken, atama yapılmamış yerel
gösterici dizilerinin elemanları içinde rasgele değerler bulunmaktadır.
Bir gösterici hatasına neden olmamak için önce gösterici dizisi elemanlarına güvenli adresler yerleştirmek
gerekmektedir. Stringler statik nesneler gibi ele alındıkları için bir gösterici dizisi elemanlarına stringlerle
değer vermek bir gösterici hatasına enden olmayacaktır. Zira stringler, daha önce de belirtildiği gibi önce
derleyici tarafından bellekte güvenli bir bölgeye yerleştirilirler, daha sonra ise yerleştirildikleri bloğun
başlangıç adresi olarak ele alınırlar.




Hiç yorum yok:

Yorum Gönder

Her yorum bilgidir. Araştırmaya devam...