C में इनपुट बफर कैसे साफ़ करें?


84

मेरे पास निम्नलिखित कार्यक्रम हैं:

int main(int argc, char *argv[])
{
  char ch1, ch2;
  printf("Input the first character:"); // Line 1
  scanf("%c", &ch1); 
  printf("Input the second character:"); // Line 2
  ch2 = getchar();

  printf("ch1=%c, ASCII code = %d\n", ch1, ch1);
  printf("ch2=%c, ASCII code = %d\n", ch2, ch2);

  system("PAUSE");  
  return 0;
}

जैसा कि उपरोक्त कोड के लेखक ने समझाया है: प्रोग्राम ठीक से काम नहीं करेगा क्योंकि लाइन 1 पर, जब उपयोगकर्ता एंटर दबाएगा, तो यह इनपुट बफर 2 चरित्र में छोड़ देगा: Enter key (ASCII code 13)और \n (ASCII code 10)। इसलिए, लाइन 2 पर, यह पढ़ेगा \nऔर एक चरित्र में प्रवेश करने के लिए उपयोगकर्ता की प्रतीक्षा नहीं करेगा।

ठीक है, मुझे यह मिल गया। लेकिन मेरा पहला सवाल है: चरित्र के बजाय दूसरा getchar()( ch2 = getchar();) क्यों नहीं पढ़ा जाता है ?Enter key (13)\n

इसके बाद, लेखक ने ऐसे प्रोब्लेम्स को हल करने के लिए 2 तरीके प्रस्तावित किए:

  1. उपयोग fflush()

  2. इस तरह एक समारोह लिखें:

    void
    clear (void)
    {    
      while ( getchar() != '\n' );
    }
    

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

जवाबों:


89

प्रोग्राम ठीक से काम नहीं करेगा क्योंकि लाइन 1 पर, जब उपयोगकर्ता Enter दबाता है, तो यह इनपुट बफर 2 वर्ण में छोड़ देगा: कुंजी दर्ज करें (ASCII कोड 13) और \ n (ASCII कोड 10)। इसलिए, लाइन 2 पर, यह \ n पढ़ेगा और उपयोगकर्ता द्वारा वर्ण दर्ज करने की प्रतीक्षा नहीं करेगा।

लाइन 2 पर आपके द्वारा देखा गया व्यवहार सही है, लेकिन यह सही स्पष्टीकरण नहीं है। टेक्स्ट-मोड स्ट्रीम के साथ, यह कोई फर्क नहीं पड़ता कि आपका प्लेटफ़ॉर्म किस लाइन-एंडिंग का उपयोग करता है (चाहे गाड़ी वापसी (0x0D) + लाइनफीड) (0x0A), एक नंगे CR, या एक नंगे LF)। सी रनटाइम लाइब्रेरी आपके लिए यह ध्यान '\n'रखेगी : आपका कार्यक्रम सिर्फ नई सुर्खियों के लिए देखा जाएगा ।

यदि आपने एक वर्ण टाइप किया है और एंटर दबाया है, तो उस इनपुट चरित्र को लाइन 1 द्वारा पढ़ा जाएगा, और फिर '\n'पंक्ति 2 से पढ़ा जाएगा। देखें मैं scanf %cवाई / एन प्रतिक्रिया पढ़ने के लिए उपयोग कर रहा हूं , लेकिन बाद में इनपुट छोड़ दिया जाता है। comp.lang.c से अक्सर पूछे जाने वाले प्रश्न।

प्रस्तावित समाधानों के लिए, देखें (फिर से comp.lang.c से प्रश्न):

जो मूल रूप से बताता है कि केवल पोर्टेबल दृष्टिकोण है:

int c;
while ((c = getchar()) != '\n' && c != EOF) { }

आपका getchar() != '\n'लूप काम करता है क्योंकि एक बार जब आप कॉल करते हैं getchar(), तो पहले से ही दिया गया वर्ण इनपुट स्ट्रीम से हटा दिया गया है।

इसके अलावा, मैं आपको scanfपूरी तरह से उपयोग करने से हतोत्साहित करने के लिए बाध्य महसूस करता हूं : हर कोई उपयोग करने के लिए क्यों नहीं कहता है scanf? मुझे इसके बजाय क्या उपयोग करना चाहिए?


1
यह एंटर दबाने के लिए उपयोगकर्ता के इंतजार में लटका रहेगा। यदि आप बस स्टड को साफ़ करना चाहते हैं, तो सीधे टर्मिनस का उपयोग करें। stackoverflow.com/a/23885008/544099
इस्माइल

