সি-তে ইনপুট বাফার কীভাবে সাফ করবেন?


87

আমি নিম্নলিখিত প্রোগ্রাম আছে:

উপরের কোডটির লেখক যেমন ব্যাখ্যা করেছেন: প্রোগ্রামটি সঠিকভাবে কাজ করবে না কারণ লাইন 1 এ, যখন ব্যবহারকারী এন্টার টিপায়, এটি ইনপুট বাফার 2 অক্ষরে ছেড়ে যাবে: Enter key (ASCII code 13)এবং \n (ASCII code 10)। অতএব, লাইন 2 এ এটি পড়বে \nএবং ব্যবহারকারীর কোনও চরিত্র প্রবেশের অপেক্ষায় থাকবে না।

ঠিক আছে, আমি এটি পেয়েছি তবে আমার প্রথম প্রশ্নটি হল: দ্বিতীয় getchar()( ch2 = getchar();)টি চরিত্রের Enter key (13)পরিবর্তে কেন পড়ছে না \n?

এর পরে, লেখক এই জাতীয় প্রব্রিমগুলি সমাধান করার জন্য 2 টি উপায় প্রস্তাব করেছিলেন:

  1. ব্যবহার fflush()

  2. এই মত একটি ফাংশন লিখুন:

এই কোডটি আসলে কাজ করেছিল। তবে আমি কীভাবে এটি কাজ করে তা নিজেকে ব্যাখ্যা করতে পারি না? কারণ বিবৃতিতে, আমরা ব্যবহার করি getchar() != '\n', তার মানে কি কোনও একক চরিত্র বাদে পড়া '\n'? যদি তাই হয় তবে ইনপুট বাফারে এখনও '\n'চরিত্রটি রয়ে গেছে ?

উত্তর:


92

প্রোগ্রামটি সঠিকভাবে কাজ করবে না কারণ লাইন 1 এ, ব্যবহারকারী যখন এন্টার টিপবে তখন এটি ইনপুট বাফার 2 অক্ষরে ছেড়ে যাবে: কী (ASCII কোড 13) এবং \ n (ASCII কোড 10) প্রবেশ করান। অতএব, লাইন 2 এ এটি read n পড়বে এবং ব্যবহারকারীর কোনও চরিত্র প্রবেশের অপেক্ষা করবে না।

২ য় লাইনে আপনি যে আচরণটি দেখছেন তা সঠিক, তবে এটি বেশ সঠিক ব্যাখ্যা নয়। পাঠ্য-মোড স্ট্রিমগুলির সাথে, আপনার প্ল্যাটফর্মটি কী লাইন-এন্ডেজেড ব্যবহার করে তা বিবেচ্য নয় (ক্যারেজ রিটার্ন (0x0D) + লাইনফিড (0x0A), একটি বেয়ার সিআর, বা একটি বেয়ার এলএফ)। সি রানটাইম লাইব্রেরি আপনার জন্য এটি যত্ন নেবে: আপনার প্রোগ্রামটি কেবল '\n'নতুন লাইনের জন্য দেখতে পাবে ।

আপনি যদি কোনও অক্ষর টাইপ করেন এবং এন্টার টিপেন, তবে সেই ইনপুট অক্ষরটি 1 লাইন দিয়ে '\n'পড়তে হবে এবং তারপরে লাইন 2 দ্বারা পড়তে হবে দেখুন আমি scanf %cকোনও Y / N প্রতিক্রিয়া পড়তে ব্যবহার করছি , তবে পরে ইনপুটটি এড়ানো যায় না। comp.lang.c এফএকিউ থেকে।

প্রস্তাবিত সমাধানগুলির জন্য, দেখুন (comp.lang.c এফএকিউ থেকে আবার):

যা মূলত বলে যে একমাত্র বহনযোগ্য পন্থাটি করণীয়:

আপনার getchar() != '\n'লুপটি কাজ করে কারণ একবার আপনি কল করার পরে getchar(), ফিরে আসা অক্ষরটি ইতিমধ্যে ইনপুট স্ট্রিম থেকে সরানো হয়েছে।

