BG MVC Model View Controller eğitim serisi yayında...

Ana sayfa > Programlama > C Programlama > Konsol işlemleri

Konsol işlemleri

Konsol işlemleri klavye ve ekran ile gerçekleştirilen işlemleri kapsar. Bu bölümde, C temelli temel giriş çıkış fonksiyonları ele alınacaktır.

getchar() ve putchar() fonksiyonları

Klavyeden girilen bir karakteri okuyarak bellekteki bir değişkene atamak için getchar() fonksiyonu, ekrana tek bir karakter yazdırmak için ise, putchar() fonksiyonu kullanılır. stdio.h başlık dosyasını kullanan bu iki fonksiyonun genel yapısı prototipi aşağıda gösterilmektedir:


int getchar(void);
int putchar(int id);

getchar() fonksiyonunu kullanarak klavyeden karakter girmemiz gerekirken, karakter girmek yerine ENTER tuşuna basarsak, getchar() fonksiyonu \n karakterini geri verir.

getchar() fonksiyonu klavyeden girdiğimiz karakteri, int bir değere çevrilen unsigned char bir değer olarak okur. Programlar, klavyeden okunan değeri genellikle char bir değişkene atar. Bu durumda int değerin en solda kalan bit'i devre dışı kalır.

Ancak, getchar() fonksiyonu int bir değer geri verir, çünkü klavyeden karakter okunurken bir hata meydana geldiğinde getchar() fonksiyonunun geri verdiği EOF makrosu genellikle -1 olan negatif bir int değerdir.

EOF makrosu stdio.h başlık dosyası içinde tanımlıdır. Sonuç olarak, klavyeden yapılan okuma işleminde bir hata meydana geldiğinde getchar() fonksiyonunun EOF değerini geri vermesi için int bir değer geri vermesi gerekir.

Şimdi, aşağıdaki örneği inceleyerek getchar() fonksiyonunun yaptığı işlemi incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cd1, cd2;

  printf("İki karakter girip ENTER tuşuna basınız: ");

  cd1 = getchar();
  cd2 = getchar();

  printf("Girdiğiniz karakterler: %c %c", cd1, cd2);

  return 0;
}

Yukarıdaki örnekte, program çalıştığında bir imleç yanıp sönmeye başlar. Bu durumda, program klavyeden 2 karakter girilmesini bekler. Bir karakter girildiğinde, karakter yanıp sönen imleç yerine ekrana yazılır ve imleç bu defa ekrana yazılan karakterin hemen sağında yanıp sönmeye devam eder. İkinci karakter girildiğinde, karakter yine ekrana yazılır ve imleç bir sağa kayar. ENTER tuşuna bastığımızda, girdiğimiz karakterler cd1 ve cd2 değişkenlerine atanır. Bu durumda ENTER tuşuna basmak yerine daha fazla karakter girilse bile, fazladan girilen karakterlerin herhangi bir etkisi olmaz. Yine ilk iki karakter değişkenlere atanır. Son olarak, program printf() fonksiyonunu kullanarak değişken değerlerini ekrana yazar. Eğer, tek bir karakter girip ENTER tuşuna basarsanız, program cd2 değişkenine herhangi bir değer atamaz, sadece cd1 değişken değerini ekrana yazar.

putchar() fonksiyonu ise, ekrana tek bir karakter yazar. putchar() fonksiyonunun parametresi int bir değerdir, ancak bu değer fonksiyon tarafından unsigned char bir değere çevrilir. Eğer işlem başarılı olursa, putchar() fonksiyonu parametre olarak verilen karakteri, aksi takdirde EOF makro değerini geri verir.

Şimdi getchar() ve putchar() fonksiyonlarının birlikte kullanıldığı örnekleri incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cd;

  printf("Tek bir karakter girip ENTER tuşuna basınız: ");

  cd = getchar();

  printf("Girilen karakter: %c", putchar(cd));

  return 0;
}

Program, klavyeden girilen karakteri getchar() fonksiyonu ile cd değişkenine atar ve putchar() fonksiyonu ile değişken değerini ekrana yazar.


#include <stdio.h>

int main(void)
{
  char cd;
  int id;

  printf("Bir harf giriniz: ");
  cd = getchar();

  for (id=0; id<10; id++) putchar(cd);

  return 0;
}

Program, klavyeden girilen harfi 10 kez ekrana yazar.

getche(), getch() ve kbhit() fonksiyonları

conio.h başlık dosyasını kullanan getche() ve getch() fonksiyonlarının genel yapıları aşağıdaki gösterilmektedir:


int getche(void);
int getch(void);

getche() fonksiyonu tıpkı getchar() fonksiyonu gibi klavyeden yazılan tek bir karakter okur. Klavyeden bir karakter girilir girilmez okur, bir bellek değişkenine atar. Ayrıca ENTER tuşuna basılmasına gerek yoktur. Klavyeden girilen karakter unsigned char bir değer olarak okunur ve int bir değere çevrilir. Sonuçta, klavyeden okunan değer char bir değişkene atanır. Bu fonksiyonu bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>
#include <conio.h>

int main(void)
{
  char cd;

  printf("Bir karakter giriniz: ");
  cd = getche();

  printf("\n");

  putchar(cd);

  return 0;
}

Program, bir karakter girildiğinde, girilen karakteri ekrana yazar ve cd değişkenine atar. putchar() fonksiyonunu kullanarak cd değişken değerini ekrana yazar.

getch() fonksiyonu da tıpkı getche() fonksiyonu gibi klavyeden yazılan tek bir karakter okur. getch() fonksiyonunu getche() fonksiyonundan ayıran en önemli özellik girdiğiniz karakteri ekrana yazmamasıdır. Şimdi, bu fonksiyonu da bir örnek üzerinde inceleyelim:


#include <stdio.h>
#include <conio.h>

