Temel C Programlama -43- Formatlı Giriş ve Çıkış

Formatlı giriş ve çıkış C dilinin en kolay konularından biri olmasına rağmen yeni başlayanlar için biraz kafa karıştırıcı gelebilir. Biz aslında “Merhaba Dünya!” uygulamasından beri formatlı giriş ve çıkış işlemlerini kullanmaktayız. Formatlı giriş ve çıkış hiç yabana atılacak bir özellik değildir ve C dilinin en kullanışlı özelliklerinden biridir. Ama yeni başlayanlar bunun ayrıntısından dolayı biraz karmaşık bulmakta ve çok da fazla beğenememektedir. Bazı dillerde de bu giriş ve çıkış işlemi basitleştirilmiştir. Örneğin C++ dilinde bile cout ve cin komutları ile format girmeden giriş ve çıkış yapabilmekteyiz. Ama bir kere formatlı giriş ve çıkış işlemlerinin gücünü ve kullanışlılığını gördükten sonra onu seveceğinizi umuyoruz.

Akışlar

C dilinde bütün giriş ve çıkış işlemleri akışlar (stream) ile yapılmaktadır. Bu akışlar bir sıralanmış baytlardan oluşmakta ve fonksiyona göre yönlendirilmesi yapılmaktadır. Örneğin girişte klavyeden girilen karakterlerin sırası, dosyadan okunan bayt sırası veya ağ bağlantısından gelen baytlar akışlara örnektir. Program çalışmaya başladığında üç adet akış otomatik olarak programa bağlanmaktadır. Bunlardan biri standart giriş akışı olup klavyeye bağlıdır (stdin), diğeri standart çıkış akışı olup monitöre (konsol ekranına) bağlıdır (stdout) ve sonuncusu ise standart hata akışı olup hata mesajlarını içermektedir (stderr). İşletim sistemi bu akışları başka aygıtlara yönlendirme yeteneğine sahiptir.

printf fonksiyonu

Baştan beri gördüğümüz printf() fonksiyonu formatlı çıkış elde etmemizi sağlayan fonksiyondur. Yukarıda belirtildiği üzere standart çıkışa (stdout) bağlıdır ve format belirteçleri ile aldığı argümanları karakter dizisi olarak yazdırmaktadır. printf() fonksiyonunun iç kısmına baktığımızda oldukça karmaşık bir format çözümleme ile en sonunda işletim sistemine karakter dizilerinin gönderildiğini görürüz. printf() fonksiyonu formatlı çıkış almak için tek fonksiyon değildir. sprintf() ve fprintf() gibi aynı işleve sahip fakat farklı noktalarda çıkış aldığımız fonksiyonlar da mevcuttur. sprintf() önceden söylediğimiz gibi karakter dizisine aynı printf() fonksiyonu gibi formatlı bir çıkış vermekte, fprintf() ise ileride göreceğimiz dosyalara formatlı bir çıkış vermektedir.

Şimdiye kadar printf() fonksiyonu için farklı format belirteçlerini kullandık. Bunları da değişken tiplerini verdiğimiz sıra tablo içerisinde size vermiştik. Örneğin tamsayı yazdıracağınız zaman %i, float değer yazdıracağınız zaman %f (aslında burada float double’a çevirilir.), işaretçi yazdıracağınız zaman %p, karakter dizisi yazdıracağınız zaman da %s gibi belirteçleri kullanmaktaydık. Bazen printf() fonksiyonu bu format belirteçleri ile tip dönüşümü de yapabilmektedir.

Fakat printf() fonksiyonu bu kadar basit bir fonksiyon olmakla sınırlı kalmamaktadır. Belirteçlerin yanında bayraklar, genişlik, ondalık hane gibi özellikler de yer almaktadır. Aynı zamanda kaçış sekansları adı verdiğimiz (escape squence) karakterlerle özel komutlar işletilmektedir. Bu sayede örneğin ondalıklı sayıları yuvarlatabilir, çıkışı sağa veya sola hizalayabilir veya ondalıklı değerleri bilimsel formatta gösterebiliriz.

