Bu yazımızda standart
printf, fprintf ve sprintf fonksiyonlarını inceleyeceğiz; bu fonksiyonlar arasındaki
temel benzerliklere ve farklılıklara değineceğiz. Fonksiyonların isimlerinin
birbirine oldukça yakın olmasının yanı sıra, yaptıkları işler de birbirine benzerdir.
Öncelikle bu fonksiyonların hepsinin standart kütüphanelerde tanımlı olduğunu
belirtmekle işe başlayalım. Bir programlama dilini yeni öğrenmeye başladığımızda
yaptığımız bir "merhaba dünya" örneği vardır :
#include
<stdio.h> //... int main () {
    printf("Merhaba Dünya\n");
}
|
* printf
Fonksiyonu :
Standart printf
fonksiyonu, C programcıları tarafından en çok çağrılan standart fonksiyonlardan
birisidir. Bu fonksiyonun prototip bildirimi stdio.h başlık dosyasında yer alır
ve yaptığı iş parametre olarak belirttiğimiz bir takım ifadeleri, bizim belirttiğimiz
biçimde (formatta) ekrana yazdırmaktır. Özel bir karaktere rastlamadığı müddetçe,
belirttiğimiz ifadeleri ekranda yan yana olacak şekilde yazar ve yazım bittiğinde
de yeni satıra geçmez. Yukarıdaki örnekte biz "\n" yazarak, fonksiyonun
belirttiğimiz karakter katarını yazdıktan sonra imleci alt satıra geçirmesini
sağladık. Bu şekilde "\" ters bölü karakteri ile başlayan ifadelere
çıkış dizileri denilmektedir. "\n" çıkışı da yeni bir satıra geçilmesini
sağlar. Çıkış karakterleri şunlardır :
Çıkış
|
Anlamı
|
\0
|
null
karakteri temsil eder (sonlandırıcı karakter) |
\n
|
Yeni
satır |
\r
|
Satırbaşı |
\t
|
Yatay
sekme |
\v
|
Düşey
sekme |
\f
|
İleri
besleme |
\b
|
Geri
boşluk (space) |
\a
|
Alarm
karakteri |
\"
|
Çift
tırnak |
\\
|
Ters
bölü |
Standart printf
fonksiyonunun prototip bildirimi genel olarak şu şekildedir :
int printf
(char *format,...); |
"format"
ismindeki parametre, çıktıyı nasıl bir biçimde görmek istediğimizi belirtir.
Biçim tanımlamak için, önceden belirlenmiş bir takım ifadeler kullanılır. İkinci
parametre ise "..." olarak belirtilmiştir. Bu da, fonksiyonun sonsuz
sayıda parametre alabileceği anlamına gelir. Geri dönüş değeri ise, ekrana yazılması
başarılı olmuş karakter sayısını ifade eder. Ancak bu değer, çok özel durumlar
söz konusu olmadığı takdirde pek kullanılmaz. printf fonksiyonu, kaç tane parametre
geçtiğimizi ve bu parametrelerin türlerini ilk argümanına bakarak anlar. Biçim
belirten ifade, genel olarak bir "%" karakterinden ve bunu izleyen
bir dönüşüm karakterinden oluşur. Ayrıca biçim ifadesinin içine, sola - sağa
yaslama, noktadan sonra x basamak yaz vb gibi isteklerimizi belirten karakterler
de ekleyebiliriz. Fonksiyon, özel bir biçimde ifade ettiğimiz bu karakter katarını
okuyarak çözümler.
d |
int türden
bir ifadeyi onluk sistemde yazar |
ld |
long türden
bir ifadeyi onluk sistemde yazar |
o |
unsigned int
türden bir ifadeyi sekizlik sistemde yazar |
x, X |
unsigned int
türden bir ifadeyi onaltılık sistemde yazar; x için küçük harfleri, X için
büyük harfleri kullanır |
lx |
unsigned long
türden bir ifadeyi onaltılık sistemde yazar |
c |
int
veya char türden bir ifadeyi karakter olarak yazar |
s |
char * türden
bir ifadeyi null karakter ile karşılaşıncaya kadar, ya da duyarlılıkla belirtilen
sayı kadar yazar |
u |
unsigned int
türden bir ifadeyi onluk sistemde yazar |
f |
double türden
bir ifadeyi yazar |
lf |
double veya
long double türden bir ifadeyi onluk sistemde yazar |
e |
gerçek sayıları
üstel olarak yazar |
% |
dönüştürülmez,
% olarak yazdırılır |
Gerçek sayıların
yazdırılmasında, noktadan sonra yazılacak basamak sayısı vb durumların ifade
edilmesi için ve tamsayıların aynı hizada yazdırılması için nokta operatörü
veya rakamlar kullanılır. Aynı şekilde karakter katarlarının sağa ya da sola
dayalı yazdırılması için veya bir karakter katarındaki karakterlerin kaç tanesinin
yazdırılacağını belirtmek için de yine nokta, eksi gibi operatörlerin ve rakamların
çeşitli kombinasyonları kullanılır. Biçimlendirme ifadelerini örnekler üzerinde
inceleyelim :
//ÖRNEK
1 :
int a = 1,
b = 10, c = 100;
printf("%d\n",a);             
// 1
printf("%d\n",b);             
// 10
printf("%d\n",c);             
// 100
//ÖRNEK
2 :
int a = 1, b = 10, c = 100;
printf("%3d\n",a);            //
   1
