Temel C Programlama -35- İşaretçiler ve Diziler

İşaretçilerin en önemli kullanım alanlarından biri dizilerdir. Diziler derken artık sadece sayıdan ibaret olan dizileri değil bizim “yazı” olarak ifade ettiğimiz karakter dizilerini de hesaba katmamız gerekir. Karakter dizileri bilgisayar programlarında en sık kullanılan veri tiplerindendir. Daha sonra ayrıntılı olarak ele alacak olsak da karakter dizileri C dilinde String veya başka bir sınıfta ayrı bir veri tipi olarak yer almaz ve saf haliyle bizim karşımıza çıkar. Veri tipleri de hakeza öyledir siz yapı tipleri ile bunu sıfırdan tanımlarsınız. C dilinin en güzel yanlarından biri eğer harici bir kütüphane veya program çatısı kullanmıyorsanız her şeyi sıfırdan yapar oluşunuzdur.

Bütün bu veri işlemenin temellerine indiğimizde ise işaretçilerin ve dizilerin beraber kullanımını görürüz. Daha önceki başlıkta ifade ettiğimiz gibi işaretçiler üzerinde aritmetik işlem yaparak farklı dizi elemanlarına erişebiliyorduk. Şimdi konumuzu daha ilerleyerek devam edecek olsak da öncelikle işaretçi tiplerinin neler olabileceğini sizlere hatırlatmak istiyoruz.

İşaretçi Tipleri

Biz bir işaretçi tanımladığımızda normal değişkenden farklı olarak değişken adının başına “*” işareti getirilmektedir. Bu sayede int *p; yazdığımız zaman tam sayı tipinde bir işaretçi tanımlamış oluruz. Bu işaretçi sadece tam sayı tipindeki değişkenleri işaretleyebilir. O halde her değişken tipi için ayrı işaretçi olması gerektiğini düşünebilirsiniz. Bu konuda haklısınız. Bazı işaretçiler şöyle olabilir.

int *ip;
float *fp;
double *dp;
char *cp;
long *lp;

İşaretçiler sadece bununla sınırlı kalmayıp aynı zamanda işaretçi dizileri veya işaretçi yapıları da olabilir. Örneğin şu şekilde bir işaretçi dizisi tanımlayabiliriz.

int *ptr [3];

Şimdilik yapı tiplerini görmesek de istersek yapı tipinde veya typedef olarak kullanıcının adlandırdığı yapı tipinde bir işaretçi tanımlamamız mümkündür. Bu işaretçi kullanıcının belirlediği yapıyı işaret eder. Veri yapılarını görürken bunun çok önemli olduğunu anlayacaksınız.

struct yapi *ptr_yapi;

Şu an yapılara geçmediğimiz için sadece örneğini vermekle yetiniyorum. Görüldüğü gibi hangi değişkeni veya yapıyı tanımlarsak tanımlayalım aynı zamanda bunun işaretçisini tanımlamamız da mümkündür.

İşaretçiler ve Diziler

İşaretçiler özellikle karakter dizileri üzerinde işlem yaparken bize büyük kolaylık sağlamaktadır. Tek tek karakterler üzerinde işlem yapılacaksa hem fonksiyona dizi işaretçi olarak aktarılmakta hem de dizinin değerlerinin kopyası üzerinden değil de adresleri üzerinden işlem yapılmaktadır. Bu da programı daha kısa ve performaslı hale getirecektir. Sadece öğreneceğimiz birkaç şey ile bizim elimizde oldukça pratik bir araç olacak ve programlamada kolaylık sağlayacaktır. Bunun nasıl olacağını size bir örnek ile gösterelim. Örneğin elimizde büyük ve küçük harflerle karışık bir yazı var ve biz bunu daha okunaklı büyük harflere dönüştürmek istiyoruz. Bunun için şöyle bir program kullanacağız.

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

void buyuk_harf( char *string );
int main(int argc, char *argv[]) {
	char string[] = "BuRaDa ApacHi GiBi YaziOz MoRuQ";
	printf("Cevirmeden Onceki String: %s \n", string);
	buyuk_harf(string);
	printf("Cevirdikten Sonra String: %s \n", string);
	
	return 0;
}

void buyuk_harf (char *string)
{
	while (*string != '\0')
	{
		*string = toupper( *string );
		++string;
	}
}

Programı çalıştırdığımızda ekran görüntüsü şu şekilde olacaktır.