int main(void)
{
  char cd;

  printf("Bir karakter giriniz: ");
  cd = getch();

  printf("\n");

  putchar(cd);

  return 0;
}

Yukarıdaki örnekte, program bir karakter girdiğinizde, girdiğiniz karakteri ekrana yazmadan cd değişkenine atar. Son olarak program putchar() fonksiyonunu kullanarak cd değişken değerini ekrana yazar.

getchar(): Girilen karakteri okuma işlemi için ENTER tuşuna basılması gerekir.

getche(): Karakter girilir girilmez okuma işlemi gerçekleşir.

getch(): getche() fonksiyonundan tek farkı girilen karakterin ekrana yazılmamasıdır.

Standart kütüphane fonksiyonlarından biri de kbhit() fonksiyonudur. Bu fonksiyonun genel yapısı aşağıdaki gösterilmektedir:


int kbhit(void);

conio.h başlık dosyasını kullanan kbhit() fonksiyonu bir tuşa basılıp basılmadığını belirler. Eğer bir tuşa basılırsa, kbhit() fonksiyonu sıfır olmayan bir değer geri verir, ancak girilen karakteri okumaz. Eğer bir tuşa basılmazsa, kbhit() fonksiyonu 0 değerini geri verir.

Şimdi, kbhit() fonksiyonunun kullanılmasını bir örnek ile incelemeye çalışalım:


#include <stdio.h>
#include <conio.h>

int main(void)
{
  for ( ; ; ) {
       printf("%d ", 21);
       if (kbhit()) break;  // 1
  }

  return 0;
}

Program, sonsuz bir for döngüsü içine girer ve sürekli olarak 21 sayısını ekrana yazmaya başlar. Klavyeden bir tuşa basıldığında, kbhit() fonksiyonu 0 olmayan bir değer geri vereceğinden, 1 sayısı ile gösterilen işlem satırındaki break komutu devreye girdiğinden, döngü ve program sona erer.


#include <stdio.h>
#include <conio.h>

int main(void)
{
  char cd = 'a';
  int id;

  for (id=0; cd!='s'; id++) {
       printf("Bir karakter giriniz: ");
       if (id%2==0) cd = getche();
       else cd = getch();
       printf("%c\n", cd);
  }

  return 0;
}

Pprogram, klavyeden bir 's' karakteri girilene kadar girilen karakterleri, sıra ile dönüşümlü olarak getche() ve getch() fonksiyonlarını kullanarak cd değişkenine atar ve ekrana yazar.

fgets() ve fputs() fonksiyonları

Klavyeden girilen karakter dizilerini okutmak için fgets() fonksiyonunu ve karakter dizilerini ekrana yazmak için puts() fonksiyonunu kullanabiliriz. stdio.h başlık dosyasını kullanan her iki fonksiyonun genel yapıları aşağıda gösterilmekte:


char* fgets(char *str, int count, FILE *stream);
int fputs(const char *str, FILE *stream);

fgets() fonksiyonu, en fazla count parametre değerinin 1 eksiği kadar karakter okur ve okuduğu karakterleri str parametresi ile gösterilen karakter dizisine atar. ENTER tuşuna basıldığında, belirtilen sayıda karakter okumadan işlem sona erer. Klavyeden değer atamak için stream parametresi için stdin değeri kullanılır. Klavyeden Okunan karakterler str ile gösterilen karakter dizisine atandıktan sonra, str sonuna otomatik olarak, dizi sonu belirlemek üzere, NULL bir karakter ('\0') eklenir. Girilebilecek maksimum karakter sayısından (count-1) daha az karakter girilirse, giriş işlemini sona erdiren yeni satır karakteri (10), '\0' karakterinden önce diziye eklenir. Başarı durumunda, fonksiyon str parametresinin içeriğini geri döndürür. Eğer bir hata oluşursa, NULL bir işaretçi döndürülür.

fputs() fonksiyonu, str parametresi ile gösterilen ve boş bir sonlandırma karakteri ('\0') ile biten karakter dizisini ekrana yazar. Karakter dizisinin sonunda yer alan '\0' karakteri yazılmaz. Başarı durumunda, negatif olmayan bir değer geri döndürür. Hata durumunda EOF değeri geri döndürülür ve akış hata göstergesi ayarlanır.

Şimdi, fgets() ve fputs() fonksiyonlarının kullanılmasını bir örnek üzerinde çalışalım:


#include <stdio.h>

unsigned int bg_strlen(const char *str);

int main(void)
{
  char cdizi[20];
  char *cp;
  const char *cpstr;
  unsigned int len;

  // Klavye girişini okuma
  printf("Bir karakter dizisi giriniz: ");
  // ENTER tuşuna basılıncaya kadar karakter girişi devam eder,
  // ancak sadece ilk 19 karakter işlem görür. Fazla karakter girilse bile dikkate alınmaz.
  cp = fgets(cdizi, 20, stdin);

  // cdizi dizisine aktarılan karakter sayısı
  len = bg_strlen(cdizi);
  printf("cdizi dizisine aktarılan karakter sayısı: %d\n", len);

  // 0 ('\0') ve 10 ('\n') karakterlerine kadar olan cdizi içeriğini yazma
  for (cpstr = cp; *cpstr && *cpstr!='\n'; ) {
       printf("%c", *cpstr++);
  }

  // 0 ('\0') ve 10 ('\n') karakterlerini yazma
  printf(" %d", (int) *cpstr);
  // Eğer girilen karakter sayısı dizi boyutunun bir eksiğinden az ise
  // giriş yapılan karakterlerin sonuna eklenen '\n' (10) karakteri yerine '\0' karakteri konur.
  if (len<(sizeof(cdizi)-1)) {
      printf(" %d", (int) *(cpstr+1));
      cdizi[len] = '\0'; // Dizide yer alan '\n' karakterini devre dışı bırakmak için
  }
  printf("\n");

  // 0 ('\0') karakterine kadar olan cdizi içeriğini yazma
  for (cpstr = cp; *cpstr; ) {
       printf("%c", *cpstr++);
  }
  printf("\n");

  fputs(cdizi, stdout);

  return 0;
}

