इनपुट पढ़ने के बाद हम cin.clear () और cin.ignore () क्यों कहेंगे?


86

Google कोड विश्वविद्यालय का C ++ ट्यूटोरियल इस कोड का उपयोग करता है:

// Description: Illustrate the use of cin to get input
// and how to recover from errors.

#include <iostream>
using namespace std;

int main()
{
  int input_var = 0;
  // Enter the do while loop and stay there until either
  // a non-numeric is entered, or -1 is entered.  Note that
  // cin will accept any integer, 4, 40, 400, etc.
  do {
    cout << "Enter a number (-1 = quit): ";
    // The following line accepts input from the keyboard into
    // variable input_var.
    // cin returns false if an input operation fails, that is, if
    // something other than an int (the type of input_var) is entered.
    if (!(cin >> input_var)) {
      cout << "Please enter numbers only." << endl;
      cin.clear();
      cin.ignore(10000,'\n');
    }
    if (input_var != -1) {
      cout << "You entered " << input_var << endl;
    }
  }
  while (input_var != -1);
  cout << "All done." << endl;

  return 0;
}

का महत्व क्या है cin.clear()और cin.ignore()? क्यों 10000और \nपैरामीटर आवश्यक हैं?


1
यह मेरी अब तक की सबसे ज्यादा पोस्ट की गई पोस्ट है। मैंने हाई स्कूल में पढ़ाई की है।
जैकबाउन

जवाबों:


102

cin.clear()पर त्रुटि ध्वज को साफ करता है cin(ताकि भविष्य आई / ओ संचालन सही ढंग से काम करेंगे), और फिर cin.ignore(10000, '\n')अगले न्यू लाइन करने के लिए छोड़ देता है (गैर संख्या के रूप में एक ही लाइन पर कुछ और अनदेखी करने के लिए इतना है कि यह एक और पार्स विफलता का कारण नहीं है) । यह केवल 10000 वर्णों को छोड़ देगा, इसलिए कोड मान रहा है कि उपयोगकर्ता बहुत लंबी, अमान्य रेखा में नहीं डालेगा।


57
+1। मैं जोड़ना चाहता हूं कि 10000 वर्णों को अनदेखा करने के बजाय, इसका उपयोग करना बेहतर होगा cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
डेनिस

30
यदि आप उपयोग करना चाहते हैं std::numeric_limits, तो सुनिश्चित करें #include <limits>
gbmhunter

1
क्या कोई वाक्यविन्यास समझा सकता है std::numeric_limits<std::streamsize>::max()?
मिन्ह ट्रान

4
@ मिन्ह ट्रान: एसटीडी :: स्ट्रीम पर हस्ताक्षर किए गए हैं जो आई / ओ चरित्र हस्तांतरित या आई / ओ बफर के आकार की संख्या देते हैं। यहाँ, "num_limits" टेम्पलेट वर्ग का उपयोग करके हम I / O बफर या स्थानांतरित किए गए वर्ण की अधिकतम सीमा जानना चाहते थे।
पंकज

1
@ मिन्ह ट्रान: केवल एक मामूली सुधार "धारा" एक वर्ग नहीं है, यह सिर्फ एक अभिन्न प्रकार है। हम अन्य सीमाएं भी प्राप्त कर सकते हैं। int, char etc. .. कृपया इसे [लिंक] ( en.cppreference.com/w/cpp/types/numeric_limits )
पंकज

46

आप दर्ज करें

if (!(cin >> input_var))

स्टेटमेंट, यदि कोई त्रुटि सिनेमा से इनपुट लेते समय होती है। यदि कोई त्रुटि होती है, तो एक त्रुटि ध्वज सेट होता है और इनपुट प्राप्त करने के भविष्य के प्रयास विफल हो जाएंगे। इसलिए आपको जरूरत है

cin.clear();

त्रुटि ध्वज से छुटकारा पाने के लिए। इसके अलावा, जो इनपुट विफल हो गया है वह मेरे मान में बैठा होगा जो किसी प्रकार का बफर है। जब आप फिर से इनपुट प्राप्त करने का प्रयास करते हैं, तो यह बफर में उसी इनपुट को पढ़ेगा और यह फिर से विफल हो जाएगा। इसलिए आपको जरूरत है