printf("%3d\n",b);            //
  10
printf("%3d\n",c);            //
100
//ÖRNEK
3 :
int a = 1, b = 10, c = 100;
printf("%.3d\n",a);           //
001
printf("%.3d\n",b);           //
010
printf("%.3d\n",c);           //
100
|
//ÖRNEK
4 :
double a = 1.0, b = 10.0, c = 100.0;
printf("%f\n",a);             
// 1.000000
printf("%f\n",b);             
// 10.000000
printf("%f\n",c);             
// 100.000000
//ÖRNEK
5:
double a = 1.0, b = 10.0, c = 100.0;
printf("%.3f\n",a);             
// 1.000
printf("%.3f\n",b);             
// 10.000
printf("%.3f\n",c);             
// 100.000
//ÖRNEK
6:
double a = 1.0, b = 10.0, c = 100.0;
printf("%7.3f\n",a);             
//    1.000
printf("%7.3f\n",b);             
//   10.000
printf("%7.3f\n",c);             
// 100.000
|
Tamsayı ifadeleri
yazdırırken "%d" ifadesinde d’nin önüne koyduğumuz rakam, sayının
kaç basamaklık bir bölgeye yazılacağını ifade eder. Yukarıda ikinci örnekte
"%3d" yazarak tamsayı değişkenlerin değerlerinin üç basamaklık bir
bölgeye yazılmasını sağladık. Üçüncü örnekte basamak ifade eden rakamın önüne
bir de nokta ekledik ve biçimlendirme ifadesini "%.3d" şeklinde yazdık.
Çıktımızda tamsayı değişkenlerin değerleri üç basamaklık bir bölgeye yazıldı
ve boş kalan yerlere sıfır yazıldı. Gerçek sayıları yazdırırken eğer sadece
"%f" biçiminde bir ifade kullanılırsa, yani ifadede herhangi bir rakam
belirtilmezse çıktımızda basamak duyarlılığı altı olarak alınacaktır. (Varsayılan
olarak noktadan sonra altı basamak yazılır) Eğer biçimlendirme ifadesini "%.3f"
biçiminde yazarsak noktadan sonra üç basamak yazılacaktır. Bu ifadede, noktadan
önce bir de rakam belirtirsek, örneğin yukarıdaki altıncı örnekte olduğu gibi
"%7.3f" şeklinde bir ifade kullanırsak, hem noktadan sonra üç basamak
yazılır hem de değerler yedi basamaklık bir alana yazılarak hizalanır. İlave
olarak burada "%07.3f" şeklinde bir ifade yazarsak, yine değerler
üç basamak duyarlıklı olarak yedi basamaklık bir alana yazılacak, ancak bu defa
boş kalan basamaklar yerine bir de sıfır yazılacaktır. (001.000 gibi) Peki karakter
katarlarının biçimlendirmesini nasıl yapabiliriz ?
//ÖRNEK
1 :
char *str
= "CSharp Nedir?";
printf("*%s*",str);             
//*CSharp Nedir?*
//ÖRNEK
2 :
char *str
= "CSharp Nedir?";
printf("*%.6s*",str);           //*CSharp*
//ÖRNEK
3 :
char *str
= "CSharp Nedir?";
printf("*%-20s*",str);          //*CSharp
Nedir?       *
|
//ÖRNEK 4 :
char *str
= "CSharp Nedir?";
printf("*%-20.6s*",str);          //*CSharp
             *
