scanf %c atlıyor gibi görünen durumun nedeni, önceki scanf çağrısından kalan Enter karakteridir. scanf("%d", &yas) yaş değerini okurken, Enter tuşuyla oluşan satır sonu karakteri n giriş tamponunda kalabilir. Ardından scanf("%c", &cevap) baştaki boşlukları kendiliğinden atlamadığı için yeni bir karakter beklemek yerine bu n karakterini okuyabilir.
Giriş tamponu, klavyeden gelen karakterlerin program tarafından okunmayı beklediği geçici alan gibi düşünülebilir. Biçim belirteci ise scanf fonksiyonuna verinin nasıl okunacağını söyleyen %d, %f ve %c gibi ifadelerdir.
scanf %c neden girdiyi beklemeden geçer?

Aşağıdaki programda önce yaş, ardından devam etmek için e veya h karakteri okunmak isteniyor:
#include <stdio.h>
int main(void) {
int yas;
char cevap;
printf("Yasiniz: ");
scanf("%d", &yas);
printf("Devam edilsin mi (e/h): ");
scanf("%c", &cevap);
printf("Okunan karakter kodu: %dn", (unsigned char)cevap);
printf("Okunan karakter: [%c]n", cevap);
return 0;
}
Program çalışırken 20 yazıp Enter tuşuna bastığında, %d yaş değerini alır. Ancak giriş akışında yaklaşık olarak 20n bulunur. Rakamlar yaş değişkenine aktarılırken satır sonundaki n karakteri okunmadan kalır. İkinci scanf çağrısı da bu karakteri okuduğu için kullanıcıdan ayrıca e veya h istemeden devam eder.
ASCII tabanlı bir GCC hedefinde satır sonu karakteri n için gözlenen karakter kodu 10'dur. Bu nedenle programda karakter kodu olarak 10 yazdırılması, %c dönüşümünün yeni bir cevap yerine tampondaki Enter karakterini okuduğunu gösterir.
Sorunu düzeltmenin kısa yollarından biri, %c dönüşümünden önce biçim dizgesine bir boşluk eklemektir:
#include <stdio.h>
int main(void) {
int yas;
char cevap;
printf("Yasiniz: ");
if (scanf("%d", &yas) != 1) {
printf("Gecerli bir sayi girilmedi.n");
return 1;
}
printf("Devam edilsin mi (e/h): ");
if (scanf(" %c", &cevap) == 1) {
printf("Okunan karakter: %cn", cevap);
}
return 0;
}
scanf(" %c", &cevap) içindeki boşluk, girişte bulunan boşluk, sekme ve Enter gibi boşluk karakterlerini geçer. Ardından %c, ilk boşluk olmayan karakteri okur. Bu yüzden önceki satırdan kalan n atlanır ve kullanıcı tarafından girilen e ya da h karakteri okunur.
scanf dönüş değerini kontrol etmek de önemlidir. Fonksiyon, başarıyla değer aktardığı değişkenlerin sayısını döndürür. Örneğin scanf("%d", &yas) != 1 ifadesi, yaş için geçerli bir sayı okunup okunmadığını kontrol eder. scanf("%c", &cevap) için dönüş değerinin 1 olması ise yalnızca bir karakterin okunduğunu gösterir; okunan karakterin gerçekten e veya h olduğunu göstermez.
%d, %f ve %c boşlukları nasıl işler?
%d ve %f dönüşümleri baştaki boşluk karakterlerini tüketebilir, %c dönüşümü ise bunu kendiliğinden yapmaz. Enter karakteri n, normal boşluk ' ' ve sekme t C programlarında boşluk karakterleri arasında değerlendirilir.
| Biçim belirteci | Baştaki boşluk davranışı | 20 ve Enter sonrasında olası sonuç |
|---|---|---|
%d |
Sayının önündeki boşlukları atlar, sayıyı okur. | 20 okunur, sondaki n kalabilir. |
%f |
Ondalık sayının önündeki boşlukları atlar, sayıyı okur. | Sayı okunur, sondaki n kalabilir. |
%c |
Boşlukları otomatik olarak atlamaz, ilk karakteri okur. | Bekleyen n karakterini okuyabilir. |
Buradaki önemli ayrım, %d ve %f dönüşümlerinin sayıyı ararken baştaki boşlukları atlamasıdır. Bu davranış, sayının arkasında kalan Enter karakterinin de otomatik olarak temizlendiği anlamına gelmez. C standardındaki fscanf kuralları, giriş boşluklarının %c için kendiliğinden atlanmadığını belirtir.
scanf(" %c") ve getchar döngüsü nasıl kullanılır?