cin.ignore(10000,'\n');

यह बफर से 10000 वर्णों को निकालता है, लेकिन यदि यह एक नई रेखा (\ n) का सामना करता है तो रुक जाता है। 10000 बस एक सामान्य बड़ा मूल्य है।


11
बस यह जोड़ना कि अनदेखा करने के लिए डिफ़ॉल्ट किसी एकल वर्ण को छोड़ना है, इसलिए आपको पूरी पंक्ति को छोड़ने के लिए बड़ी संख्या की आवश्यकता होती है।
बो पर्सन

22

हम क्यों उपयोग करते हैं:

1) Cin.ignore

2) Cin.clear

?

सीधे शब्दों में:

1) उन मूल्यों को अनदेखा करना (निकालना और त्यागना) जो हम धारा पर नहीं चाहते हैं

2) धारा की आंतरिक स्थिति को साफ करने के लिए। Cin.clear का उपयोग करने के बाद आंतरिक स्थिति को फिर से गुडबाय पर सेट किया जाता है, जिसका अर्थ है कि कोई 'त्रुटियाँ' नहीं हैं।

दीर्घ संस्करण:

अगर कोई चीज put स्ट्रीम ’(सिनेमा) पर रखी गई है तो उसे वहां से ले जाना चाहिए। By लिया ’से हमारा मतलब 'प्रयुक्त’, taken हटा ’,' निकाला’ धारा से है। धारा का प्रवाह है। डेटा स्ट्रीम पर पानी की तरह बह रहा है। आप बस पानी के बहाव को रोक नहीं सकते;)

उदाहरण देखो:

string name; //line 1
cout << "Give me your name and surname:"<<endl;//line 2
cin >> name;//line 3
int age;//line 4
cout << "Give me your age:" <<endl;//line 5
cin >> age;//line 6

यदि उपयोगकर्ता जवाब देता है तो क्या होता है: "अर्कादिअस व्लोडरस्कीज़" पहला सवाल?

अपने लिए देखने के लिए कार्यक्रम को चलाएं।

आप कंसोल पर "अर्कादिअस" देखेंगे, लेकिन कार्यक्रम आपसे 'उम्र' नहीं पूछेगा। यह "अर्कादिअस" मुद्रित करने के तुरंत बाद ही समाप्त हो जाएगा।

और "Wlodarczyk" नहीं दिखाया गया है। ऐसा लगता है जैसे यह चला गया था (?) *

क्या हुआ? ;-)

क्योंकि "अर्कादिअस" और "वलोडरस्कीज़" के बीच एक स्थान है।

नाम और उपनाम के बीच "स्थान" चरित्र कंप्यूटर के लिए एक संकेत है कि 'इनपुट' स्ट्रीम पर निकाले जाने के लिए दो चर हैं।

कंप्यूटर सोचता है कि आप एक से अधिक वेरिएबल में इनपुट भेजने के लिए बांध रहे हैं। उस तरह से व्याख्या करने के लिए "स्पेस" चिन्ह उसके लिए एक संकेत है।

इसलिए कंप्यूटर "अर्कादिअस" को 'नाम' (2) में निर्दिष्ट करता है और क्योंकि आप स्ट्रीम (इनपुट) पर एक से अधिक स्ट्रिंग डालते हैं, कंप्यूटर "व्लोडरस्की" को वैरिएबल 'उम्र' (!) में रखने की कोशिश करेगा। उपयोगकर्ता को लाइन 6 में 'Cin' पर कुछ भी डालने का मौका नहीं मिलेगा क्योंकि उस निर्देश को पहले ही निष्पादित किया गया था (!)। क्यों? क्योंकि धारा पर अभी भी कुछ बाकी था। और जैसा कि मैंने कहा कि पहले की धारा एक प्रवाह में है इसलिए जितनी जल्दी हो सके सब कुछ इसे से हटा दिया जाना चाहिए। और संभावना तब हुई जब कंप्यूटर ने निर्देश देखें >> आयु;