Öncelikle printf() fonksiyonunun prototipini sizlere gösterelim.

int printf ( const char * format, ... );

Biz printf() fonksiyonundan dönen değeri şimdiye kadar okumasak da aslında printf() fonksiyonunun int tipinde bir sayı değerini geri döndürdüğünü görmekteyiz. Bu geri dönen değer yazdırma başarılı ise kaç karakterin yazdırıldığına dair bir pozitif değer olmaktadır. Eğer yazdırma başarısız ise negatif değer dönmektedir. Bu değer hata denetleme için kullanılabilir.

Burada const char * format tipini hepimiz biliyoruz. Bu bir karakter dizisi. printf() fonksiyonunu kullanırken ilk argümanın her zaman bir karakter dizisi sabiti olarak çift tırnak arasında yazıldığını gördük. “Merhaba %s” gibi yazılan değer hiç bir zaman değişmiyor. O yüzden const char *format olarak değeri almakta. Burada asıl mesele ikinci argümandır. Gördüğünüz gibi orada herhangi bir değer yazmamakda ve sadece üç nokta (…) yer almakta. Bu aldığı argümanların herhangi bir sınırı olmadığını göstermektedir. Değişken argümanlar (variable arguments) adı verilen bu özellik C dilinde mevcuttur ve biz de fonksiyonları bu şekilde yapabiliriz. İlerleyen konularda anlatacağımız için şimdiden kafanızı karıştırmak istemiyoruz.

Şimdi printf() fonksiyonun aldığı format belirteçlerini bir tablo halinde size verelim.

Belirteç

Çıkış

Örnek

d ya da i

İşaretli tam sayı (signed int)

300

u

İşaretsiz tam sayı (unsigned int)

5000

o

İşaretsiz oktal

640

x

İşaretsiz onaltılık tamsayı (küçük)

ff0

X

İşaretsiz onaltılık tamsayı(büyük)

FF0

f

Onluk ondalıklı sayı (float, küçük)

320.15

F

Onluk ondalıklı sayı (float, büyük)

300.25

e

Bilimsel notasyon, küçük

3.12e+2

E

Bilimsel notasyon, büyük

3.12E+2

g

%e ya da %f’nin en kısa temsili

3.14

G

%E ya da %F’nin en kısa temsili

3.14

a

Onaltılık ondalıklı sayı, küçük

-0xc.90FEA-2

A

Onaltılık ondalıklı sayı, büyük

-0XC.90FEA-2

c

Karakter

c

s

Karakter dizisi

Arduinocu

p

İşaretçi Adresi

0FFA005B

n

Birşey yazdırılmaz.

%

Peşine gelen % işareti ekranda yazdırılır.

%%

Burada kadar anlamadığımız bir nokta yok. Zaten derslerin başından veri bunları kullanıyoruz. Kullanmadığımız bazı format belirteçleri yer alsa da bunları siz rahatlıkla ihtiyaç duyduğunuz zaman kullanabilirsiniz. Formatlamada belli bir söz dizimi takip etmek zorunda olduğunuzu unutmayın. Eğer sıraya uygun formatı yazmazsanız doğru formatlanmayacaktır. Bunun söz dizimi şu şekildedir.

%[bayraklar][genişlik][.hane][uzunluk]belirteç

Burada % işaretini ve belirteçleri biliyoruz fakat karşımıza bayraklar, genişlik, hane ve uzunluk gibi değerler çıkmakta. Şimdiye kadar bunlardan size bahsetmedik ve bunları hiç kullanmadık. Artık sıra printf() fonksiyonunu tam anlamıyla öğrenmeye geldi.

Bayraklar