unsigned int bg_strlen(const char *str)
{
  const char *s;
  for (s = str; *s && *s!=10; ++s);

  return(s - str);
}

Program klavyeden girilen bir karakter dizisini fgets() fonksiyonu ile okuyarak, cdizi adlı diziye atar. bg_strlen() fonksiyonu ile, cdizi dizisine aktarılan karakter sayısını ('\n' ve '\0' karakterleri hariç) hesaplayarak len adlı değişkene atar. Önce, '\n' ve '\0' karakterleri hariç olmak üzere dizi içeriğini, daha sonra varsa '\n' karakterini ve '\0' karakterini ekrana yazar. Eğer '\n' karakteri varsa, yerine '\0' karakteri koyar. Dizi içeriğini bir for döngüsü ve fputs() fonksiyonu ile iki kez ekrana yazar.

printf() fonksiyonu

printf() fonksiyonunun genel yapısı aşağıdaki gösterilmektedir:


int printf (char *kontrol-dizisi, par1, par2, ...);

printf() fonksiyonunun ilk parametresi kontrol-dizisi ifadesi ile gösterilen ve kontrol dizisi adı verilen bir karakter dizisidir. printf() fonksiyonu, " " işaretleri arasında yer alan bu karakter dizisini ekrana yazar.

Kontrol dizisinin içinde hem normal karakterler hem de (%) işareti ile başlayan format tanımlayıcıları adı verilen ifadeler yer alabilir. printf() fonksiyonu " " işaretleri arasında yer alan normal karakterleri sıra ile ekrana yazar. Kontrol dizisi içinde yer alan her bir format tanımlayıcısı için par ifadesi ile gösterilen bir değer tanımlanır. Ancak, burada dikkat edilmesi gereken 2 önemli nokta vardır:

1. Kontrol dizisi içinde yer alan format tanımlayıcısı kadar par ifadesi ile gösterilen argüman tanımlanmalıdır.

2. Her argümanın veri türü kendisine karşılık gelen format tanımlayıcısının veri türüne uygun olmalıdır.

par ifadesi ile gösterilen argümanlar bir değişken, sabit, ifade veya bir fonksiyon çağrısı olabilir.

printf() fonksiyonu, ekrana yazdığı karakter sayısını int bir değer olarak geri verir. printf() fonksiyonunun çalışmasında bir hata meydana gelirse, fonksiyon negatif bir sayı geri verir.

printf() fonksiyonunun çalışma prensibini farklı kelimelerle tekrar ifade etmek gerekirse:

Fonksiyon çalışmaya başladığında, önce kontrol dizisi içinde yer alan ilk karaktere bakar. Eğer normal bir karakter ise hemen ekrana yazar. Eğer bir format tanımlayıcısı ise, bu format tanımlayıcısına karşılık gelen ilk argüman değerini ekrana yazar. Kontrol dizisi içindeki bütün karakterleri sıra ile bu şekilde kontrol edip işlem yaptıktan sonra çalışması sona erer.

Format tanımlayıcıları kendilerine karşılık gelen argümanların ekrana nasıl yazılacağını belirler. printf() fonksiyonu format tanımlayıcıları ile karşılaştığında ekrana farklı bir veri yazacağını ve bu verinin printf() fonksiyonu çağrılırken karakter dizisinden sonra tanımlanmış olan argüman değerlerinden sıra ile alınacağını anlar.

printf() fonksiyonu ile kullanılmakta olan format tanımlayıcıları aşağıdaki tabloda gösterilmektedir:

Format tanımlayıcısı Karşılığı
c Karakter
d signed int
i signed int
e Bilimsel gösterim
E Bilimsel gösterim
f Ondalıklı sayı
g e ve %f'den kısa olanı kullanır.
G E ve %f'den kısa olanı kullanır.
o unsigned 8'lik sayı
s Karakter dizisi
u unsigned int
x unsigned 16'lık sayı (Küçük harf)
X unsigned 16'lık sayı (Büyük harf)
p İşaretçi
n Karşılık gelen argüman ekrana yazılan karakterlerin sayısının atandığı int bir değeri gösteren bir işaretçi olmalıdır.
% % işaretini ekrana yazar.

%e veya %E format tanımlayıcılarını kullanarak, float sayı değerleri bilimsel bir şekilde ekranda gösterilebilir. Bunlarla birlikte l(double) ve L(long double) değiştirici ifadelerini kullanarak sırası ile double ve long double değerleri de bilimsel bir şekilde ekranda gösterilebilir.

Şimdi, anlattıklarımızı bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  float fd1, fd2;

  fd1 = fd2 = 726.548317;

  printf("%e\n%E", fd1, fd2);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

7.265483e+002
7.265483E+002

%g ve %G format tanımlayıcıları float ve double değerlerle birlikte kullanılır. Çıkışı normal veya bilimsel şekilde ekranda gösterir. Bu işlemi yaparken kısa olan şekli tercih ederler. Bunlarla birlikte l(double) ve L(long double) değiştirici ifadelerini kullanarak sırası ile double ve long double değerler de bilimsel bir şekilde ekranda gösterilebilir.

Şimdi, anlattıklarımızı bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  float fd1, fd2;
  double dd;

  fd1 = fd2 = 4231.953217;
  dd = 21542.652841;

  printf("%g\n%G\n%lg", fd1, fd2, dd);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

4231.95
4231.95
21542.7

int bir değer %o format tanımlayıcısı ile 8'lik sayı sisteminde ekranda gösterilebilir. %o format tanımlayıcısı short veri tiplerini ekranda göstermek için h ve long veri tiplerini ekranda göstermek için l değiştiricilerini kullanır. Şimdi bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  id = 7122;

  printf("Onluk sayı sisteminde: %d\n", id);
  printf("Sekizlik sayı sisteminde: %o", id);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Onluk sayı sisteminde: 7122
