C dili ile çalışan programlamacının en büyük dostlarından biri kuşkusuz "scanf()" fonksiyonudur. İşlevi ise kullanıcıdan input almak üzerinedir. Ancak bu dost bazen problemler çıkarabiliyor. Advanced Programming dersinde yaptığım son ödevde başıma gelen sorun gibi. Ödevim; text olarak alınmış bir inputun morse alfabesi ile karşılığının ve morse alfabesi ile alınmış bir inputun text olarak karşılığının ekrana yazdırılması için gerekli algoritmayı kurmaktı. Haliyle; algoritma bir menü ile çalışmak zorunda. Text'ten mi morse'a çevireceksiniz, yoksa morse'tan mı text'te... Bunu menü ile seçmeniz gerekiyor. Ve bunu bir loop'a sokmak gerekiyor ki birden fazla kez işlem yapılabilsin. Menüde seçim yapabilmek için ise bir karakter variable tanımlamak gerekiyor. Bu variable'ı da her seferinde tekrar istemek gerekiyor. Kod olarak ise şöyle gösterilebilir: printf("\tMenu\nE\tEncode(Read text and convert to morse)\n"
"D\tDecode(Read morse and convert to text)\n"
"X\tExit\n>");
scanf("%c", &selection;);
while ( (selection != 'x') && (selection != 'X') )
{
if( (selection == 'e') || (selection == 'E') )
{
//Statements
}
else
if( (selection == 'd') || (selection == 'D') )
{
//Statements
}
printf("\tMenu\nE\tEncode(Read text and convert to morse)\n"
"D\tDecode(Read morse and convert to text)\n"
"X\tExit\n>");
scanf("%c", &selection;);
}
     Bu kodu run ettiğimde menünün iki defa karşıma çıktığını gördüm. Halbu ki iki if statement'tan sonra bir kere menünün çıkması ve "scanf()" fonksiyonunu beklemesi gerekiyor. Karşıma çıkan sorun da işte bu. Variable tekrar kullanıcıdan istendiğinde "scanf()", sanki zaten variable'ı tekrar istemiş ve okumuş gibi davranıyor ve loop tekrar çalışıyordu. Haliyle menü iki kez karşıma çıkıyordu. Bu durumun "scanf()"ten kaynaklanan bir sorun olduğu ortada. Yaptığım araştırma sonucunda ise şöyle bir bilgiye eriştim.
     "scanf()" fonksiyonu çalıştığında tampon denilen bölgeden (birazdan açıklayacağım) bütün veriyi alıyor. Veriyi alırken de bölgedeki boşlukları ignore edip veriyi alıyor. Bu şu demek oluyor. Eğer verinin alındığı tampon bölgede herhangi bir veri varsa kullanıcıdan inputu almadan önce "scanf()" o bölgede varolan veriyi alıyor. Enter tuşuna basmamızı da bekler, fakat bölgedeki verinin içinde enter karakteri varsa bunu bile beklmeden statement'ı zaten çalışmış ve input alınmış gibi atlıyor. Bundan dolayı da "scanf()", kullanıcının input vermesine olanak vermiyor. Bu yüzden, "scanf()" fonksiyonunu kullanmadan önce mutlaka tampon bölgeyi boşaltmamız gerekiyor. Bu esanada da "fflush()" fonksiyonu imdadımıza yetişiyor. Tampon bölgeyi boşaltman için "scanf()" fonksiyonunu call etmeden önce "fflush()" fonksiyonunu call ederek tampon(buffer) bölgesini boşaltmamız gerekiyor. O zaman ise kod şu şekilde oluyor:
printf("\tMenu\nE\tEncode(Read text and convert to morse)\n"
"D\tDecode(Read morse and convert to text)\n"
"X\tExit\n>");
scanf("%c", &selection;);
while ( (selection != 'x') && (selection != 'X') )
{
if( (selection == 'e') || (selection == 'E') )
{
//Statements
}
else
if( (selection == 'd') || (selection == 'D') )
{
//Statements
}
fflush(stdin);
printf("\tMenu\nE\tEncode(Read text and convert to morse)\n"
"D\tDecode(Read morse and convert to text)\n"
"X\tExit\n>");
scanf("%c", &selection;);
}
     Peki nedir bu tampon(buffer) bölge? Klavyeden kullanıcı bir input girdiğinde aslında bu input, standart input dosyasına yazılmış oluyor. Yani aslında bizim bildiğimiz klavye ve ekran, input ve output dosyalarını temsil ediyor. Terminolojik olarak bunlar C dilinde "stdin" dosyası ve "stdout" dosyası olarak adlandırılıyor. "stdin" dosyasının varsayılan değeri klavye, "stdout" dosyasının varsayılan değeri ise ekran oluyor. "stdin" dosyasından okuma yapan fonksiyonlara ("gets()", "scanf()" gibi) verilen inputlar tampon bölgesinde tutuluyor ve okuma burada gerçekleşiyor.
     Örneğin en çok kullandığımız fonksiyonlardan biri olan "printf()" fonksiyonu aslında "fpirntf()" olarak çalışır. "printf("Bilgi Paylaştıkça Artar")" dediğimizde aslında "fprintf(stdout, "Bilgi Paylaştıkça Artar")" demiş oluyoruz.
     Sonuç olarak "scanf()"ten önce yukarıdaki kodda olduğu gibi "fflush(stdin)" fonksiyonunu kullandığımızda "stdin" dosyasını boşaltmış oluyoruz. Tavsiyem, "scanf()"ten önce mümkün olduğu kadar tampon bölgeyi boşaltmanızdır. Hatta "gets()" fonksiyonundan önce de aynı işlemi yapıp, string alırken de başınıza gelebilecek bu sorundan kurtulabilirsiniz. Aksi halde sorunun ne olduğunu saatlerce düşünüp saç baş yolabilirsiniz.Kaynak: http://www.sorucevap.com/bilisimteknolojisi/programcilik/c/ders.asp?206634
Etiket(ler): c, scanf, tampon bölge, buffer, stdin, stdout, fflush, gets