Şimdi programın ne işe yaradığını ve nasıl çalıştığını bütün ayrıntısıyla inceleyelim. Bu programın tek amacı string adındaki karakter dizisine girilen değer ne olursa olsun bunun bütün harflerini büyük harflere çevirmektir. İstersek tamamı küçük harf istersek de yukarıdaki örnek gibi birbirine karışmış harflerden oluşabilir. Bu program bu sayede 10 yaşındaki bir gencin yazısını caps lock’u açık unutan bir ihtiyarın yazısına çevirebilir. 🙂 Şimdi satır satır programın önemli kısımlarını açıklayarak bunu nasıl yaptığını sizlere anlatalım.

#include <ctype.h> C standart kütüphanesinde ctype.h adında bir başlık dosyası bulunmaktadır. Bu başlık dosyasında karakterlerle alakalı özel fonksiyonlar yer alır. Buradaki bütün fonksiyonlar karakterlerle (char) alakalı fonksiyonlardır. Örneğin karakterin sayı olup olmadığı, büyük olup olmadığı, küçük olup olmadığı büyükse küçültme veya küçükse büyültme gibi metin işlemle alakalı fonksiyonlar yer almaktadır. Bu fonksiyonlar teker teker karakter bazlı olmakta. Yani bunları bir cümle gibi bir karakter dizisine uygulamak için bir algoritma geliştirmemiz gerekmekte. Biz de burad toupper() yani büyük harf yap fonksiyonunu kullanabilmek için ctype.h dosyasını programa dahil ettik.

void buyuk_harf( char *string );

Normalde buna baktığınızda sadece bir char tipine ait bir *string adında işaretçi görürsünüz değil mi? Ama C dilinde karakter işaretçilerinin farklı bir yeri bulunmakta ve char *string bir karakter dizisi işaretçisi olmaktadır. char *string ile karakter dizisi olarak alınan argümanın birinci elemanına işarette bulunulur. Biz istersek C dilinde şu şekilde bir karakter dizisi tanımlaması da yapabiliriz.

char *string = "string";

Bu tanımlama normal dizilere göre derleyici tarafından farklı olarak ele alınmakta ve daha hızlı olmaktadır. Sabir değerleri bu şekilde kullanmak daha performanslıdır. Yeni standartlarla beraber bunun başına const getirilmesi gerektiğini unutmayın.

buyuk_harf(string); Burada string diyerek karakter dizisini fonksiyona göndersek de bunun adres mi yoksa dizinin kopyası mı olacağını fonksiyonun aldığı argüman tipi belirlemektedir. Eğer char * string yerine char string [] diye bir değer alsaydı bu sefer dizinin değerlerini argüman olarak alacaktı. Ama char *string diyerek dizinin adres değerini argüman olarak almaktadır.

while (*string != ‘\0’) Burada *string ile dizinin değerlerine erişilmiş ve ‘\0’ karakteri denetlenmiştir. C dilinde biz koymasak bile derleyici otomatik olarak dizinin sonuna \0 karakterini koymaktadır. Bu karakter dizinin bittiğini bildirmektedir. Aksi halde dizinin bittiğinden haberimiz olmaz. Bu özel karakter aynı bize yazının bittiğini gösteren nokta işareti gibi görev yapmaktadır. Karakter dizileri üzerinde çalışırken yazacağımız her programda hemen hemen \0 karakterinin denetimini yapmak zorunda kalırız. Önceden de söylemiştik, C dilinde her şeyi siz yapmak zorunda kalıyorsunuz.

*string = toupper( *string ); Burad toupper() fonksiyonundan dönen değer ilgili dizi elemanına * erişim operatörü vasıtasıyla yükleniyor. Aslında burada yapılan işlem oldukça basit. Dizinin ilgili elemanı işaretçi erişim operatörü ile okunur ve bu toupper() fonksiyonu ile büyük harfe çevrildikten sonra tekrar aynı elemana yerleştirilir.

++string; Görüldüğü gibi işaretçi aritmetiği burada da karşımıza çıkmakta. Aslında programın en önemli özelliklerinden biri olarak işaretçilerin bir dizi üzerinde işlem yapabilmesini sağlamakta. Eğer bu olmasaydı tek bir karakter üzerinde işlem yapmaktan öte geçemezdik. Her döngü sırasında sıra ile birer birer artırılarak bütün dizi üzerinde işlem yapmamızı sağlıyor. Her bir artırıldığında bir sonraki dizi elemanını göstermekte bu işaretçi.

Bir sonraki yazımızda konumuza devam edeceğiz. Sıkılıyor musunuz bilmiyorum ama ben yazarken eğleniyorum. Böyle kafa yoracağınız zor konular işi daha eğlenceli kılıyor. Programcılıkta bana kalırsa en sıkıcı şey tek düzelik ve sıradanlıktır.

Last updated