এছাড়াও, আমি আপনাকে scanfসম্পূর্ণরূপে ব্যবহার থেকে নিরুৎসাহিত করতে বাধ্য বলে মনে করি : সবাই কেন ব্যবহার না করতে বলে scanf? পরিবর্তে আমার কী ব্যবহার করা উচিত?


4
এটি ব্যবহারকারীর এন্টার টিপে অপেক্ষা করতে থাকবে। আপনি যদি কেবল স্টিডিন সাফ করতে চান তবে সরাসরি টের্মিওগুলি ব্যবহার করুন। stackoverflow.com/a/23885008/544099
ইসমাইল

@ ইশমেল আপনার মন্তব্যটির কোনও অর্থ নেই কারণ এন্টার টিপলে স্টিডিন সাফ করার প্রয়োজন হয় না ; এটি প্রথম স্থানে ইনপুট পেতে প্রয়োজন। (এবং এটি সি এর ইনপুট পড়ার একমাত্র স্ট্যান্ডার্ড উপায় আপনি যদি অবিলম্বে কীগুলি পড়তে সক্ষম হতে চান তবে আপনাকে অ-মানক গ্রন্থাগার ব্যবহার করতে হবে
j

@ জেমসডলিন লিনাক্সে, গেটচার () ব্যবহারকারী এন্টার টিপে অপেক্ষা করবে। তবেই তারা লুপটি ভেঙে ফেলবে। আমি যতদূর সচেতন, টেরিমিয়াস একটি স্ট্যান্ডার্ড লাইব্রেরি।
ishmael

@ ইশমেল না, আপনি উভয়ই বিবেচনায় ভুল। ইনপুট পড়ার পরে স্টিডিন থেকে অবশিষ্ট ইনপুট সাফ করার বিষয়ে এবং স্ট্যান্ডার্ড সি-তে, এই ইনপুটটি সরবরাহ করার জন্য প্রথমে একটি লাইন টাইপ করা এবং এন্টার টিপতে হবে This সেই লাইনটি প্রবেশ করার পরে , getchar()সেই অক্ষরগুলি পড়বে এবং ফিরে আসবে; ব্যবহারকারীর আর একবার এন্টার টিপতে হবে না। তদ্ব্যতীত, যদিও টার্মিয়ামগুলি লিনাক্সে সাধারণ হতে পারে তবে এটি সি স্ট্যান্ডার্ড লাইব্রেরির অংশ নয় ।
জেমসডলিন 21

scanf(" %c", &char_var)% গ স্পেসিফায়ার মাত্র একটি স্পেস যোগ করে নতুন লাইনে কাজ করা এবং উপেক্ষা করার কারণ কী ?
ক্যাটালিনা সরবু

44

আপনি এটিও (এটি) এভাবে করতে পারেন:


বাহ ... বিটিডব্লিউ, স্ট্যান্ডার্ড বলে fseekকি পাওয়া যায় stdin?
ikh

4
আমি জানি না, আমি মনে করি এটির উল্লেখ নেই, তবে স্টিডিন হ'ল ফাইল * এবং fseek একটি ফাইল * পরামিতি গ্রহণ করে। আমি এটি পরীক্ষা করেছি এবং এটি ম্যাক ওএস এক্সে কাজ করে তবে লিনাক্সে নয়।
রামি আল জুহুরী

দয়া করে ব্যাখ্যা করুন. লেখক যদি এই পদ্ধতির অন্তর্নিহিত লেখেন তবে এটি একটি দুর্দান্ত উত্তর হবে। কোন সমস্যা আছে?
ইভ্যালাক্স

7
@ এভ্যালেক্স: এটি নিয়ে অনেকগুলি সমস্যা রয়েছে। এটি যদি আপনার সিস্টেমে কাজ করে তবে দুর্দান্ত; যদি তা না হয় তবে অবাক হওয়ার মতো কিছু নেই যে কোনও কিছুতেই গ্যারান্টি নেই যে এটি কার্যকর হবে যখন স্ট্যান্ডার্ড ইনপুটটি ইন্টারেক্টিভ ডিভাইস (বা পাইপ বা সকেট বা একটি ফিফোর মতো অ-সন্ধানযোগ্য ডিভাইস, নামকরণ করা তবে কয়েকটি অন্যান্য উপায় যা এটি করতে পারে ব্যর্থ)।
জোনাথন লেফলার

এটি SEEK_END হওয়া উচিত কেন? পরিবর্তে আমরা SEEK_SET ব্যবহার করতে পারি? এফপি স্টিডিন কীভাবে আচরণ করে?
রাজেশ

11

আপনি ইতিমধ্যে আংশিকভাবে পড়ার চেষ্টা করেছেন এমন একটি লাইনের শেষে পরিষ্কার করার একটি পোর্টেবল উপায় হ'ল:

এটি অক্ষরগুলি পড় এবং ত্যাগ করে যতক্ষণ না এটি পায় \nযা ফাইলটির শেষের সংকেত দেয়। EOFলাইন শেষ হওয়ার আগে ইনপুট স্ট্রিম বন্ধ হয়ে যাওয়ার ক্ষেত্রে এটি পরীক্ষা করে । ধরণ cহবে int(বা বড়) অর্ডার মূল্য রাখা পাবে মধ্যে EOF

বর্তমান লাইনের পরে আর কোনও লাইন রয়েছে কিনা তা খুঁজে পাওয়ার কোনও পোর্টেবল উপায় নেই (যদি না থাকে তবে getcharইনপুটটির জন্য ব্লক হয়ে যাবে)।


কেন যখন ((সি = গেটচার ())! = ইওএফ); কাজ করে না? এটি অন্তহীন লুপ। স্টিডিনে ইওএফের অবস্থান বুঝতে সক্ষম নয়।
রাজেশ

@ রাজেশ এটি ইনপুট স্ট্রিম বন্ধ না হওয়া অবধি পরিষ্কার করবে, পরে আরও ইনপুট আসার পরে তা হবে না
এমএম

@ রাজেশ হ্যাঁ, আপনি ঠিক বলেছেন। এটি ডেকে এলে স্টিনে ফ্লাশ করার মতো কিছু না থাকলে এটি অসীম লুপে ধরা পড়ার কারণে এটি ব্লক (হ্যাং) হয়ে যাবে।
জেসন এনোকস 21

11

রেখাগুলি:

লাইনফিড ( '\n') এর আগে কেবল অক্ষরগুলি পড়ে না । এটি স্ট্রিমের সমস্ত অক্ষর পড়বে (এবং এগুলি বাতিল করে) পরবর্তী লাইনফিড (বা ইওএফ-এর মুখোমুখি হয়েছে) সহ including পরীক্ষাটি সত্য হওয়ার জন্য, প্রথমে লাইনফিডটি পড়তে হবে; সুতরাং যখন লুপটি থামবে, লাইনফিডটি ছিল সর্বশেষ চরিত্রের পড়া, তবে এটি পড়েছে।

কেন এটি ক্যারেজ রিটার্নের পরিবর্তে একটি লাইনফিড পড়ে, কারণ সিস্টেমটি একটি লাইনফিডে রিটার্নটি অনুবাদ করেছে। এন্টার টিপলে, এটি লাইনের শেষের ইঙ্গিত দেয় ... তবে স্ট্রিমের পরিবর্তে একটি লাইন ফিড থাকে কারণ এটি সিস্টেমের জন্য স্বাভাবিক প্রান্তের-লাইন চিহ্নিতকারী। এটি প্ল্যাটফর্ম নির্ভর হতে পারে।

এছাড়াও, fflush()ইনপুট স্ট্রিম ব্যবহার করা সমস্ত প্ল্যাটফর্মগুলিতে কাজ করে না; উদাহরণস্বরূপ এটি লিনাক্সে সাধারণত কাজ করে না।


দ্রষ্টব্য: ফাইলের শেষের কারণে while ( getchar() != '\n' );একটি অসীম লুপটি getchar()ফিরে আসা উচিত EOF
chux - মনিকা

পাশাপাশি ইওএফ পরীক্ষা int ch; while ((ch = getchar()) != '\n' && ch != EOF);করতে , ব্যবহার করা যেতে পারে
দিমিত্রি

8

তবে আমি কীভাবে এটি কাজ করে তা নিজেকে ব্যাখ্যা করতে পারি না? কারণ যখন বিবৃতিতে, আমরা ব্যবহার করি getchar() != '\n', এর অর্থ হল কোনও একক অক্ষর ছাড়া '\n'?? যদি তাই হয় তবে ইনপুট বাফারে এখনও '\n'অক্ষরটি রয়ে গেছে ??? আমি কি কিছু ভুল বুঝছি ??

আপনি যে জিনিসটি বুঝতে পারবেন না তা হ'ল তুলনাটি ইনপুট বাফার থেকে চরিত্রটিকে সরিয়ে দেওয়ার পরে ঘটে getchar()। সুতরাং আপনি যখন পৌঁছেছেন '\n', এটি গ্রাস করা হয় এবং তারপরে আপনি লুপটি ভেঙে ফেলেন।


6

আপনি চেষ্টা করতে পারেন

যেখানে% * c নিউলাইনটি গ্রহণ করে এবং উপেক্ষা করে

fflush (stdin) এর পরিবর্তে আরও একটি পদ্ধতি যা আপনাকে লিখতে পারে এমন অপরিজ্ঞাত আচরণের জন্য আবেদন করে

লুপ করার পরে সেমিকোলনটি ভুলে যাবেন না


4
1) "%*c"কোনও অক্ষর স্ক্যান করে (এবং এটি সংরক্ষণ করে না), এটি একটি নতুন লাইন বা অন্য কিছু হোক। কোড নির্ভর করে যে ২ য় অক্ষরটি একটি নতুন লাইন। 2) ফাইলের শেষের কারণে while((getchar())!='\n');একটি অসীম লুপ getchar()ফিরে আসা উচিত EOF
chux - মনিকা