कंप्यूटर को पता नहीं है कि आपने एक चर बनाया है जो किसी की उम्र (पंक्ति 4) को संग्रहीत करता है। label उम्र ’एक लेबल मात्र है। कंप्यूटर के लिए 'आयु' के रूप में अच्छी तरह से कहा जा सकता है: 'afsfasgfsagasggas' और यह वही होगा। उसके लिए यह सिर्फ एक चर है कि वह "Wlodarczyk" को असाइन करने का प्रयास करेगा क्योंकि आपने कंप्यूटर को लाइन में ऐसा करने का आदेश दिया था / निर्देश दिया था (6)।

ऐसा करना गलत है, लेकिन हे यह तो तुमने ही किया है! यह आपकी गलती है! खैर, शायद उपयोगकर्ता, लेकिन फिर भी ...


ठीक है ठीक है। लेकिन इसे कैसे ठीक करें ?!

आइए कुछ और रोचक बातें जानने के लिए ठीक से ठीक करने से पहले उस उदाहरण के साथ खेलने की कोशिश करें :-)

मैं एक दृष्टिकोण बनाना पसंद करता हूं जहां हम चीजों को समझते हैं। ज्ञान के बिना कुछ तय करना कि हमने कैसे किया, इससे संतुष्टि नहीं मिलती, क्या आपको नहीं लगता? :)

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate(); //new line is here :-)

ऊपर दिए गए कोड को लागू करने के बाद आप देखेंगे कि आपकी धारा (Cin) की स्थिति 4 (पंक्ति 7) के बराबर है। जिसका अर्थ है कि इसकी आंतरिक स्थिति अब गुडबिट के बराबर नहीं है। कुछ गड़बड़ है। यह बहुत स्पष्ट है, है ना? आपने चर 'आयु' टाइप करने के लिए स्ट्रिंग प्रकार मान ("Wlodarczyk") आवंटित करने का प्रयास किया। प्रकार मेल नहीं खाते। यह सूचित करने का समय है कि कुछ गलत है। और कंप्यूटर धारा की आंतरिक स्थिति को बदलकर करता है। यह पसंद है: "आप च **** अप यार, मुझे ठीक कर दो। मैं आपको 'कृपया' सूचित करता हूं ;-)

आप अब 'Cin' (स्ट्रीम) का उपयोग नहीं कर सकते। यह अटक गया है। जैसे अगर आपने पानी की धारा पर बड़ी लकड़ी की लकड़ियाँ डाल दी हैं। इसका उपयोग करने से पहले आपको इसे ठीक करना होगा। डेटा (पानी) उस धारा (कूल्हे) से प्राप्त नहीं किया जा सकता है क्योंकि लकड़ी का लॉग (आंतरिक स्थिति) आपको ऐसा करने की अनुमति नहीं देता है।

ओह, अगर कोई बाधा है (लकड़ी के लॉग) तो हम इसे केवल उन उपकरणों का उपयोग करके निकाल सकते हैं जो ऐसा करने के लिए बने हैं?

हाँ!

4 पर सेट की आंतरिक स्थिति एक अलार्म की तरह होती है जो हॉलिंग और शोर करती है।

cin.clear राज्य को वापस सामान्य (गुडबिट) में साफ़ करता है। यह ऐसा है जैसे आप आए और अलार्म को चुप करा दिया। तुम बस लगा दो। आपको पता है कि ऐसा कुछ हुआ है, इसलिए आप कहते हैं: "यह ठीक है कि शोर करना बंद कर दें, मुझे पता है कि कुछ पहले से ही गलत है, चुप रहो (स्पष्ट)"।

चलो ठीक है! चलो Cin.clear () का उपयोग करें।

पहले इनपुट के रूप में "अर्कादिअस व्लोडरस्कीज़" का उपयोग करके कोड नीचे दर्ज करें:

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl; 
cin.clear(); //new line is here :-)
cout << cin.rdstate()<< endl;  //new line is here :-)

हम उपरोक्त कोड को निष्पादित करने के बाद निश्चित रूप से देख सकते हैं कि राज्य गुडबिट के बराबर है।