@ishmael आपकी टिप्पणी से कोई मतलब नहीं है क्योंकि स्टड साफ़ करने के लिए Enter दबाने की आवश्यकता नहीं है ; पहले स्थान पर इनपुट प्राप्त करना आवश्यक है। (और यह सी में इनपुट पढ़ने का एकमात्र मानक तरीका है। यदि आप तुरंत कुंजियों को पढ़ने में सक्षम होना चाहते हैं, तो आपको गैर-मानक पुस्तकालयों का उपयोग करना होगा।)
jamesdlin

@jamesdlin लिनक्स पर, getchar () एंटर प्रेस करने के लिए उपयोगकर्ता की प्रतीक्षा करेगा। तभी वे लूप से बाहर निकल जाएंगे। जहाँ तक मेरी जानकारी है, टर्मिनस एक मानक पुस्तकालय है।
इस्माईल

@ishmael नहीं, आप दोनों मामलों में गलत हैं। यह प्रश्न इस बारे में है कि इनपुट पढ़ने के बाद स्टड से शेष इनपुट को कैसे साफ किया जाए , और मानक सी में, उस इनपुट को प्रदान करने के लिए पहले एक लाइन टाइप करने और एंटर दबाने की आवश्यकता होती है। उसके बाद लाइन में प्रवेश किया गया है, getchar()पढ़ेंगे और उन पात्रों को वापस करेंगे; एक उपयोगकर्ता को दूसरी बार Enter दबाने की आवश्यकता नहीं होगी। इसके अलावा, जबकि टर्मिनस लिनक्स पर आम हो सकता है , यह सी मानक पुस्तकालय का हिस्सा नहीं है ।
jamesdlin

scanf(" %c", &char_var)केवल% c स्पेसियर के लिए स्पेस जोड़ने से न्यूलाइन को काम करने और अनदेखा करने का क्या कारण है ?
17-22 में Cătălina Sîrbu

44

आप इसे इस तरह भी कर सकते हैं:

fseek(stdin,0,SEEK_END);

वाह ... btw, मानक कहते हैं के fseekलिए उपलब्ध है stdin?
--ख

3
मुझे नहीं पता, मुझे लगता है कि यह इसका उल्लेख नहीं करता है, लेकिन स्टड FILE * है और fseek एक FILE * पैरामीटर को स्वीकार करता है। मैंने इसका परीक्षण किया और यह मैक ओएस एक्स पर काम करता है लेकिन लिनक्स पर नहीं।
रामी अल ज़ूहरी

कृपया समझाएँ। यदि लेखक इस पद्धति के निहितार्थ लिखेंगे तो यह बहुत अच्छा जवाब होगा। क्या कोई समस्या है?
EvAlex

7
@EvAlex: इसके साथ कई मुद्दे हैं। यदि यह आपके सिस्टम पर काम करता है, महान; यदि नहीं, तो यह आश्चर्य की बात नहीं है क्योंकि कुछ भी गारंटी नहीं देता है कि यह तब काम करेगा जब मानक इनपुट एक इंटरेक्टिव डिवाइस (या पाइप या सॉकेट या फीफो की तरह एक गैर-खोजने योग्य उपकरण है, नाम के लिए लेकिन कुछ अन्य तरीके जिसमें यह कर सकता है असफल)।
जोनाथन लेफ़लर 5

यह SEEK_END क्यों होना चाहिए? क्या हम इसके बजाय SEEK_SET का उपयोग कर सकते हैं? एफपी स्टड कैसे व्यवहार करता है?
राजेश

11

एक पंक्ति के अंत तक साफ़ करने का एक पोर्टेबल तरीका जिसे आपने पहले ही आंशिक रूप से पढ़ने की कोशिश की है:

int c;

while ( (c = getchar()) != '\n' && c != EOF ) { }

यह वर्णों को तब तक पढ़ता और डिसॉर्ड करता है जब तक कि यह \nफ़ाइल के अंत का संकेत नहीं देता । यह EOFइनपुट लाइन के समाप्त होने से पहले बंद होने की स्थिति में भी जांच करता है । मूल्य धारण करने में सक्षम होने के लिए प्रकार (या बड़ा) cहोना चाहिए ।intEOF

यह पता लगाने का कोई पोर्टेबल तरीका नहीं है कि क्या वर्तमान लाइन के बाद कोई और लाइनें हैं (यदि नहीं हैं, तो getcharइनपुट के लिए ब्लॉक हो जाएगी)।