Bayraklar formatlı giriş ve çıkışta önemli bir yere sahiptir. Verinin nasıl hizalanacağı, nasıl işaretleneceği, nasıl belitileceği gibi konuları bayraklar vasıtasıyla belirtiriz. Bayrakları şu şekilde özetleyebiliriz

Bayrak

Açıklama

Belirtilen alan genişliği içerisinde veriyi sola hizalama. Normalde sağa hizalanmaktadır.

+

Yazdırılan verinin başına pozitifse (+) negatifse (-) işaretini koymaya zorlar. Normalde sadece negatif sayılarda (-) işaretini görürüz.

(boşluk)

Eğer herhangi bir işaret yazılmazsa değerden önce boş bir karakter eklenir.

#

o, x ve X belirteçleri ile kullanılır. Bu oktal ve onaltılık sayıları belirtmek için önek koyar. Örneğin hex sayı için 0xFF gibi. Ondalıklı sayılarda ise düz sayi olsa bile noktasını belirtir. Örneğin 32.00 gibi.

0

Sol taraftaki boşluklar sıfır ile doldurulur boşluk yerine.

Şimdi “-” bayrağı ile ilgili bir uygulama yapalım. “-” bayrağının düzgün çalışması için öncelikle bir boşluk yani hücre tanımlamamız gereklidir. Aynı tablodaki hücrelerde olduğu gibi printf() ile tanımladığımız hücrelerde de veriler sola ya da sağa hizalı yazdırılabilir. Burada hücrenin uzunluğu karakter sayısı olarak ele alınmaktadır. Sonrasında ise sola hizalamak için (-) yazıyoruz ve sağa hizalamak için ise boş bırakıyoruz. Örnek programımız şu şekildedir.

#include <stdio.h>
#include <string.h>

main()
{
	int sayi1 = 200;
	int sayi2 = 2000;
	int sayi3 = 20000;
	int sayi4 = 200000;
	int sayi5 = 2000000;
	printf ("%-10i \n", sayi1);
	printf ("%-10i \n", sayi2);
	printf ("%-10i \n", sayi3);
	printf ("%-10i \n", sayi4);
	printf ("%-10i \n", sayi5);
	printf ("%10i \n", sayi1);
	printf ("%10i \n", sayi2);
	printf ("%10i \n", sayi3);
	printf ("%10i \n", sayi4);
	printf ("%10i \n", sayi5);
}

Burada güzel gösterebilmek adına beş adet farklı basamaklarda sayı değişkeni tanımladık ve bunları ilk önce %-10i formatında gösterdik. Bu bilgisayara “Bana 10 karakterlik bir hücre ayarla ve sola hizalı olarak tam sayı yazdır.” demenin kısa yoludur. Burada 10 yazarak değerin yazdırılacağı boşluğun genişliğini belirlemiş olduk. Sonrasında ise yine normal bir şekilde değerleri yazdırdık. Bu sefer sola hizalı değil de sağa hizalı olarak yazdırıldı. Önemli nokta burada belli bir genişlik değerinin verilmesidir. Genişlik değeri olmadan sola ya da sağa hizalamanın bir anlamı kalmayacaktır. Programın ekran görüntüsü şu şekildedir.

Şimdi “+” bayrağını kullanmak için ufak bir program yazalım ve nasıl çalıştığını görelim.

#include <stdio.h>
#include <string.h>

main()
{
	int sayi1 = 200;
	int sayi2 = -300;
	printf("Sayi1 = %+i \nSayi2 = %+i", sayi1, sayi2);
}

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

Anlatmaya gerek yok görüyorsunuz. 🙂 Bu bayrak sadece pozitif ve negatif sayıları daha belirgin gösterebilmek adına pozitif sayıların önüne + işareti koymakta. Bir gün gelir de bu şekilde yazdırmanız gerekirse böyle bir özelliğin olduğunu bilin.