scanf(" %c", &cevap) içindeki baştaki boşluk, scanf'e önceki boşluk karakterlerini geçmesini ve ilk boşluk olmayan karakteri okumasını söyler. Giriş tamponu, klavyeden gelen karakterlerin program tarafından okunmayı beklediği alandır. Biçim belirteci ise %d ve %c gibi, okunacak verinin türünü ve okuma biçimini belirleyen ifadedir.
Örneğin yaş bilgisinden sonra e veya h okumak için aşağıdaki kullanım tercih edilebilir:
#include <stdio.h>
int main(void) {
int yas;
char cevap;
printf("Yasinizi girin: ");
if (scanf("%d", &yas) != 1) {
printf("Gecersiz yas girisi.n");
return 1;
}
printf("Devam etmek istiyor musunuz? (e/h): ");
if (scanf(" %c", &cevap) != 1) {
printf("Karakter okunamadi.n");
return 1;
}
printf("Yas: %dn", yas);
printf("Okunan karakter kodu: %dn", (unsigned char) cevap);
printf("Okunan karakter: %cn", cevap);
return 0;
}
Örneğin giriş olarak önce 20, ardından Enter ve sonra e yazıldığında program yaş değerini 20, karakter kodunu ise e karakterine karşılık gelen değer olarak yazdırır. scanf dönüş değerinin 1 olması, ilgili çağrıda bir değerin başarıyla okunup değişkene aktarıldığını gösterir. scanf işlevinin dönüş değeri ve biçim belirteçlerinin boşluk davranışı GNU C Library'nin biçimlendirilmiş giriş açıklamasında ayrıntılı olarak ele alınır.
Baştaki boşluk kullanılmadığında sorun yeniden ortaya çıkar:
if (scanf("%c", &cevap) != 1) {
printf("Karakter okunamadi.n");
return 1;
}
printf("Okunan karakter kodu: %dn", (unsigned char) cevap);
Bu çağrıdan önce scanf("%d", &yas) kullanıldıysa yaş olarak yazılan sayının ardından basılan Enter karakteri tamponda kalabilir. %c boşlukları atlamadığı için bu karakteri okur. Yaygın ASCII tabanlı ortamlarda yazdırılan karakter kodu 10 olur. Karakter ekrana görünmediğinden program cevabı atlamış gibi görünür.
Bir başka yaklaşım, sonraki okumadan önce satırın kalanını getchar ile tüketmektir:
#include <stdio.h>
int main(void) {
int yas;
int ch;
char cevap;
printf("Yasinizi girin: ");
if (scanf("%d", &yas) != 1) {
printf("Gecersiz yas girisi.n");
return 1;
}
while ((ch = getchar()) != 'n' && ch != EOF) {
}
printf("Devam etmek istiyor musunuz? (e/h): ");
if (scanf("%c", &cevap) != 1) {
printf("Karakter okunamadi.n");
return 1;
}
printf("Yas: %dn", yas);
printf("Okunan karakter kodu: %dn", (unsigned char) cevap);
printf("Okunan karakter: %cn", cevap);
return 0;
}
getchar döngüsü, satır sonuna ulaşıncaya veya dosya sonu durumunu gösteren EOF değerini görene kadar karakterleri okur. Böylece yaş bilgisinden sonra tamponda kalan Enter ve aynı satırdaki diğer karakterler tüketilir. Ardından scanf("%c", &cevap) kullanıldığında okunan karakter, yeni giriş satırının ilk karakteri olur. getchar dönüş değeri int tutulur; bunun nedeni getchar'ın normal karakter değerlerinin yanında EOF değerini de döndürebilmesidir.
scanf("%c ", &cevap) biçimindeki kullanım ise farklı davranır. Buradaki boşluk, karakter okunduktan sonra gelen boşluk, tab ve satır sonlarını tüketmeye çalışır. Kullanıcı e yazıp Enter'a bastığında program, Enter'dan sonra yeni bir boşluk olmayan karakter gelip gelmediğini anlamak için bekleyebilir. Tek bir karakter okuyup devam etmek istediğinde baştaki boşluk kullanmak veya satırı getchar döngüsüyle temizlemek daha anlaşılırdır.
fflush(stdin) neden çözüm sayılmaz?
fflush(stdin) kullanımı, giriş tamponunu temizlemek için taşınabilir ve güvenilir bir C çözümü değildir. ISO C standardına göre fflush, giriş akışına veya son işlemi giriş olan güncelleme akışına uygulandığında davranış tanımsızdır. Bu kural, ISO/IEC 9899:2024 standardındaki fflush açıklamasında yer alır.
Bazı derleyici veya çalışma ortamlarında fflush(stdin) beklenen şekilde çalışıyor gibi görünebilir. Ancak bu davranış standart C tarafından garanti edilmediği için aynı kod başka bir ortamda farklı sonuç verebilir. Girişte kalan karakterleri açıkça tüketmek gerektiğinde getchar döngüsü kullanılmalıdır.
fflush(stdin)kullanmak: Giriş akışını temizlemek için satır sonuna kadargetchardöngüsü kullan.%c'nin arkasına boşluk koymak: Tek karakter okumadascanf(" %c", &c)biçimindeki baştaki boşluğu tercih et.scanfdönüş değerini kontrol etmemek: Okuma başarılı olduğunda beklenen atama sayısını, bu örneklerde1değerini kontrol et.
Sık Sorulan Sorular
scanf("%d", &yas) sonrasında scanf("%c", &cevap) neden Enter karakterini okur?
scanf("%d", &yas) sayıyı okurken Enter karakterini tamponda bırakabildiği için sonraki %c çağrısı bu satır sonunu okur. %c başlangıçtaki boşlukları kendiliğinden atlamaz.
scanf(" %c", &c) içindeki baştaki boşluk neyi değiştirir?
Baştaki boşluk, girişte bulunan boşluk, tab ve satır sonu karakterlerinin geçilmesini sağlar. Ardından gelen ilk boşluk olmayan karakter c değişkenine aktarılır.
scanf("%c", &c) ifadesinin sonuna boşluk koymak neden bekleme davranışına yol açabilir?
Biçim dizesinin sonundaki boşluk, okunan karakterden sonra gelen boşlukları tüketmeye çalışır ve ilk boşluk olmayan karakteri arar. Etkileşimli girişte bu karakter henüz yazılmadıysa program yeni bir giriş bekleyebilir.
getchar döngüsü ile scanf(" %c", &c) arasında nasıl seçim yapılır?
Yalnızca boşlukları geçip ilk karakteri okumak istediğinde scanf(" %c", &c) pratik bir seçimdir. Önceki satırda kalan karakterlerin tamamını, satır sonuna kadar temizlemek istediğinde getchar döngüsü daha açık bir kontrol sağlar.
fflush(stdin) neden giriş tamponunu temizlemek için kullanılmamalıdır?
fflush(stdin), ISO C açısından giriş akışını temizlemek için tanımlı ve taşınabilir bir yöntem değildir. Tamponda kalan karakterleri kontrollü biçimde tüketmek için getchar döngüsü kullanılmalıdır.
scanf ile karakter okurken tamponda hangi karakterin kaldığını ve kullandığın biçim dizesinin boşlukları nasıl işlediğini kontrol etmek, sorunun kaynağını doğrudan görmeni sağlar.