Sekizlik sayı sisteminde: 15722

Program, %o format tanımlayıcısını kullanarak d1 değişkenine atadığı 5158 sayısını sekizlik sayı sisteminde ekrana yazar.

int bir değeri 16'lık sayı sisteminde ekranda göstermek için %x veya %X format tanımlayıcılarından biri kullanılır. %x format tanımlayıcısı kullanılırsa 16'lık sayı sisteminde yer alan harfler (A-F) küçük olarak, %X format tanımlayıcısı kullanılırsa büyük olarak ekrana yazılır. %x ve %X format tanımlayıcıları, short veri tiplerini ekranda göstermek için h değiştiricisini, long veri tiplerini ekranda göstermek için l değiştiricisini kullanır. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  id = 7524;

  printf("Onluk sayı sisteminde: %d\n", id);
  printf("16'lık sayı sisteminde: %X\n", id);
  printf("16'lık sayı sisteminde: %x", id);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Onluk sayı sisteminde: 7524
16'lık sayı sisteminde: 1D64
16'lık sayı sisteminde: 1d64

%n format tanımlayıcısına karşılık gelen argüman int bir değer gösteren bir işaretçi olmalıdır. %n format tanımlayıcısını kullandığınızda, printf() fonksiyonu, argüman tarafından gösterilen int değişkene, ekrana yazılan karakterlerin sayısını atar. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  printf("%s%n", "Harf", &id);

  printf("\nEkrana yazılan karakter sayısı: %d", id);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Harf
Ekrana yazılan karakter sayısı: 4

Ekrana % işareti yazdırmak için %% ifadesini kullanılır:

printf("%%");

Şimdi, bir format tanımlayıcısının genel yapısını ele alıp, her bir elemanını ayrı ayrı incelemeye çalışalım:

Format tanımlayıcı genel yapısı

%[göstergeler][genişlik][.hassasiyet][uzunluk]format tanımlayıcısı

Bir format tanımlayıcısı toplam 6 farklı ifadeden oluşmaktadır. En baştaki % işareti ile en sonda yer alan format tanımlayıcı harfi mutlaka kullanılmalıdır. [] işaretleri arasında yer alan diğer dört ifade isteğe bağlı olarak kullanılır.

Şimdi, isteğe bağlı olarak kullanılan ifadeleri incelemeye çalışacağız. Bu ifadeler bütün format tanımlayıcıları ile kullanılmaz. %%, %p ve %c dışında kalan bütün format tanımlayıcıları ile asgari alan genişliği tanımlayıcısı ve/veya bir kesinlik tanımlayıcısı kullanılabilir. Bu değerlerin her ikisi de int değerlerdir. Eğer çıktısı alınacak değer tanımlanan asgari alan genişliğinden kısa ise, asgari alan genişliğine tamamlanana kadar boşluk ile doldurulur. Eğer çıktısı alınacak değer uzun ise çıkış kesilmez. Asgari alan genişliği tanımlayıcısı % işaretinden sonra kullanılır.


#include <stdio.h>