4
দ্বিতীয় পদ্ধতিটি শর্তের উপর নির্ভর করে যেমন নিউলাইন, নাল অক্ষর, ইওএফ ইত্যাদি (উপরে এটি নিউলাইন ছিল)
ক্যাপিল

1

সমাধানটি বাস্তবায়নের চেষ্টা করার সময় আমি একটি সমস্যার মুখোমুখি হয়েছি

যাদের সমস্যা হতে পারে তাদের জন্য আমি সামান্য সমন্বয় 'কোড বি' পোস্ট করি।

সমস্যাটি হ'ল প্রোগ্রামটি আমাকে প্রবেশের চরিত্র থেকে স্বতন্ত্রভাবে '\ n' চরিত্রটি ধরেছিল, এখানে কোডটি আমাকে সমস্যা দিয়েছে।

কোড এ

এবং অ্যাডজাস্টমেন্টটি ছিল (এন -1) অক্ষরটি 'ধরা' ঠিক এর আগে লুপটির মূল্যায়ন করার সময় শর্তযুক্ত হওয়ার আগে, কোডটি এখানে:

কোড বি

সম্ভাব্য ব্যাখ্যাটি হ'ল লুপটি ভেঙে যাওয়ার জন্য, এটি পরিবর্তনশীল y এর জন্য '\ n' নির্ধারণ করতে হবে, সুতরাং এটিই শেষ নির্ধারিত মান হবে be

