Bu yaygın olarak tartışılan bir konudur, görüş dolu ama daha az ilginç değildir. Bu sitede benzer sorulara daha önce cevap vermiş olanların büyük bir çoğunluğunun şu tarafa düştüğünü gözlemledim: fgets()
. Ben de onlardan biriyim. Buluyorum fgets()
kullanıcı girişi için kullanmaktan çok daha iyi olmak scanf()
birkaç istisna dışında. scanf()
olduğunu kabul ederek birçok gibi alt-optimal yöntem kullanım için kullanıcı girişi. Örneğin
"...size başarılı olup olmadığını veya başarısız olup olmadığını söyleyecektir, ancak size yalnızca nerede başarısız olduğunu ve nasıl veya neden olduğunu söyleyemez. Sen
herhangi bir hata kurtarma yapmak için çok az fırsatınız var."
(jamesdlin). Ancak dengeye teşebbüs etmek adına, bu tartışmayı gerekçe göstererek başlayacağız.
Gelen kullanıcı girişi için stdin
klavye girişi, fgets()
daha iyi bir seçim olacaktır. Dönüşüm denenmeden önce okuduğu dizenin tamamen doğrulanabilmesi çok daha bağışlayıcıdır
Bir scanf(): fscanf() formunu kullanmanın birkaç zamanından biri, girişi çok kontrollü bir kaynaktan dönüştürürken, yani tahmin edilebilir alanları tekrarlayan kesin olarak biçimlendirilmiş bir dosyayı okurken kullanmak iyi olabilir.
Daha fazla tartışma için, ikisinin bu karşılaştırması, her ikisinin de ek avantajlarını ve dezavantajlarını vurgulamaktadır.
Edit: Adres OP ek soru hakkında taşması:
"Sormak istediğim bir şey daha var: fgets kullandığımızda bile, kullanıcı karakterleri sınırdan daha fazla girerse ne olur (çok fazla demek istiyorum
karakterler), arabellek taşmasına neden olur mu? O zaman nasıl başa çıkılır
mi?"
[fgets ()] (https://www.tutorialspoint.com/c_standard_library/c_function_fgets.htm parametrelerini düzgün bir şekilde kullanarak arabellek taşmasını önlemek için güzel bir şekilde tasarlanmıştır, örn.:
char buffer[100] = {0};
...
while fgets(buffer, sizeof buffer, stdin);
Bu, arabellek boyutundan daha büyük girdilerin işlenmesini engeller ve böylece taşmayı önler.
hatta kullanarak scanf()
arabellek taşmasını önlemek oldukça basittir: Biçim dizesinde bir genişlik belirticisi kullanın. Örneğin girişi okumak ve giriş boyutunu kullanıcıdan maksimum 100 karakterle sınırlamak istiyorsanız, kod aşağıdakileri içerir:
char buffer[101] = {0};// includes space for 100 + 1 for NULL termination
scanf("%100s", buffer);
^^^ width specifier
Ancak, sayılarla taşma kullanmak o kadar da hoş değil scanf()
. Göstermek için, çalışma başına bir yorumda belirtilen iki değeri girerek bu basit kodu kullanın:
int main(void)
{
int val = 0;
// test with 2147483647 & 2147483648
scanf("%d", &val);
printf("%d\n", val);
return 0;
}
İkinci değer için sistemim aşağıdakileri atar:
NON-FATAL RUN-TIME ERROR: "test.c", line 11, col 5, thread id 22832: Function scanf: (errno == 34 [0x22]). Range error
`
Burada bir dizede okumanız, ardından aşağıdakilerden birini kullanarak bir dizeden sayıya dönüşüm izlemeniz gerekir strto_()
fonksiyonlar: strtol (), strtod (),...). Her ikisi de çalışma zamanı uyarısı veya hatasına neden olmadan önce taşma olup olmadığını sınama yeteneğini içerir. Bunu kullanarak unutmayın atoi()
, atod()
taşmaya karşı da koruma sağlamaz.