क्यों जबकि (सी (get = getchar) (!) = EOF); काम नहीं करता? यह अंतहीन लूप है। स्टड में ईओएफ के स्थान को समझने में सक्षम नहीं है।
राजेश

@ राजेश कि इनपुट स्ट्रीम बंद होने तक यह स्पष्ट होगा, जो बाद में आने के लिए अधिक इनपुट होने पर ऐसा नहीं होगा
MM

@ राजेश जी, आप सही हैं। अगर यह कहा जाता है, तो यह फँसाने के लिए स्टड पर कुछ भी नहीं है, यह अनंत लूप में पकड़े जाने के कारण ब्लॉक (लटका) होगा।
जेसन हनोकस

11

रेखाएं:

int ch;
while ((ch = getchar()) != '\n' && ch != EOF)
    ;

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

क्योंकि यह एक गाड़ी वापसी के बजाय एक लाइनफीड पढ़ता है, ऐसा इसलिए है क्योंकि सिस्टम ने लाइनफीड को रिटर्न का अनुवाद किया है। जब एंटर दबाया जाता है, तो वह लाइन के अंत का संकेत देता है ... लेकिन स्ट्रीम में लाइन फीड होती है बजाय इसके कि सिस्टम के लिए सामान्य एंड-ऑफ लाइन मार्कर होता है। यह प्लेटफॉर्म पर निर्भर हो सकता है।

इसके अलावा, fflush()इनपुट स्ट्रीम का उपयोग करना सभी प्लेटफार्मों पर काम नहीं करता है; उदाहरण के लिए यह आमतौर पर लिनक्स पर काम नहीं करता है।


नोट: while ( getchar() != '\n' );एक अनंत लूप है जो फ़ाइल के अंत के कारण getchar()वापस आ जाना चाहिए EOF
chux -

EOF के लिए भी जाँच की int ch; while ((ch = getchar()) != '\n' && ch != EOF);जा सकती है,
दिमित्री

8

लेकिन मैं खुद को नहीं समझा सकता कि यह कैसे काम करता है? क्योंकि जिस वक्त स्टेटमेंट में हम यूज करते हैं getchar() != '\n', मतलब किसी एक कैरेक्टर को छोड़कर पढ़ते हैं '\n'?? यदि हां, तो इनपुट बफर में अभी भी '\n'चरित्र बना हुआ है ??? क्या मैं कुछ गलत समझ रहा हूँ ??

हो सकता है कि आपको एहसास न हो कि तुलना इनपुट बफर से वर्ण को हटाने के बाद होती है getchar()। इसलिए जब आप पहुंचते हैं '\n', तो इसका सेवन किया जाता है और फिर आप लूप से बाहर निकल जाते हैं।


6

तुम कोशिश कर सकते हो

scanf("%c%*c", &ch1);

जहाँ% * c स्वीकार करता है और न्यूलाइन को अनदेखा करता है

Fflush (स्टडिन) के बजाय एक और तरीका जो अपरिभाषित व्यवहार को आमंत्रित करता है

while((getchar())!='\n');

लूप के बाद अर्धविराम को न भूलें


2
1) "%*c"किसी भी चरित्र को स्कैन करता है (और इसे नहीं बचाता है), यह एक नई रेखा या कुछ और हो। कोड इस बात पर भरोसा कर रहा है कि दूसरा वर्ण एक नई पंक्ति है। 2) while((getchar())!='\n');एक अनंत लूप है जो फ़ाइल के अंत के कारण getchar()वापस आ जाना चाहिए EOF
chux -

1
दूसरी विधि न्यूलाइन, अशक्त चरित्र, ईओएफ आदि जैसी स्थिति पर निर्भर करती है (ऊपर यह न्यूलाइन थी)
कपिल

1

मैं समस्या को हल करने की कोशिश कर रहा हूं

while ((c = getchar()) != '\n' && c != EOF) { }

मैं किसी के लिए थोड़ा समायोजन 'कोड बी' पोस्ट करता हूं, जो शायद एक ही समस्या है।

समस्या यह थी कि कार्यक्रम ने मुझे '\ n' चरित्र को पकड़ने के लिए रखा, स्वतंत्र रूप से दर्ज चरित्र से, यहाँ कोड है जिसने मुझे समस्या दी है।

कोड ए

int y;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   continue;
}
printf("\n%c\n", toupper(y));