int main(void)
{
  int id;
 
  id = 7452;

  printf("%7d\n%2d", id, id); 

  return 0;  
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

   7452
7452

Program, asgari alan genişliği tanımlayıcısının özelliklerini gösterir. id1 değişkenine atanan 7452 sayısını ekrana yazarken printf komutundaki ilk seçenekte asgari alan genişliği 7 olarak tanımlandığından, sayının rakam hane sayısını asgari alan genişliğine eşitlemek için, önüne üç boşluk koyar. İkinci seçenekte ise asgari alan genişliği 2 olarak tanımlandığından sayı ekrana yazılırken rakam hane sayısında herhangi bir azaltma yapılmaz.

Kesinlik tanımlayıcısı (precision specifier) asgari alan genişliği tanımlayıcısından sonra gelir. Arada bir nokta işareti vardır. Kesinlik tanımlayıcısı farklı format tanımlayıcılarını farklı şekilde etkiler. Eğer %d, %i, %o, %u ve %x format tanımlayıcılarına uygulanırsa, ekranda kaç rakamın görüneceğini belirler. Bu format tanımlayıcılarının kullanılmasını bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  id = 6578;

  printf("%.8d\n%.8i\n%.8o\n%.8u\n%.8x", id, id, id, id, id);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

00006578
00006578
00014662
00006578
000019b2

Program, printf() fonksiyonu ile kesinlik tanımlayıcısı olarak 8 değerini kullandığından, ekrana yazılan değer 8 haneden az ise, eksik hane sayısı kadar 0 rakamını değerin başında ekrana yazar.

Kesinlik tanımlayıcısını, printf() fonksiyonunun %f, %e ve %g format tanımlayıcılarına uyguladığınızda, ondalık hanesinde kaç rakam görüneceğini belirler. Bu özelliği de bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  float fd;

  fd = 8624.895346;

  printf("%.3f\n%.5f", fd, fd);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

8624.896
8624.89551

Program, float bir değerin ondalık kısmını önce 3 sonra 5 haneli olarak ekrana yazar. printf() fonksiyonu içindeki format tanımlayıcılarında kullanılan 3 ve 5 değerleri sayıların ondalık kısımlarının hane sayısını belirler.

%s format tanımlayıcısına uygulandığında ise, azami alan genişliğini tanımlar. Eğer bir karakter dizisi azami alan genişliği tanımlayıcısından uzun ise ekrana yazılırken kısaltılır:


#include <stdio.h>

int main(void)
{
  char cdizi[] = "Karakter";

  printf("%.12s\n", cdizi);
  printf("%.5s", cdizi);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Karakter
Karak

Program, ilk printf() fonksiyon satırı ile "Karakter" kelimesinin tamamını, ikinci printf() fonksiyonu ile de ilk 5 harfini ekrana yazar.

Normal olarak bütün sayısal çıkışlar sağa yanaşıktır. Sola yanaşık çıkış elde etmek için % işaretinden hemen sonra - işareti koymak gerekir. - işaretinin kullanılmasını da bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  id = 21452;

  printf("%8d\n%-8d\n", id, id);
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

   21452
21452   

Yukarıdaki örnekte, program int bir değeri asgari alan genişliğini 8 alarak önce sağa, sonra sola yanaşık olarak ekrana yazar.


#include <stdio.h>

int main(void)
{
  int id1, id2;

  for (id1=0, id2=25; id1<10; id1++, id2+=10)
       printf("%-6d %6d\n", id2, id2);  
   
   return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

5          5
50        50
500      500 
5000    5000 
50000  50000

Yukarıdaki örnekte, program for döngüsü içinde elde edilen sayıları önce sola, sonra sağa yanaşık olarak ekrana yazar. Bu işlemleri yaparken asgari alan genişliğini 6 olarak tanımlar.

Şimdiye kadar printf() fonksiyonu ile ekrana tek bir karakter, karakter dizileri ve sayılar yazdırmayı gördük. Şimdi ise, klavyeden girilemeyen değerlerin printf() fonksiyonu ile ekrana nasıl aktarıldığını inceleyelim.

C'de, bu amaçla 13 adet özel kod tanımlanmıştır. Bütün kodlar (\) işareti ile başlar. Bu kodları normal bir karakteri kullandığınız her yerde kullanabilirsiniz. Bu kodlar birer karakter sabiti olduğundan, bir tanesini bir karakter değişkenine atarken ('') işaretleri arasına almamız gerekir.

KOD     ANLAMI

\b      Geriye doğru karakter silme
\f      Sayfa atlama
\n      Satır aralığı ve satır başı
\r      Satır başı
\t      Yatay tab değeri
\"      Çift tırnak
\'      Tek tırnak
\0      Boş değer
\\      Ters kesme işareti
\v      Dikey tab değeri
\a      Zil sesi
\N      8'li tabanda sabit
\xN     16'lı tabanda sabit

Bu kodlardan en çok kullanılan \n kodudur. Bu kod bir satır başı ve satır aralığı karakterinin devreye girmesini sağlar.

printf() fonksiyonuna ait özel kodları örnekler üzerinde incelemeye devam edelim:


#include <stdio.h>

int main(void)
{
  printf("Bilgisayar\n");
  printf("Programlama\nDilleri");
  printf("\nC Programlama Dili");
  
  return 0;
}

Yukarıdaki programı derleyip çalıştırdığımızda, aşağıdaki ifadeleri ekrana yazar:

Bilgisayar
Programlama
Dilleri
C Programlama Dili

Programın amacı size \n kodunun kullanılmasını ve karakter dizisinin herhangi bir yerinde kullanılabileceğini göstermektir. Program, karakter dizilerini ekranda 4 satıra yazmaktadır.


#include <stdio.h>

int main(void)
{
  int id1;

  for (id=0; id<10; id++) {
       printf("%d ", id);
       if(id == 5) printf("\t");
  }
  
  return 0;
}

Yukarıdaki örnekte, program aşağıdaki satırı ekrana yazar:

0 1 2 3 4 5     6 7 8 9

Program 1'den 10'a kadar olan sayıları ekrana yazarken 5 ile 6 sayısı arasına bir tab değeri yerleştirir.

scanf() Fonksiyonu

scanf() fonksiyonunun genel yapısı aşağıda gösterilmektedir:


int scanf (char *kontrol dizisi,...);

Nokta işaretleri fonksiyon parametrelerini gösterir. scanf() fonksiyonu klavyeden girilen verileri okuyarak belirli değişkenlere atar.

Burada, dikkat edilmesi gereken 2 önemli nokta vardır:

1. Format parametresi ile gösterilen kontrol dizisi içinde yer alan format tanımlayıcısı kadar par ifadesi ile gösterilen parametre tanımlanmalıdır.

2. Her parametrenin veri türü kendisine karşılık gelen format tanımlayıcısının veri türüne uygun olmalıdır.

scanf() fonksiyonuna geçirilen ilk argüman " " işaretleri ile arasında tanımlanan bir karakter dizisidir. Kontrol dizisi olarak adlandırılan bu karakter dizisinin içinde hem normal karakterler hem de (%) işareti ile başlayan format tanımlayıcıları adı verilen ifadeler yer alabilir. scanf() fonksiyon format tanımlayıcıları, scanf() fonksiyonunun, kontrol dizisinden sonra yer alan argümanlar (değişken adresleri) tarafından adresleri gösterilen değişkenlere klavyeden okuduğu bilgileri hangi yapıda atayacağını belirler. scanf() fonksiyonunun kontrol dizisi içinde tanımlanan format tanımlayıcı sayısı kadar argüman tanımlanması gerekir. scanf() fonksiyonu bir format tanımlayıcısı ile karşılaştığında, klavyeden bir veri okuyacağını ve bu verinin format tanımlayıcısına karşılık gelen argümanda adresi gösterilen değişkene atanacağını anlar.

scanf() fonksiyonu bellek adresleri argüman olarak verilen değişkenlere atanan değer sayısını geri verir. Fonksiyonun çalışmasında herhangi bir hata meydana gelirse, EOF değerini geri verir.

Format içinde yer alan her bir değerin genel yapısı

%[*][genişlik][uzunluk]format tanımlayıcısı

Bu fonksiyon için bir format tanımlayıcısı toplam 5 farklı ifadeden oluşmaktadır. En baştaki % işareti ile en sonda yer alan format tanımlayıcı harfi mutlaka kullanılmalıdır. [] işaretleri arasında yer alan diğer üç ifade isteğe bağlı olarak kullanılır.

% : Mutlaka tanımlanması gereken bu karakter format parametresinin değeri içinde yer alan ve fonksiyona geçirilecek parametrelere atanacak değerlerin yapısını gösteren her bir değerin başlangıcını gösterir.

* : İsteğe bağlı olarak tanımlanan bu karakter verilerin akıştan okunması gerektiğini ancak göz ardı edildiğini, yani karşılık gelen argümanda depolanmadığını gösterir.

genişlik : İsteğe bağlı olarak tanımlanan bu değer geçerli okuma işleminde okunacak maksimum karakter sayısını gösterir.

uzunluk : İsteğe bağlı olarak tanımlanan bu değer okutulacak argümanın boyutunu gösterir. hh, h, l, ll, j, z, t, L değerlerinden biri kullanıldığında, karşılık gelen argümanın gösterdiği kaydetme tipini değiştirir.

scanf() fonksiyonu ile kullanılmakta olan format tanımlayıcıları aşağıdaki tabloda yer almaktadır:

Format tanımlayıcı Karşılığı
c Karakter
d signed int
i signed int
e Bilimsel gösterim
E Bilimsel gösterim
f Ondalıklı sayı
g e ve %f'den kısa olanı kullanır.
G E ve %f'den kısa olanı kullanır.
o unsigned 8'lik sayı
s Karakter dizisi
u unsigned int
x unsigned 16'lık sayı (Küçük harf)
X unsigned 16'lık sayı (Büyük harf)
p İşaretçi
n Okunan karakter sayısını içeren int bir değer alır.
[ ] Bir karakter setini tarar.
% % karakterini ifade eder.

Şimdi, klavyeden girilen int bir değerin scanf() fonksiyonu ile okunmasını bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;

  printf("int bir değer giriniz: ");
  scanf("%d", &id);

  printf("Girdiğiniz değer: %d", id);
  
  return 0;
}

Program, klavyeden girilen int bir değeri ekrana yazar.

unsigned int değerleri 16'lık sayı sisteminde (Hexadecimal) okutmak için %x format tanımlayıcısı, 8'lik sayı sisteminde (Octal) okutmak için ise, %o format tanımlayıcısı kullanılır. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  unsigned int id1, id2;

  printf("16'lık sayı sisteminde bir sayı giriniz: ");
  scanf("%x", &id1);

  printf("8'lik sayı sisteminde bir sayı giriniz: ");
  scanf("%o", &id2);

  printf("Girdiğiniz sayıların 10'luk sayı sistemindeki değerleri: ");
  printf("%u %u", id1, id2);
  
  return 0;
}

Program, biri 16'lık diğeri ise 8'lik sayı sisteminde olmak üzere 2 sayı girmenizi ister. Sonra, girdiğiniz değerleri 10'luk sayı sisteminde ekrana yazar.

%d, %i, %u, %x ve %o format tanımlayıcıları short bir değişken okurken h, long bir değişken okurken l ifadesi ile kullanılır.

%e, %f ve %g format tanımlayıcıları aynı amaçla kullanılır. Hepsi bilimsel veya normal bir şekilde ifade edilen float bir değeri okumakta kullanılabilir. Bu format tanımlayıcıları, okunan değerleri float veri değişkenlere atar. double bir değer okurken l, long double bir değer okurken L ifadesi ile kullanılır.

Klavyeden girilen bir karakter dizisini okutmak için scanf() fonksiyonu %s format tanımlayıcısı ile kullanılır. scanf() fonksiyonu bir boşluk, tab ya da satırbaşı karakteri ile karşılaştığında okumayı durdurur. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi1[40], cdizi2[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%s", cdizi1);

  printf("Arada boşluk bırakarak 2 kelime giriniz: ");
  scanf("%s", cdizi2);

  printf("%s\n%s", cdizi1, cdizi2);

  return 0;
}

Program, bir karakter dizisi ile arasında boşluk bulunan iki kelime girilmesini ister. İlk girilen karakter dizisinin tamamını okutarak cdizi1 dizisine, ikinci girilen iki kelimenin ise sadece ilkini okuyarak cdizi2 dizisine atar. cdizi1 ve cdizi2 dizilerine atanan karakter dizilerini ekrana yazar. Ancak, scanf() fonksiyonu ikinci kelimeyi okutmadığı için, cdizi2 dizisi yazıldığında ekrana yazılmaz.

%p format tanımlayıcısı, girdiğiniz bir işaretçi değerini, yani bir bellek adresini, kendisine karşılık gelen argümana atar. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char *cp;

  printf("Bir adres giriniz: ");
  scanf("%p", &cp);

  printf("%p bellek adresindeki değer: %c", cp, *cp);
  
  return 0;
}