//ÖRNEK
3 :
char *str
= "CSharp Nedir?";
printf("*%20.6s*",str);         
 //*             
CSharp*
|
Karakter katarlarını
biçimlendirirken sadece "%s" yazdığımızda, str değişkenindeki ifade
olduğu gibi yazılıyor, burada herhangi bir biçimlendirme yoktur. Eğer nokta
(.) ile bir rakam kombinasyonu yazılırsa bu durumda, karakter katarımızın belirtilen
sayı kadar karakteri yazdırılır. "%.6s" durumunda karakter katarının
içindeki ilk altı karakter yazdırılmıştır. Eğer nokta yerine eksi (-) kullanılırsa
bu durumda da, belirtilen sayı kadar bir alana sola dayalı biçimde yazdırma
işlemi yapılır. Nokta, eksi ve rakam bir arada kullanılırsa, örneğin "%-20.6s"
gibi, bu durumda noktadan önce belirtilen rakam kadar bir alana, karakter
katarının noktadan sonra belirtilen rakam kadar karakteri sola dayalı biçimde
yazdırılır. Eğer eksi kullanılmazsa, örneğin "%20.6s" ifadesinde olduğu
gibi, bu durumda yine noktadan önce belirtilen rakam kadar bir alana, karakter
katarının noktadan sonra belirtilen rakam kadar karakteri sağa dayalı biçimde
yazdırılır. Bu şekilde biçimlendirmeler kullanarak çıktıyı görmek istediğimiz
şekle getiririz.
* fprintf
Fonksiyonu :
Şimdi fprintf fonksiyonunu
inceleyelim. Fonksiyonun prototip bildirimi, stdio.h başlık dosyasında yapılmıştır.
int fprintf(FILE
*fp,const char *format, ...); |
fprintf fonksiyonu
dosya işlemleri yapan fonksiyonlardan birisidir. Aslında printf fonksiyonuna
oldukça benzer. Bu fonksiyon da parametre olarak geçtiğimiz değerleri, parametre
olarak geçtiğimiz biçimlendirme ifadesine göre yazar. printf fonksiyonu ekrana
yazma işlemi yapıyordu, işte fprintf fonksiyonu bu noktada printf fonksiyonundan
farklıdır. fprintf fonksiyonu, yazması gereken bilgiyi ekrana değil, ilk parametresi
fp dosya göstericisinin işaret ettiği dosyaya yazar. Bu özelliği haricinde printf
fonksiyonu gibidir. fprintf fonksiyonu çağrılmadan önce elimizde başarıyla açılmış
ya da yaratılmış bir dosyaya işaret eden dosya göstericisi bulunmalıdır. Şimdi
elimizde ay isimlerinin tutulduğu (char *) türünden bir dizi olduğunu düşünelim
ve bu dizinin elemanlarını birer birer dosyaya yazalım. Yazma işlemi için de
fprintf fonksiyonunu kullanarak fonksiyonun çalışma şeklini kavramaya çalışalım.
#include <stdio.h>
#include <stdlib.h>
#define MONTH_NUMBER
12
char *ptr
[] = {"Ocak","Subat","Mart","Nisan","Mayis","Haziran",
"Temmuz","Agustos","Eylul","Ekim","Kasim","Aralik"};
int main()
{
    FILE *fp;
    int i;
    fp = fopen("aylar.txt","w");
    if (!fp) {
       printf("aylar.txt dosyasi olusturulamadi,
program sonlandiriliyor...\n");
       exit(EXIT_FAILURE);
    }
    for (i = 0; i < MONTH_NUMBER; ++i)
       fprintf(fp,"%2d. ay : %s\n",i+1,ptr[i]);
    fclose(fp);
    return 0;
}
|
Programımızı inceleyelim
: Önce global düzeyde ptr isimli (char *) türünden bir dizi tanımladık ve dizinin
elemanlarına ay isimlerini atadık. Programın ana bloğu içerisinde (FILE *) türünden
bir gösterici tanımladık. Standart fopen fonksiyonu ile "aylar.txt"
isminde bir dosyayı yazma modunda açtık. Dosya açma işleminin başarısını fp
göstericisinin NULL değere sahip olup olmaması koşuluna göre kontrol ettik.
Eğer gösterici NULL değere sahip ise "!fp" ifadesi doğru olacaktır.
Bu durumda bir hata mesajı vererek programı sonlandırdık. Eğer dosya başarıyla
açılmışsa işlemlere devam ettik. Bir for döngüsü kurduk. Bu döngü, dizimiz 12
elemanlı olduğu için 12 kez dönecek. Döngünün her adımında fprintf fonksiyonunu
çağırdık. Fonksiyonun ilk parametresi olarak fp dosya göstericisini yazdık.
Yazmak istediğimiz ifadeler, fp göstericisinin gösterdiği dosyaya, yani "aylar.txt"
dosyasına yazılacak. fprintf fonksiyonunun ikinci ve üçüncü parametreleri, printf
fonksiyonuna gönderdiğimiz birinci ve ikinci parametre gibidir. fprintf fonksiyonuna
ikinci parametre olarak biçimlendirme ifadesini yazdık. Önce ayın, yılın kaçıncı
ayı olduğu bilgisi iki karakterlik bir alana, sonrada o aya ilişkin isim yazılıyor
ve alt satıra geçiliyor. Bu programı, çalıştırılabilir dosyasından çalıştırdığınızda,
o dizinde "aylar.txt" isminde bir dosya yaratılacaktır. Bu dosyayı
açarak ifadelerin doğru yazılıp yazılmadığını kontrol edebilirsiniz.
Bir C programı
başlatıldığında, işletim sistemi otomatik olarak üç dosya açar ve bu dosyaların
atandığı üç dosya göstericisi yaratır. Bu dosya göstericileri stdin, stdout
ve stderr olarak isimlendirilmiştir; bildirimleri sdtio.h başlık dosyasında
yer alır. Bu göstericilerden stdin klavyeye, stdout ve stderr ekrana bağlanmıştır.
Biz fprintf fonksiyonuna ilk parametre olarak bu göstericilerden birini de geçebiliriz.
Örneğin fprintf fonksiyonunun, tıpkı printf fonksiyonu gibi ekrana yazma yapmasını
istiyorsak stdout göstericisini göndeririz. Şimdi yukarıdaki örnekte, döngü
içerisindeki fprintf çağrısının ilk parametresi olarak fp yerine stdout yazalım
:
for (i = 0;
i < MONTH_NUMBER; ++i)
  fprintf(stdout,"%2d. ay : %s\n",i+1,ptr[i]);
|
Programı bu haliyle
çalıştırdığınızda bilgilerin dosyaya değil, ekrana yazıldığını göreceksiniz.
Bu haliyle fprintf fonksiyonu, printf fonksiyonu ile aynı işlemi yapmaktadır.
* sprintf
Fonksiyonu :
Son olarak sprintf
fonksiyonunu inceleyelim. Bu fonksiyonun prototip bildirimi de stdio.h başlık
dosyasında yer almaktadır.
int sprintf(char
*str1,char *format,...); |
sprintf fonksiyonu
da, printf ve fprintf fonksiyonlarına benzer şekilde çalışmaktadır. Bu fonksiyonun
diğerlerinden temel farkı ise, yazacağı ifadeleri bir dosyaya ya da ekrana değil,
bir karakter katarına yazmasıdır. Fonksiyonun ilk parametresi, ifadenin yazılacağı
karakter katarıdır. str1 göstericisi, sprintf fonksiyonu çağrılmadan önce tanımlanmış
olmalıdır ve bellekte güvenilir bir bölgeyi gösteriyor olmalıdır. sprintf fonksiyonunu
kullanırken dikkat edilmesi gereken önemli bir nokta, ilk parametre için ayrılmış
olan alanın, yazılacak ifadenin uzunluğundan büyük olmasıdır. Aksi takdirde
bir gösterici hatası ile karşılaşılacaktır. Şimdi sprintf fonksiyonuna dair
bir örnek yapalım :
#include <stdio.h>
#define STR_LENGTH
20
int main()
{
    char str [STR_LENGTH];
    sprintf(str,"%s","CSharp Nedir?");
    puts(str);
    return 0;
}
|
Programda önce,
#define önişlemci komutu ile STR_LENGTH isminde bir sembolik sabit bildirimi
yaptık. Daha sonra (char) türden bir dizi tanımladık. Dizimizin uzunluğu STR_LENGTH
kadar olacak. Dizi bildiriminden sonra sprintf fonksiyonunu çağırarak "CSharp
Nedir?" yazısını diziye yazdırdık. Gördüğünüz gibi fonksiyona gönderdiğimiz
ikinci ve üçüncü parametreler, printf ve fprintf fonksiyonlarının parametrelerine
benzemektedir. Dizi sınırı aşımını test etmek için sembolik sabiti bildirirken
20 sayısı yerine yazımızın uzunluğundan daha küçük bir değer yazın. Bu durumda
dizi taşma hatası olduğundan program hata verecektir. Bu fonksiyonu kullanırken
özellikle bu duruma dikkat edilmelidir. Derleyici bu gibi hataları kontrol etmez,
bu tamamen programcının sorumluluğuna bırakılmıştır. Bu çağrıda (char) türden
bir dizi tanımlamak yerine (char *) türünden bir gösterici tanımlamak istiyorsanız,
sprintf fonksiyonunu çağırmadan önce bu gösterici için standart malloc fonksiyonu
ile bellekte bir alan tahsis etmelisiniz :
char *str
= malloc(sizeof(char)*20);
sprintf(str,"%s","CSharp Nedir?");
|
Bu bellek tahsisatı
yapılmazsa, göstericimiz herhangi bir yeri göstermediği için bellekte güvenilir
olmayan bir bölgeye erişmeye çalışmış oluruz. Bu durumda yine bir gösterici
hatası ile karşılaşılır. Öncelikle mutlaka bellek tahsisatı yapılmalıdır.
Bu yazımızda printf,
fprintf ve sprintf fonksiyonlarının temel benzerliklerine, farklılıklarına ve
kullanım şekillerine değindik. Kullanımda dikkat edilmesi gereken noktaları
belirttik. Bir sonraki yazımızda görüşmek dileğiyle..
Makale:
Standart printf, fprintf ve sprintf Fonksiyonları C ve Sistem Programlama Çiğdem Çavdaroğlu
|