2009-05-14 13 views
6

an answer में एक दिलचस्प बयान नहीं थी:। "यह fscanf() समारोह का उपयोग करने के रूप में यह विफलता पर एक अज्ञात स्थान में अपनी फ़ाइल सूचक छोड़ सकते हैं लगभग हमेशा एक बुरा विचार है मैं fgets() का उपयोग करने के प्रत्येक पंक्ति पाने के लिए पसंद करते हैं और उसके बाद sscanf() वह। "fscanf() फ़ंक्शन का उपयोग करने का बुरा विचार कब/क्यों है?

क्या आप कुछ फ़ाइल पढ़ने के लिए fgets() और sscanf() का उपयोग करना बेहतर हो सकता है?

उत्तर

13

तीन लाइनों के साथ एक फ़ाइल की कल्पना कीजिए:

1 
    2b 
    c 

fscanf() का उपयोग पूर्णांकों को पढ़ने के लिए, पहली पंक्ति ठीक पढ़ा होगा, लेकिन दूसरी पंक्ति पर fscanf() 'बी' में आप छोड़ना होगा, क्या करना है यकीन नहीं वहां से। तीसरी पंक्ति देखने के लिए आपको कचरा इनपुट के पीछे जाने के लिए कुछ तंत्र की आवश्यकता होगी।

यदि आप fgets() और sscanf() करते हैं, तो आप गारंटी दे सकते हैं कि आपकी फ़ाइल सूचक एक समय में एक पंक्ति को ले जाती है, जो कि निपटने के लिए थोड़ा आसान है। आम तौर पर, आपको अभी भी किसी भी विषम वर्णों की रिपोर्ट करने के लिए पूरी स्ट्रिंग को देखना चाहिए।

मैं बाद दृष्टिकोण अपने आप को पसंद करते हैं, हालांकि मैं बयान "यह लगभग हमेशा एक बुरा विचार fscanf() उपयोग करने के लिए" के साथ सहमत नहीं हैं ... fscanf() सबसे बातों के लिए बिल्कुल ठीक है।

+1

कृपया बदल 'हो जाता है()' 'fgets करने के लिए()'। '() को कभी भी इस्तेमाल नहीं किया जाना चाहिए। – Wiz

+0

एक टाइपो होना चाहिए :) इसे पकड़ने के लिए धन्यवाद। –

0

असल में, उस कार्य को को बताए गए मेमोरी क्षेत्र के लिए सीमाओं से बाहर जाने के लिए कोई तरीका नहीं है।

fnscanf की तरह कई प्रतिस्थापन सामने आए हैं, जो पाठकों को लिखने के लिए अधिकतम सीमा निर्दिष्ट करके उन कार्यों को ठीक करने का प्रयास है, इस प्रकार इसे ओवरफ़्लो नहीं होने की अनुमति मिलती है।

+1

जबकि बफर ओवरफ्लो स्कैनफ() परिवार के कार्यों के साथ एक समस्या है, वे यहां पूछे गए समस्या से असंबंधित हैं। -1 – Sparr

+1

"क्या आप विस्तार कर सकते हैं कि कुछ फाइल पढ़ने के लिए fgets() और sscanf() का उपयोग करना बेहतर क्यों हो सकता है।" मैं अपने प्रश्न पर विस्तार कर रहा था। मैंने आपके अतिव्यापी "-1" – cyberconte

+1

को अस्वीकार कर दिया है, इसका मतलब यह है कि आपका जवाब पहले से प्रस्तुत किए गए आधार पर आधारित होना चाहिए, जो फ़ाइल सूचक समस्या है। अगर वह अन्य कारण चाहते थे तो वह प्रश्न की उत्पत्ति से जुड़े नहीं होंगे, या इसके प्रासंगिक भाग को उद्धृत नहीं करेंगे। – Sparr

2

जब इनपुट विफलता या मिलान विफलता के कारण fscanf() विफल हो जाता है, तो फ़ाइल सूचक (यानी, उस फ़ाइल में स्थिति जिसमें से अगले बाइट पढ़ा जाएगा) इसे अन्य स्थितियों में छोड़ दिया जाता है fscanf() सफल होगा। अनुक्रमिक फ़ाइल पढ़ने में यह आमतौर पर अवांछनीय है। एक समय में एक पंक्ति को पढ़ने से फ़ाइल इनपुट अनुमानित हो सकता है, जबकि सिंगल लाइन असफलताओं को व्यक्तिगत रूप से संभाला जा सकता है।

1