Program, girilen bir bellek adresini ve adreste yer alan karakteri ekrana yazar.

%n format tanımlayıcısını kullandığınızda, scanf() fonksiyonu, format tanımlayıcısına karşılık gelen argüman tarafından gösterilen int değere klavyeden girilen karakterlerin sayısını atar. %n format tanımlayıcısına karşılık gelen argüman int bir değer gösteren bir işaretçi olmalıdır. %n format tanımlayıcısı, kontrol dizisi içinde yer aldığı noktaya kadar okunan karakterlerin sayısını, kendisine karşılık gelen işaretçi argüman tarafından gösterilen int değişkene atar. %n format tanımlayıcısı değerini long bir değişkene atamak için l, short bir değişkene atamak için h ifadesini kullanır. %n format tanımlayıcısının kullanılmasını örneklerle incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id;
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%s%n", cdizi, &id);

  printf("%s\n", cdizi);
  printf("Girilen karakter sayısı: %d", id);
  
  return 0;
}

Program, scanf() fonksiyonunu kullanarak klavyeden girilen bir karakter dizisini cdizi adlı bir diziye atar. Karakter dizisindeki karakter sayısını id değişkenine atar. Daha sonra karakter dizisini ve karakter sayısını ekrana yazar.


#include <stdio.h>