महान तो समस्या हल हो गई है?

पहले इनपुट के रूप में "अर्कादिअस व्लोडरस्कीज़" का उपयोग करके कोड नीचे दर्ज करें:

string name;
cout << "Give me your name and surname:"<<endl;
cin >> name;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << cin.rdstate() << endl;; 
cin.clear(); 
cout << cin.rdstate() << endl; 
cin >> age;//new line is here :-)

यहां तक ​​कि राज्य को पंक्ति 9 के बाद गुडबाइट करने के लिए सेट किया गया है उपयोगकर्ता को "उम्र" के लिए नहीं पूछा गया है। कार्यक्रम रुक गया।

क्यों?!

अरे यार ... तुम बस अलार्म लगा दो, एक पानी के अंदर लकड़ी के लॉग के बारे में क्या? * पाठ पर वापस जाएं जहां हमने "व्लोडरस्की" के बारे में बात की थी कि यह कैसे माना जाता है।

आपको धारा से लकड़ी के उस टुकड़े को "वलोडरस्कीज़" को हटाने की आवश्यकता है। अलार्म बंद करने से समस्या हल नहीं होती है। आपने इसे चुप कर दिया है और आपको लगता है कि समस्या दूर हो गई है? ;)

तो यह एक और उपकरण के लिए समय है:

Cin.ignore की तुलना एक विशेष ट्रक से की जा सकती है जिसमें रस्सियाँ आती हैं और लकड़ी के लॉग को हटा देती है जो धारा अटक गई। यह आपके द्वारा बनाए गए प्रोग्राम के उपयोगकर्ता की समस्या को दूर करता है।

तो क्या अलार्म बंद होने से पहले ही हम इसका इस्तेमाल कर सकते हैं?

हाँ:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;

लाइन 7 में शोर करने से पहले "Wlodarczyk" को हटा दिया जाएगा।

10000 और '\ n' क्या है?

यह कहता है कि 10000 वर्णों को हटा दें (केवल मामले में) जब तक '\ n' पूरा नहीं हो जाता (ENTER)। BTW यह num_limits का उपयोग करके बेहतर किया जा सकता है लेकिन यह इस उत्तर का विषय नहीं है।


तो समस्या का मुख्य कारण शोर करने से पहले ही चला गया है ...

हमें 'स्पष्ट' की आवश्यकता क्यों है?

क्या होगा अगर किसी ने 6 साल की उम्र में 'मुझे अपनी उम्र दे दो' सवाल पूछा है: 20 लिखने के बजाय "बीस साल पुराना"?

प्रकार फिर से मेल नहीं खाते। कंप्यूटर int को स्ट्रिंग असाइन करने की कोशिश करता है। और अलार्म बजने लगता है। आप इस तरह की स्थिति पर भी प्रतिक्रिया करने का मौका नहीं है। Cin.ignore उस मामले में आपकी मदद नहीं करेगा।

तो हम इस तरह के मामले में स्पष्ट उपयोग करना चाहिए:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
int age;
cout << "Give me your age:" << endl;
cin >> age;
cin.clear();
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow

लेकिन क्या आपको राज्य को 'सिर्फ मामले में' साफ करना चाहिए?

बिलकूल नही।

यदि कुछ गलत हो जाता है (Cin >> age;) अनुदेश आपको इसके बारे में सूचित करता है तो वह गलत तरीके से लौटता है।

इसलिए हम यह जांचने के लिए सशर्त विवरण का उपयोग कर सकते हैं कि उपयोगकर्ता ने स्ट्रीम पर गलत प्रकार डाला है या नहीं

int age;
if (cin >> age) //it's gonna return false if types doesn't match
    cout << "You put integer";
else
    cout << "You bad boy! it was supposed to be int";

ठीक है तो हम अपनी प्रारंभिक समस्या को ठीक कर सकते हैं जैसे कि उदाहरण के लिए:

string name;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow

int age;
cout << "Give me your age:" << endl;
if (cin >> age)
  cout << "Your age is equal to:" << endl;