और समायोजन को (n-1) वर्ण को 'लूप' में सशर्त से ठीक पहले दिया गया था जबकि लूप का मूल्यांकन किया गया था, यहाँ कोड है:

कोड बी

int y, x;

printf("\nGive any alphabetic character in lowercase: ");
while( (y = getchar()) != '\n' && y != EOF){
   x = y;
}
printf("\n%c\n", toupper(x));

संभावित व्याख्या यह है कि लूप को तोड़ने के लिए, इसे वेरिएबल y को '\ n' मान देना होगा, इसलिए यह अंतिम असाइन किया गया मान होगा।

अगर मुझे स्पष्टीकरण के साथ कुछ याद आया, तो कोड ए या कोड बी कृपया मुझे बताएं, मैं मुश्किल से सी में नया हूं।

आशा है कि यह किसी की मदद करता है


आपको लूप के अंदर अपने " अपेक्षित " चरित्र के साथ व्यवहार करना चाहिए while। लूप के बाद आप साफ / स्पष्टstdin हो सकते हैं और या तो ' ' या पकड़ लेंगे । जब कोई नई रेखा मौजूद नहीं होती है और बफर समाप्त हो जाता है (यदि इनपुट को दबाया गया था तो बफर ओवरफ्लो हो जाएगा )। - आप प्रभावी रूप से इनपुट बफर में प्रत्येक वर्ण को चबाने के लिए उपयोग करते हैं y\nEOFEOF[ENTER]while((ch=getchar())!='\n'&&ch!=EOF);stdin
वेजाइनाज़े

0
unsigned char a=0;
if(kbhit()){
    a=getch();
    while(kbhit())
        getch();
}
cout<<hex<<(static_cast<unsigned int:->(a) & 0xFF)<<endl;

-या-

शायद उपयोग करें _getch_nolock().. ???


प्रश्न C के बारे में है, C ++ के बारे में नहीं।
स्पिकैट्रिक्स

1
ध्यान दें कि kbhit()और केवल विंडोज पर मानक के रूप में उपलब्ध getch()कार्यों में घोषित किए गए हैं <conio.h>। उन्हें यूनिक्स जैसी मशीनों पर अनुकरण किया जा सकता है, लेकिन ऐसा करने के लिए कुछ देखभाल की आवश्यकता होती है।
जोनाथन लेफ्लर

0

एक अन्य समाधान जिसका उल्लेख अभी तक नहीं किया गया है, वह है: रिवाइंड (स्टडिन);


2
अगर पूरी तरह से फ़ाइल में रीडायरेक्ट हो जाता है तो यह प्रोग्राम को पूरी तरह से तोड़ देगा। और इंटरैक्टिव इनपुट के लिए यह कुछ भी करने की गारंटी नहीं है।
melpomene

0

मुझे आश्चर्य है कि किसी ने भी इसका उल्लेख नहीं किया है:

scanf("%*[^\n]");

-1

लघु, पोर्टेबल और stdio.h में घोषित

stdin = freopen(NULL,"r",stdin);

एक अनंत लूप में लटका नहीं है, जब निम्न अच्छी तरह से पता लाइन की तरह फ्लश करने के लिए कुछ भी नहीं है:

while ((c = getchar()) != '\n' && c != EOF) { }

थोड़ा महंगा तो इसे एक प्रोग्राम में उपयोग न करें जो बार-बार बफर को साफ करने की आवश्यकता है।

एक सहकर्मी से चोरी :)


लिनक्स पर काम नहीं करता है। इसके बजाय सीधे शब्दावली का उपयोग करें। stackoverflow.com/a/23885008/544099
इस्माइल

2
क्या आप इस बात का विस्तार कर सकते हैं कि प्रसिद्ध लाइन एक संभावित अनंत लूप क्यों है?
काकाहुइट फ्रिटो

पूरा कारण freopenमौजूद है कि आप आंशिक रूप से असाइन नहीं कर सकते हैं stdin। यह स्थूल है।
melpomene

1
ishmel: साइबर कमांड में हमारे सभी कंप्यूटर यहां लिनक्स हैं और यह उन पर ठीक काम करता है। मैंने इसे डेबियन और फेडोरा दोनों पर परीक्षण किया।
जेसन हनोकस

जिसे आप "अनंत लूप" कहते हैं, वह प्रोग्राम है जो इनपुट की प्रतीक्षा कर रहा है। यह वही बात नहीं है।
जेम्सडलिन

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