যদি আমি ব্যাখ্যাটি দিয়ে কিছু মিস করি তবে কোড এ বা কোড বি দয়া করে আমাকে বলুন, আমি সি তে সবে নতুন।

আশা করি এটি কাউকে সাহায্য করবে


লুপের অভ্যন্তরে আপনার " প্রত্যাশিত " চরিত্রটি ব্যবহার করা উচিত while। লুপের পরে আপনি পরিষ্কার / সাফstdin বলে বিবেচনা করতে পারেন এবং এটি ' ' বা ধরে রাখবেন । কোনও নিউলাইন উপস্থিত না থাকলে এবং বাফারটি শেষ হয়ে গেলে ফিরে আসে (যদি ইনপুটটি চাপ দেওয়ার আগে বাফারটি উপচে পড়ত )। - আপনি ইনপুট বাফারের প্রতিটি অক্ষরকে চিবিয়ে কার্যকরভাবে ব্যবহার করুন। y\nEOFEOF[ENTER]while((ch=getchar())!='\n'&&ch!=EOF);stdin
ভেগানাইজে

0

-অর-

ব্যবহার সম্ভবত ব্যবহার _getch_nolock().. ???


প্রশ্নটি সি ++ নয়, সি সম্পর্কে about
স্পিক্যাট্রেক্স