int main(void)
{
  int id1, id2, id3;
  char cdizi1[40], cdizi2[40];

  printf("İki karakter dizisi giriniz: ");
  scanf("%n%s%n%s%n", &id1, cdizi1, &id2, cdizi2, &id3);

  printf("%s\n%s\n", cdizi1, cdizi2);
  printf("Girilen karakter sayısı: %d  %d  %d ", id1, id2, id3);
  
  return 0;
}

Program, iki karakter dizisi girilmesini ister. scanf() fonksiyon işlem satırında %s format tanımlayıcılarının arasında üç defa %n format tanımlayıcısı kullanır. Girilen karakter dizilerini ve girilen ilk karakter dizisinin karakter sayısı ile her iki karakter dizisinde yer alan karakterlerin toplam miktarını ekrana yazar. Ekrana yazdığı 0 değeri ilk olarak kullanılan %n format tanımlayıcısından önce herhangi bir karakter girişi yapılmadığını göstermektedir. Başka bir şekilde ifade edersek, %n format tanımlayıcıları kendisinden önce girilen karakter sayısını verir.

scanf() fonksiyonu ile birlikte scanset tanımlayıcısı adı verilen özel bir kullanım şekli vardır. Scanset tanımlayıcısı, [] işaretleri arasına yerleştirilen karakterlerle oluşturulur. Scanset'in genel yapısı aşağıdaki şekildedir:

scanf ("%[FTHKACN]", cdizi);

Yukarıdaki işlem satırında, [] işaretleri arasında yer alan 9 adet karakterin tamamı scanset'in bir elemanıdır.

scanf() fonksiyonu bir scanset tanımlayıcısı ile karşılaştığı zaman, klavyeden girdiğiniz karakter dizisini okumaya başlar. Girdiğiniz karakter scanset içinde yer aldığı sürece, girdiğiniz karakterleri okumaya devam eder. Eğer klavyeden girdiğiniz karakter, scanset içinde yer almıyorsa, scanf() fonksiyonu scanset tanımlayıcısı ile ilgili olarak yaptığı karakter dizisi okuma işlemine son verir ve kontrol dizisindeki bir sonraki format tanımlayıcısından çalışmasına devam eder.

Scanset tanımlayıcısının kullanılmasını bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%[hnigcvbla]", cdizi);
  printf(cdizi);
  
  return 0;
}

Program, klavyeden bir karakter dizisi girilmesini ister. Girilen karakter dizisinde, scanset içinde yer almayan ilk harfe kadar olan karakterleri cdizi adlı karakter dizisine atar. Sonra cdizi dizisini ekrana yazar. Örneğin, karakter dizisi olarak "bilgisayar" kelimesi girildiğinde, program ekrana sadece aşağıdaki ifadeyi yazar. Çünkü, 's' harfi scanset içinde yer almamaktadır:

bilgi

scanf() fonksiyonu Scanset tanımlayıcısı içinde çok fazla karakter kullanılacağı zaman, tanımlanacak karakter grubunun başlangıç ve bitim karakterlerinin arasında bir - işareti kullanmak yeterlidir. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%[a-r]", cdizi);

  printf(cdizi);
  
  return 0;
}

Program, klavyeden bir karakter dizisi girilmesini ister. Girilen karakter dizisinde, k ile t harfi arasında yer almayan ilk harfe kadar olan karakterleri cdizi adlı karakter dizisine atar. Sonra, cdizi dizisini ekrana yazar. Örneğin, karakter dizisi olarak "karakter" kelimesi girildiğinde, program ekrana sadece aşağıdaki ifadeyi yazar. Çünkü, 't' harfi scanset içinde yer almamaktadır:

karak

Scanset için çok büyük bir karakter grubu tanımlamanız gerektiği zaman, sadece tanımlamak istemediğiniz karakterleri belirtmeniz daha pratik bir çözüm olacaktır.

Bu işlem için ^ işaretini kullanmak yeterlidir. ^ işareti ile ilgili bir örneği incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%[^dlpz]", cdizi);

  printf(cdizi);
  
  return 0;
}

Program, klavyeden bir karakter dizisi girilmesini ister. Scanset içinde, ^ işaretinden sonra tanımlanan harfler dışında girilen bütün karakterler scanf() fonksiyonu tarafından cdizi adlı bir karakter dizisine atanır. Daha sonra, program cdizi dizisinin içeriğini ekrana yazar. scanf() fonksiyonunun okuma işlemini sona erdirmesi için, mutlaka scanset içindeki d, l, p veya z harflerinden birinin karakter dizisinin bir parçası olarak girilmesi gerekir.

Şimdi, - ve ^ işaretlerinin birlikte kullanılmasını bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%[^A-Z]", cdizi);

  printf(cdizi);
  
  return 0;
}

Program, klavyeden bir karakter dizisi girilmesini ister. Scanset içinde ^ işaretinden sonra kullanılan A-Z ifadesi, büyük harfler dışında, klavyeden girilen bütün karakterlerin scanf() fonksiyonu tarafından cdizi adlı bir karakter dizisine atanmasını sağlar. Daha sonra, program cdizi dizisinin içeriğini ekrana yazar. scanf() fonksiyonunun okuma işlemini sona erdirmesi için karakter dizisinin bir parçası olarak mutlaka büyük bir harf girilmesi gerekir.

Klavyeden girdiğiniz karakterlerin, scanf() fonksiyonu tarafından hiç dikkate alınmamasını sağlamak için, format tanımlayıcılarında % işaretinden sonra * işaretini kullanmanız yeterlidir. Bu durumda, girdiğiniz karakter sanki hiç yazılmamış gibi işlem görür.