else
{
 cin.clear();
 cin.ignore(10000, '\n'); //time to remove "Wlodarczyk" the wood log and make the stream flow
 cout << "Give me your age name as string I dare you";
 cin >> age;
}

बेशक, उदाहरण के लिए यह सुधार किया जा सकता है कि आपने प्रश्न का उपयोग करते समय क्या किया था।

बक्शीश:

आप सोच रहे होंगे। यदि मैं उपयोगकर्ता से एक ही पंक्ति में नाम और उपनाम प्राप्त करना चाहता था तो क्या होगा? क्या यह भी संभव है कि यदि सिनेमा "स्पेस" द्वारा अलग-अलग वैरिएबल के रूप में अलग-अलग मूल्य की व्याख्या करता है, तो सिने का उपयोग करना संभव है?

ज़रूर, आप इसे दो तरीके से कर सकते हैं:

1)

string name, surname;
cout << "Give me your name and surname:"<< endl;
cin >> name;
cin >> surname;

cout << "Hello, " << name << " " << surname << endl;

2) या गेटलाइन फ़ंक्शन का उपयोग करके।

getline(cin, nameOfStringVariable);

और यह कैसे करना है:

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

दूसरा विकल्प यह हो सकता है कि गेटलाइन से पहले 'सिने' का उपयोग करने के बाद आप इसका उपयोग करें।

चलो पता करते हैं:

ए)

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endl;

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

यदि आप उम्र के रूप में "20" डालते हैं तो आपसे nameAndSurname नहीं पूछा जाएगा।

लेकिन अगर आप इसे इस तरह से करते हैं:

ख)

string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;
int age;
cout << "Give me your age:" <<endl;
cin >> age;
cout << "Your age is" << age << endll

सब कुछ ठीक है।

क्या?!

हर बार जब आप इनपुट (स्ट्रीम) पर कुछ डालते हैं, तो आप अंत में सफेद वर्ण पर छोड़ देते हैं जो कि ENTER ('\ n') होता है। आपको किसी तरह कंसोल में मान दर्ज करना होगा। यदि उपयोगकर्ता से डेटा आता है तो ऐसा होना चाहिए।

b) सिनेमा की खासियत यह है कि यह व्हाट्सएप को नजरअंदाज करता है, इसलिए जब आप सिनेमा से जानकारी में पढ़ रहे होते हैं, तो नया चरित्र '\ n' मायने नहीं रखता। इसे नजरअंदाज कर दिया जाता है।

a) गेटलाइन फ़ंक्शन को पूरी लाइन न्यूलाइन वर्ण ('\ n') तक मिलती है, और जब न्यूलाइन चार पहली चीज़ होती है तो गेटलाइन फ़ंक्शन '\ n' हो जाता है, और यह सब प्राप्त करना है। आप उपयोगकर्ता द्वारा स्ट्रीमलाइन पर छोड़ी गई नई लाइन वर्ण को निकालते हैं, जिसने लाइन 3 में "20" को स्ट्रीम पर रखा था।

तो इसे ठीक करने के लिए हमेशा Cin.ignore () को लागू करना है; यदि आप कभी भी अपने प्रोग्राम के अंदर गेटलाइन () का उपयोग करने जा रहे हैं तो आप किसी भी मूल्य को प्राप्त करने के लिए सिनेमा का उपयोग करते हैं।

तो उचित कोड होगा:

int age;
cout << "Give me your age:" <<endl;
cin >> age;
cin.ignore(); // it ignores just enter without arguments being sent. it's same as cin.ignore(1, '\n') 
cout << "Your age is" << age << endl;


string nameAndSurname;
cout << "Give me your name and surname:"<< endl;
getline(cin, nameAndSurname);

cout << "Hello, " << nameAndSurname << endl;

मुझे आशा है कि धाराएँ आपके लिए अधिक स्पष्ट हैं।

हाहा चुप करो मुझे! :-)


1

बफ़र में cin.ignore(1000,'\n')पिछले सभी वर्णों को साफ़ करने के लिए उपयोग करें cin.get()और यह '\ n' या 1000 charsपहले मिलने पर बंद होने का चयन करेगा ।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.