4
নোট করুন kbhit()এবং এতে উইন্ডোজ হিসাবে getch()ঘোষণা করা হয় <conio.h>এবং এটি কেবলমাত্র স্ট্যান্ডার্ড হিসাবে উপলব্ধ। এগুলি ইউনিক্সের মতো মেশিনগুলিতে অনুকরণ করা যায় তবে এটি করার জন্য কিছু যত্ন নেওয়া দরকার।
জোনাথন লেফলার

0

এখনও উল্লিখিত না হওয়া অন্য সমাধানটি হ'ল: রিওয়াইন্ড (স্টিডিন);


4
স্টিডিন যদি কোনও ফাইলে পুনঃনির্দেশিত হয় তবে এটি প্রোগ্রামটি পুরোপুরি ভেঙে দেবে। এবং ইন্টারেক্টিভ ইনপুট জন্য এটি কিছু করার গ্যারান্টিযুক্ত না।
melpomene

0

আমি অবাক হয়েছি কেউ এর উল্লেখ করেনি:


-1

সংক্ষিপ্ত, বহনযোগ্য এবং stdio.h এ ঘোষণা করা

নিম্নলিখিত ভালভাবে জানা লাইনের মতো ফ্ল্যাশ করার জন্য স্টিডিনে কিছুই নেই তখন অসীম লুপে ঝুলবেন না:

কিছুটা ব্যয়বহুল তাই কোনও প্রোগ্রামে এটি ব্যবহার করবেন না যাতে বার বার বাফার সাফ করা দরকার।

সহকর্মীর কাছ থেকে চুরি হয়েছে :)


লিনাক্সে কাজ করে না। পরিবর্তে সরাসরি Termios ব্যবহার করুন। stackoverflow.com/a/23885008/544099
ishmael

4
আপনি কেন বিশদ রেখাগুলি একটি অসীম লুপ হিসাবে বিশদটি জানাতে পারেন?
alx

পুরো কারণ freopenবিদ্যমান আপনি পোর্টেবলভাবে বরাদ্দ করতে পারবেন না stdin। এটি একটি ম্যাক্রো।
মেল্পোমেন

4
ইসমাইল: সাইবার কমান্ডে আমাদের এখানে থাকা সমস্ত কম্পিউটার লিনাক্স এবং এটি তাদের জন্য দুর্দান্ত কাজ করে। আমি এটি ডেবিয়ান এবং ফেডোরা উভয়তেই পরীক্ষা করেছিলাম।
জেসন এনোকস

আপনি যাকে "অসীম লুপ" বলছেন তা হ'ল প্রোগ্রামটি ইনপুটটির জন্য অপেক্ষা করছে। এটি একই জিনিস নয়।
জেমসডলিন

-1

এটা চেষ্টা কর:

stdin->_IO_read_ptr = stdin->_IO_read_end;


4
কিভাবে এই সমাধান কাজ করে সে সম্পর্কে একটি বিট আরো বিবরণ যোগ এবং এটি কিভাবে সমস্যা সমাধানের জন্য একটি দরকারী উপায় দয়া করে stackoverflow.com/help/how-to-answer
মামলা বয় অ্যাপস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.