fscanf() फ़ंक्शन का उपयोग करना लगभग हमेशा एक बुरा विचार है क्योंकि यह विफलता पर किसी अज्ञात स्थान पर आपकी फ़ाइल पॉइंटर को छोड़ सकता है। मैं प्रत्येक पंक्ति में sscanf() प्राप्त करने के लिए fgets() का उपयोग करना पसंद करता हूं।

आप फ़ाइल में वर्तमान स्थिति का पता लगाने के लिए हमेशा ftell() का उपयोग कर सकते हैं, और फिर निर्णय लें कि वहां से क्या करना है। मूल रूप से, यदि आप जानते हैं कि आप क्या उम्मीद कर सकते हैं तो fscanf() का उपयोग करने में संकोच न करें।

4

यह मामला जहां खेल में आता है वह तब होता है जब आप चरित्र अक्षर से मेल खाते हैं। मान लीजिए आप है:

int n = fscanf(fp, "%d,%d", &i1, &i2); 

दो संभव आदानों "323,A424" और "323A424" पर विचार करें।

दोनों मामलों में fscanf() 1 वापस आ जाएगा और अगला चरित्र पढ़ा जाएगा 'A'।यह निर्धारित करने का कोई तरीका नहीं है कि अल्पविराम मिलान किया गया था या नहीं।

कहा जा रहा है, यह केवल तभी महत्वपूर्ण है जब त्रुटि का वास्तविक स्रोत खोजना महत्वपूर्ण है। ऐसे मामलों में जहां विकृत इनपुट त्रुटि पर्याप्त है, fscanf() वास्तव में कस्टम पार्सिंग कोड लिखने से बेहतर है।

2

इसके दो कारण हैं:

  • scanf() एक राज्य है कि भविष्यवाणी करना मुश्किल है में stdin छोड़ सकते हैं; यह असंभव नहीं होने पर त्रुटि पुनर्प्राप्ति मुश्किल बनाता है (यह fscanf() के साथ कोई समस्या नहीं है); और
  • पूरे scanf() परिवार तर्क के रूप में पॉइंटर्स लेते हैं, लेकिन कोई लंबाई सीमा नहीं है, इसलिए वे बफर को ओवरराउन कर सकते हैं और बफर के बाद होने वाले असंबंधित चर बदल सकते हैं, जो यादृच्छिक स्मृति भ्रष्टाचार त्रुटियों को समझते हैं जो समझना बहुत मुश्किल है, ढूंढें, और विशेष रूप से कम अनुभवी सी प्रोग्रामर के लिए डिबग करें।

नौसिखिए सी प्रोग्रामर अक्सर संकेत और "पता-की" ऑपरेटर के बारे में उलझन में हैं, और अक्सर "अच्छा उपाय" & आवश्यकतानुसार छोड़ देते हैं, या जोड़ने यह जहां यह नहीं है। इससे "यादृच्छिक" segfaults का कारण बनता है जो उनके लिए खोजना मुश्किल हो सकता है। यह scanf() की गलती नहीं है, इसलिए मैं इसे अपनी सूची से छोड़ देता हूं, लेकिन यह ध्यान में लायक है।

23 के बाद साल, मैं अभी भी याद जब मैं सी प्रोग्रामिंग शुरू कर दिया और पता नहीं था समझते हैं और डिबग करने के लिए कैसे त्रुटियों के इन प्रकार यह एक बड़ी दर्द जा रहा है, और (कोई है जो साल बिताए शिक्षण के रूप में सी शुरुआती लोगों के लिए) उन्हें एक नौसिखिया को समझाना बहुत मुश्किल है जो अभी तक पॉइंटर्स और स्टैक को समझ नहीं पा रहा है।

कोई भी जो scanf() को नौसिखिया सी प्रोग्रामर को निर्दयतापूर्वक फंस जाना चाहिए।

ठीक है, शायद नहीं निर्दयता से, लेकिन जिस्मानी सज़ा किसी तरह के क्रम में निश्चित रूप से है, ओ)

+0

कथन "तर्क के रूप में पॉइंटर्स लेते हैं, लेकिन कोई लंबाई सीमा नहीं है" भ्रामक है: अधिकांश प्रकारों के लिए, आकार तय किए जाते हैं ('% i','% d', '% lf') इसलिए लंबाई सीमा की आवश्यकता नहीं होती है। एक अपवाद '% s' के साथ तार पढ़ने के लिए है।लेकिन इसके साथ ही, 'char '[100]' के रूप में घोषित वर्ण स्ट्रिंग के लिए '%' और 's':'% 99s' के बीच एक संख्या जोड़कर एक सीमा निर्दिष्ट की जा सकती है। –

संबंधित मुद्दे