2012-06-07 32 views
5

मैं निम्नलिखित कार्यक्रम में स्कैनफ़ के व्यवहार के बारे में उलझन में हूं। स्कैनफ एक बार इनपुट करने के लिए प्रतीत होता है, और उसके बाद फिर से इनपुट नहीं होता है, जब तक कि अक्षरों की एक धारा मुद्रित न हो जाए।स्कैनफ़ इनपुट इनपुट छोड़ने के लिए क्यों दिखाई देता है?

#include<stdio.h> 
int main() 
{ 
    int i, j=0; 

    do 
    { 
     ++j; 
     scanf("%d", &i); 
     printf("\n\n%d %d\n\n", i, j); 
    } 
    while((i!=8) && (j<10)); 

    printf("\nJ = %d\n", j); 
    return 0; 
} 

यहाँ एक सी कार्यक्रम में नीचे, जब तक मैं किसी भी पूर्णांक कार्यक्रम inputting हूँ पूरी तरह से ठीक काम करता है, लेकिन जब एक चरित्र इनपुट किया जाता है यह तक मैं के अंतिम inputed मूल्य मुद्रण पर चला जाता है और कभी नहीं बंद हो जाता है (जेड 10 है जब लूप निकलता है) स्कैनफ के लिए अगले इनपुट लेना।

output:: 
1 <-----1st input 
1 1 
2 <---- 2nd input 
2 2 
a <---- character input 
2 3 
2 4 
2 5 
2 6 
2 7 
2 8 
2 9 
2 10 

J = 10 

सी ++ में भी यही बात हो रही है।

#include<iostream> 
using namespace std; 
int main() 
{ 
    int i, j=0; 

    do 
    { 
     ++j; 
     cin>>i; 
     cout<<i<<" "<<j<<"\n"; 
    } 
    while((i!=8) && (j<10)); 

    cout<<"\nj = "<<j<<"\n"; 
} 


output of c++ program :: 
1  <-----1st input 
1 1 
2  <-----2nd input 
2 2 
a <------ character input 
0 3 
0 4 
0 5 
0 6 
0 7 
0 8 
0 9 
0 10 

j = 10 

केवल सी ++ में परिवर्तन यह है कि 0 को अंतिम मूल्य के बजाय मुद्रित किया जा रहा है।

मुझे पता है कि प्रोग्राम द्वारा पूर्णांक मानों की अपेक्षा की जाती है, लेकिन मैं जानना चाहता हूं कि जब एक पूर्णांक के स्थान पर चरित्र इनपुट किया जाता है तो क्या होता है? उपरोक्त सभी का क्या कारण है?

+1

यह आपकी मदद कर सकता है: http://www.parashift.com/c++-faq-lite/input-output.html#faq-15.3। अगला जवाब पृष्ठभूमि पर थोड़ा और बताता है। – chris

+1