Şimdi, bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cd;

  printf("İki harf giriniz: ");
  scanf("%c%*c", &cd);
  printf("%c", cd);
  
  return 0;
}

Program, klavyeden 2 harf girilmesini ister. scanf() fonksiyonu klavyeden girilen ilk harfi, cd değişkenine atar. Kontrol dizisinde, ikinci karaktere karşılık gelen format tanımlayıcısında * işareti yer aldığından, klavyeden girilen ikinci karakteri dikkate almaz. Sonra, girilen karakteri ekrana yazar.

%c ve %n format tanımlayıcıları hariç, scanf() fonksiyonu ile kullanılan bütün format tanımlayıcıları için azami alan genişliği tanımlayabiliriz. Azami alan genişliği % işaretinden hemen sonra ve unsigned int bir değer olarak tanımlanır. Bu özelliği bir örnek üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  char cdizi[40];

  printf("Bir karakter dizisi giriniz: ");
  scanf("%15s", cdizi);

  printf(cdizi);
  
  return 0;
}

Program, bir karakter dizisi girilmesini ister. Dizi boyutu 40 karakter olduğu halde, %s format tanımlayıcısı için azami alan genişliği 15 karakter olarak tanımlandığından, scanf() fonksiyonu klavyeden girilen 10 karakterden fazlasını dikkate almaz. Sonra, program dizi içeriğini ekrana yazar.

Eğer bir kontrol dizisi içinde bir boşluk karakteri yer alırsa, % dışında bir ASCII karakteri ile karşılaşana kadar, scanf() fonksiyonu okuduğu boşluk, tab ve yeni satır karakterlerini dikkate almaz. Eğer bir kontrol dizisi içinde başka herhangi bir karakter varsa, o karakter ile aynı olmayan ilk karakteri kontrol dizisinden okuyana kadar, scanf() fonksiyonu okuduğu karakterleri dikkate almaz. scanf() fonksiyonu sadece %c format tanımlayıcısından önce yer alan boşluk karakterlerini dikkate alır. Diğer format tanımlayıcılarından önce tanımlanan boşluk karakterlerinin programın çalışmasına herhangi bir etkisi yoktur. Şimdi, bu özellikleri örnekler üzerinde incelemeye çalışalım:


#include <stdio.h>

int main(void)
{
  int id1, id2, id3;

  printf("3 int değer giriniz: ");
  scanf("%d%d%d", &id1, &id2, &id3);     // 1

  printf("Girdiğiniz tamsayıların toplamı: %d", id1+id2+id3);

  printf("\n\n3 int değer daha giriniz: ");
  scanf("%d %d %d", &id1, &id2, &id3);   // 2

  printf("Girdiğiniz tamsayıların toplamı: %d", id1+id2+id3);
  
  return 0;
}

Program, 2 kez üç adet int değer girilmesini ister. Her defasında girilen int değerlerin toplamını ekrana yazar. 1 sayısı ile gösterilen işlem satırındaki kontrol dizisinde kullanılan %d format tanımlayıcıları arasında boşluk tanımlanmış, 2 sayısı ile gösterilen işlem satırında ise kontrol dizisi içindeki format tanımlayıcıları arasında boşluk tanımlanmamış olmasına rağmen, her iki işlem satırı da aynı işlemi gerçekleştirir. Her iki işlem satırı içinde, ister her int değer girişinden sonra, isterseniz tüm int değerlerin girişinden sonra bir kez ENTER tuşuna basabilirsiniz. Ancak, tüm değerlerin girişinden sonra ENTER tuşuna bir kez basmak yolunu tercih ederseniz, her değer girişinden sonra bir boşluk bırakmanız gerekir. Kısaca ifade edersek, scanf() fonksiyonunun kontrol dizisinde kullanılan %d format tanımlayıcıları arasında boşluk karakteri tanımlamakla tanımlamamak arasında herhangi bir fark yoktur.


#include <stdio.h>

int main(void)
{
  char cd1, cd2;

  printf("2 char değer giriniz: ");
  scanf("%c %c", &cd1, &cd2);

  printf("Girdiğiniz karakterler: %c %c", cd1, cd2);
 
  return 0;
}

Program, sıra ile 2 char değer girilmesini ister. Girilen karakterleri ekrana yazar. Ancak, scanf() fonksiyonu kontrol dizisi içindeki %c format tanımlayıcıları arasında bir boşluk karakteri tanımlandığından, iki karakter girişi arasında ENTER tuşuna basılsa bile, iki karakter de program tarafından okunur. Eğer boşluk olmasaydı, ENTER tuşuna basıldığında ikinci karakter okunmayacaktı. Kısaca ifade etmek gerekirse, scanf() fonksiyonunun kontrol dizisinde kullanılan %c format tanımlayıcılarından önce boşluk karakteri tanımlamak farklı sonuç verir.


#include <stdio.h>

int main(void)
{
  char cdizi1[20], cdizi2[20];
  char cd;

  printf("Aralarında boşluk ile iki karakter dizisi ve arasında bir karakter giriniz:");
  scanf("%s%c%s", cdizi1, &cd, cdizi2); 
  printf("İlk karakter dizisi: %s\n", cdizi1);
  printf("İkinci karakter dizisi: %s\n", cdizi2);
  printf("Karakter: %c", cd);
  
  return 0;
}

Program, 2 karakter dizisi ve arasında 1 karakter girilmesini ister. Ancak, 1 sayısı ile gösterilen işlem satırında %c format tanımlayıcısından önce bir boşluk tanımlanmadığı için, karakter olarak girilen değeri ikinci karakter dizisi olarak kabul eder. Sanki kontrol dizisi içinde %c format tanımlayıcısı hiç tanımlanmamış gibi sadece karakter dizilerini ekrana yazar. Eğer boşluk tanımlanırsa, program girilen değerleri beklendiği şekilde okur ve ekrana yazar.