Genişlik kısmını (width) yukarıda gösterdiğim için tekrar tekrar göstermeyeceğim. Yukarıda bazı bayraklar için kendiniz örnek yapıp deneyebilirsiniz. Bunlar çok sık kullanılan özellikler olmadığı için mümkün mertebe önemsiz örnekler vermemeye çalışıyorum. Burada aslında en önemli noktalardan birisi ondalıklı sayıların nasıl gösterileceğidir. Örneğin biz PI sayısını 3.14 olarak da gösterebiliriz 3.14159265359 olarak da gösterebiliriz. Bu durumda bazen istemediğimiz haneler hesaba katılabilir. Bunun için yuvarlama işlemi yapılmaktadır. Ondalık sayılarda noktadan sonra kaç hane gösterileceğine precision adı verilmektedir. Bu terim hassasiyet ve doğruluk için de elektronikte kullanılmaktadır.

Ondalık sayılar için şu şekilde bir format belirteci kullanılır;

%.sayif

Yani biz %.2f yazdığımızda virgülden sonraki iki hane gösterilir, %.5f yaptığımızda ise virgülden sonraki beş hane gösterilir. Geri kalan sayılar ise yuvarlatılır.Bu yuvarlama işleminden sonra 3.14… diye devam eden bir sayı 3.15 olarak yazdırılabilir ve böyle işlem yapılabilir. Hassas işlemlerde buna dikkat etmeniz çok önemlidir. 5’i 2’ye bölerken tam sayı kullanmamanız gerektiğini şimdiye kadar öğrenmiş olmalısınız. C dilinde ondalıklı sayılarla ilgili ikinci en önemli tüyo da budur. Şimdi yuvarlama işleminin nasıl yapıldığını görmek için bir örnek yazalım.

#include <stdio.h>
#include <string.h>

main()
{
	float pi = 3.14159265;
	printf("%.2f \n", pi);
	printf("%.3f \n", pi);
	printf("%.4f \n", pi);
	printf("%.5f \n", pi);
	printf("%.6f \n", pi);
	printf("%.7f \n", pi);
}

Program çalıştığında ekran görüntüsü şöyle olacaktır.

Görüldüğü gibi burada bir yerde 3.142 derken bir yerde 3.1416 demektedir. O da aslında 3.1415 olması gerekirken yuvarlama sonucunda bu değeri almıştır. Buna dikkat ettiğiniz sürece ondalıklı sayıların gereksiz basamaklarından kurtulmak için müthiş bir özellik olduğunu söyleyebiliriz.

Kaçış Sekansları

Kaçış sekansları printf() fonksiyonunun karakter dizisi sabiti içerisinde yer alan ve fonksiyon içerisinde bazı karakterleri yazdırmak için veya bazı komutları işletmek için kullanılan özel karakterlerdir. Bunlardan yeni satıra atlamak için “\n” sekansını sıkça kullandığımızı biliyorsunuz. Bunları da lazım olunca kullanacağınız için sadece tablosunu vermekle yetinelim.

Kaçış Sekansı

Açıklama

\’

Tek tırnak işareti (‘) yazdırır.

\”

Çift tırnak işareti (“) yazdırır.

\?

Soru işareti (?) yazdırır.

\\

Backslash işareti (\) yazdırır.

\a

Bilgisayardan uyarı sesi gelir. (Bende Windows’dan uyarı sesi geliyor. Eski sistemlerde PC hoparlöründen bip sinyali alınabilir veya sisteme göre değişir.)

\b

İmleci bir karakter geriye götürür.

\f

İmleci bir sonraki mantıksal sayfanın başına götürür

\n

İmleci yeni satıra götürür.

\r

İmleci mevcut satırın başına götürür.

\t

Yatay satır atlama (tab)

\v

Dikey satır atlama

Artık C formatlarına dair anlatacağımız bir konu kalmadı. Artık C dilinin çoğu konusunu bitirdiğimizi söyleyelim ve bir sonraki konumuza geçelim.

Last updated