[scff() misbehaving के संभावित डुप्लिकेट] (http://stackoverflow.com/questions/5062646/scanf-misbehaving) –

उत्तर

5

जब आप a दर्ज करें, फिर cin >> i इसे पढ़ने के लिए विफल रहता है क्योंकि i के प्रकार int को जो एक चरित्र पढ़ा नहीं जा सकता है। इसका मतलब है, a स्ट्रीम में हमेशा के लिए रहता है।

अब i प्रिंट 0 एक अलग कहानी है। असल में यह कुछ भी प्रिंट कर सकते हैं। पढ़ने के प्रयास विफल होने पर i की सामग्री को परिभाषित नहीं किया गया है। इसी तरह की चीज scanf के साथ भी होती है।

उचित तरीके से यह इस लिखने के लिए:

int i = 0, j = 0; 
while((i!=8) && (j<10) && (cin >> i)) 
{ 
    ++j; 
    cout<<i<<" "<<j<<"\n"; 
} 
+0

चाहे यह उचित है या नहीं, आप इनपुट त्रुटियों को कैसे संभालना चाहते हैं इस पर निर्भर करता है। –

+0

@ बेंजामिन लिंडले: सच। इसलिए मेरी पोस्ट संपादित करें। – Nawaz

+0

'" पढ़ने की कोशिश विफल होने के बाद मुझे परिभाषित नहीं किया गया है "' cin >> i' के लिए, यह सी ++ 11 में परिभाषित किया गया है – Cubbi

2

आप अपने उपयोगकर्ताओं को वैध प्रवेश करने की उम्मीद कभी नहीं कर सकते हैं:

do 
{ 
    ++j; 
    if (!(cin>>i)) 
    { 
     //handle error, maybe you want to break the loop here? 
    } 
    cout<<i<<" "<<j<<"\n"; 
} 
while((i!=8) && (j<10)); 

या बस यह (आप अगर त्रुटि तब होती है पाश से बाहर निकलना चाहते हैं) बातें। सबसे अच्छा अभ्यास read the input into a string and try to convert it to integer है। If the input is not an integer, आप उपयोगकर्ता को एक त्रुटि संदेश दे सकते हैं।

5

यदि scanf इनपुट स्ट्रीम में एक वर्ण देखता है जो रूपांतरण विनिर्देश से मेल नहीं खाता है, तो यह रूपांतरण को रोकता है और इनपुट स्ट्रीम में अपमानजनक चरित्र को छोड़ देता है।

इससे निपटने के कुछ तरीके हैं। एक सब कुछ पाठ के रूप में पढ़ना है (scanf%s या %[ रूपांतरण विनिर्देशक या fgets के साथ) और फिर रूपांतरण (मेरी पसंदीदा विधि) करने के लिए atoi या strtol का उपयोग करें।

वैकल्पिक रूप से, आप scanf के वापसी मूल्य की जांच कर सकते हैं; यह सफल रूपांतरणों की संख्या इंगित करेगा। इसलिए, यदि scanf("%d", &i); 0 के बराबर है, तो आप जानते हैं कि इनपुट स्ट्रीम में एक खराब चरित्र है। आप इसे getchar() से उपभोग कर सकते हैं और पुनः प्रयास करें।

2

समस्या यह है कि जब आप एक निवेश है कि उम्मीद प्रकार (scanf के लिए %d द्वारा निर्दिष्ट की नहीं है, और cin>>i; के लिए int प्रकार, InputStream उन्नत नहीं है, जो एक ही निकालने की कोशिश कर दोनों के संचालन में जो परिणाम है सटीक उसी गलत इनपुट से डेटा का प्रकार (और साथ ही साथ इस समय भी असफल हो रहा है), इस प्रकार आप कभी भी किसी अन्य इनपुट के लिए नहीं पूछेंगे।

यह सुनिश्चित करने के लिए कि आपको दोनों के वापसी मूल्य की जांच करने की आवश्यकता होगी संचालन (प्रत्येक रिपोर्ट त्रुटियों के लिए मैन्युअल पढ़ें)। यदि कोई त्रुटि होती है (जब आप कोई वर्ण दर्ज करते हैं), तो आपको त्रुटि को साफ़ करने, अमान्य इनपुट का उपभोग करने की आवश्यकता होगी और पुनः प्रयास करें। मुझे int या std::string के बजाय std::gtline() का उपयोग करके पूरी लाइन को पढ़ने के लिए सी ++ में बेहतर लगता है, जब आप थर्म उपयोगकर्ता से इंटरैक्टिव रूप से इनपुट प्राप्त करते हैं, तो आप इस "अनंत" लूप में अनुभव करते हैं।

1

आप वापसी मूल्य को अनदेखा कर रहे हैं। देखें कि कौन सी मैन्युअल scanf(3) के बारे में कहते हैं:

RETURN VALUE
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

यह एक पूर्णांक मिलान विफल रहता है।

1

scanf के लिए, आपको इनपुट पर रूपांतरण करने के लिए यह देखने के लिए अपने वापसी मूल्य की जांच करनी होगी। scanf सफलतापूर्वक स्कैन किए गए तत्वों की संख्या लौटाएगा। यदि रूपांतरण काम नहीं करता है, तो यह अकेले इनपुट छोड़ देगा, और आप इसे अलग-अलग स्कैन करने का प्रयास कर सकते हैं, या केवल एक त्रुटि की रिपोर्ट कर सकते हैं। उदाहरण के लिए:

if (scanf("%d", &i) != 1) { 
    char buf[512]; 
    fgets(buf, sizeof(buf), stdin); 
    printf("error in line %d: got %s", j, buf); 
    return 0; 
} 

अपने कार्यक्रम में, के बाद से इनपुट अकेला छोड़ दिया जाता है, अपने पाश ही इनपुट को पढ़ने का प्रयास दोहराया जाता है।

सी ++ में, आप fail विधि का उपयोग करके विफलता की जांच करते हैं, लेकिन इनपुट स्ट्रीम विफलता स्थिति चिपचिपा है। तो यह आपको त्रुटि स्थिति को साफ़ किए बिना आगे स्कैन करने नहीं देगा।

std::cin >> i; 
    if (std::cin.fail()) { 
     std::string buf; 
     std::cin.clear(); 
     std::getline(cin, buf); 
     std::cout 
      << "error in line " << j 
      << ": got " << buf 
      << std::endl; 
     return 0; 
    } 

अपने प्रोग्राम में, जब से तुम विफलता राज्य स्पष्ट कभी नहीं, एक विफलता राज्य में cin का उपयोग कर तो यह सिर्फ कुछ भी करने के बिना विफलता रिपोर्ट पाश दोहराता है।

दोनों मामलों में, यदि आप पहले इनपुट लाइन में पढ़ेंगे, तो इनपुट इनपुट के साथ काम करने के लिए आपको आसान या अधिक विश्वसनीय मिल सकता है, और फिर इनपुट लाइन को पार्स करने का प्रयास करें। स्यूडोकोड में:

while read_a_line succeeds 
    parse_a_line 

सी में, एक पंक्ति को पढ़ने के लिए पकड़ है कि अगर यह आपके बफर से अधिक लंबी है, तो आप उस के लिए जाँच करें और पंक्ति के रूप में करने के लिए एक साथ कई fgets कॉल परिणामों को श्रेणीबद्ध करने की आवश्यकता होगी है। और, एक पंक्ति को पार्स करने के लिए, आप sscanf का उपयोग कर सकते हैं, जो scanf के समान है लेकिन स्ट्रिंग पर काम करता है।

if (sscanf(buf, "%d", &i) != 1) { 
     printf("error in line %d: got %s", j, buf); 
     return 0; 
    } 

सी ++ में, स्वरूपित इनपुट के त्वरित निम्न स्तर पार्सिंग के लिए, मैं भी sscanf पसंद करते हैं। लेकिन, यदि आप स्ट्रीम दृष्टिकोण का उपयोग करना चाहते हैं, तो आप इनपुट को स्कैन करने के लिए string बफर को istringstream में परिवर्तित कर सकते हैं।

std::getline(cin, buf); 
    if (std::cin.fail()) { 
     break; 
    } 
    std::istringstream buf_in(buf); 
    buf_in >> i; 
    if (buf_in.fail()) { 
     std::cout << "error in line " << j 
      << ": got " << buf 
      << std::endl; 
     return 0; 
    } 
1

आप scanf की वापसी मूल्य की जांच कर सकता निर्धारित करने के लिए एक पूर्णांक ठीक प्रकार से पार्स किया गया है (वापसी करना चाहिए = 1)। विफलता पर, आपके पास विकल्प हैं: या तो त्रुटि के उपयोगकर्ता को सूचित करें और समाप्त करें, या scanf("%s" ...) के साथ अगले टोकन को एक चेतावनी के साथ पढ़कर पुनर्प्राप्त करें।

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