আইওস্ট্রিম :: লুপের ভিতরে ইওফকে (যেমন `যখন (! স্ট্রিম.ওফ ())`) ভুল হিসাবে বিবেচিত হয়?


595

আমি এই উত্তরে কেবল একটি মন্তব্য পেয়েছি যা বলেছে যে iostream::eofএকটি লুপ অবস্থায় ব্যবহার করা "প্রায় অবশ্যই ভুল"। আমি সাধারণত এমন কিছু ব্যবহার while(cin>>n)করি - যা আমি অনুমান করি যে ইওএফের জন্য স্পষ্টতই পরীক্ষা করা হয়।

কেন ইওফের জন্য স্পষ্টভাবে while (!cin.eof())ভুল ব্যবহার করা হচ্ছে তা পরীক্ষা করা হচ্ছে ?

scanf("...",...)!=EOFসিতে ব্যবহার করা থেকে এটি কীভাবে আলাদা (যা আমি প্রায়শই কোনও সমস্যা ছাড়াই ব্যবহার করি)?


21
scanf(...) != EOFসি তেও কাজ করবে না, কারণ scanfসফলভাবে পার্স এবং নির্ধারিত ক্ষেত্রের সংখ্যা প্রদান করে। ফর্ম্যাট স্ট্রিংয়ের ক্ষেত্র সংখ্যা scanf(...) < nযেখানে সঠিক শর্ত n
বেন ভয়েগট

5
@ বেন ভয়েগ্ট, ইওএফ পৌঁছানোর ক্ষেত্রে এটি একটি নেতিবাচক সংখ্যা (যা সাধারণত ইওএফকে সাধারণত হিসাবে সংজ্ঞায়িত করা হয়) ফিরিয়ে দেবে
সেবাস্তিয়ান

19
@ সেবাস্তিয়ানগোডলেট: প্রকৃতপক্ষে, EOFপ্রথম ক্ষেত্র রূপান্তরকরণের আগে ফাইলটির শেষের মুখোমুখি হলে (সফল বা না) এটি ফিরে আসবে । যদি ফাইলের সমাপ্তি ক্ষেত্রগুলির মধ্যে পৌঁছে যায় তবে এটি সাফল্যের সাথে রূপান্তরিত এবং সঞ্চিত ক্ষেত্রের সংখ্যা প্রদান করবে। যা EOFভুলের সাথে তুলনা করে ।
বেন ভয়েগট

1
@ সেবাস্তিয়ানগোডলেট: না, সত্যই নয়। যখন তিনি বলেন যে "লুপটির অতীতে কোনও অনুচিতের থেকে উপযুক্ত ইনপুট আলাদা করার কোনও সহজ (সহজ) উপায় নেই" তখন তিনি ভুল করেন। .eof()লুপটি প্রস্থান করার পরে এটি চেক করা ঠিক তত সহজ ।
বেন ভয়েগট

2
@ বেন হ্যাঁ, এই মামলার জন্য (একটি সাধারণ ইনট পড়ুন)। তবে একটি সহজেই এমন দৃশ্যের সাথে আসতে পারে যেখানে while(fail)লুপটি আসল ব্যর্থতা এবং ইওফ উভয় দিয়েই শেষ হয়। আপনার পুনরাবৃত্তির জন্য 3 টি ইনট প্রয়োজন কিনা তা ভেবে দেখুন (বলুন যে আপনি একটি জাইজ পয়েন্ট বা কিছু পড়ছেন), তবে স্রোতে ভ্রান্তভাবে কেবল দুটি ইনট রয়েছে।
সেয়ানা

উত্তর:


544

কারণ iostream::eofকেবলমাত্র স্রোতের সমাপ্তি পড়ার true পরে ফিরে আসবে । এটি নির্দেশ করে না যে, পরবর্তী পঠনটি স্ট্রিমের সমাপ্তি হবে।

এটি বিবেচনা করুন (এবং ধরে নিন যে পরবর্তী পড়াটি স্ট্রিমের শেষে হবে):

while(!inStream.eof()){
  int data;
  // yay, not end of stream yet, now read ...
  inStream >> data;
  // oh crap, now we read the end and *only* now the eof bit will be set (as well as the fail bit)
  // do stuff with (now uninitialized) data
}

এর বিপরীতে:

int data;
while(inStream >> data){
  // when we land here, we can be sure that the read was successful.
  // if it wasn't, the returned stream from operator>> would be converted to false
  // and the loop wouldn't even be entered
  // do stuff with correctly initialized data (hopefully)
}

এবং আপনার দ্বিতীয় প্রশ্ন: কারণ

if(scanf("...",...)!=EOF)

হিসাবে একই

if(!(inStream >> data).eof())

এবং না হিসাবে একই

if(!inStream.eof())
    inFile >> data

12
উল্লেখযোগ্য হ'ল যদি (! (ইনস্ট্রিম >> ডেটা) .ওফ ()) কার্যকর কিছু না করে। মিথ্যাচার 1: ডেটা শেষ টুকরা (শেষ ডাটাম প্রক্রিয়া করা হবে না) পরে কোন শ্বেত স্পেস না থাকলে এটি শর্তে প্রবেশ করবে না। মিথ্যাচার 2: ডেটা পড়তে ব্যর্থ হওয়া সত্ত্বেও এটি শর্তে প্রবেশ করবে, যতক্ষণ না ইওএফ পৌঁছায় না (অসীম লুপ, একই পুরানো ডেটা বারবার প্রক্রিয়াকরণ)।
ট্রিক

4
আমি মনে করি এটি উল্লেখ করা উপযুক্ত যে এই উত্তরটি কিছুটা বিভ্রান্তিকর। যখন আহরণের ints অথবা std::strings অথবা অনুরূপ, ফাইলের শেষে বিট হয় সেট যখন আপনি শেষ হওয়ার আগে এক অধিকার নিষ্কর্ষ এবং নিষ্কাশন শেষ হিট। আপনার আর পড়ার দরকার নেই। ফাইলগুলি থেকে পড়ার সময় এটি সেট না হওয়ার কারণ হ'ল \nশেষে আরও একটি অতিরিক্ত । আমি এটি অন্য উত্তরে coveredেকে রেখেছি । charগুলি পড়া আলাদা বিষয় কারণ এটি একবারে কেবল একটি করে বের করে এবং শেষ পর্যন্ত আঘাত করা অবিরত করে না।
জোসেফ ম্যানসফিল্ড

79
মূল সমস্যাটি হ'ল কেবল কারণ আমরা ইওএফ পৌঁছেছি না, এর অর্থ এই নয় যে পরবর্তী পড়াটি সফল হবে
জোসেফ ম্যানসফিল্ড

1
@ স্প্রেটববিট: সমস্ত সত্য তবে খুব কার্যকর নয় ... এমনকি '\ n' এর পিছনে কোনও পেজ নেই এমন হওয়াও যুক্তিযুক্ত যুক্তিসঙ্গতভাবে অন্যান্য পেছনের শ্বেত স্পেসটি ফাইলের পুরো অংশে (যেমন বাদ দেওয়া হয়) অন্য সাদা জায়গার সাথে নিয়মিতভাবে পরিচালনা করা উচিত। তদ্ব্যতীত, "যখন আপনি আগে ডানটি বের করেন" এর একটি সূক্ষ্ম পরিণতি হ'ল ইনপুট সম্পূর্ণ ফাঁকা থাকলে এস বা এসগুলিতে while (!eof())"কাজ" করে না , সুতরাং এমনকি কোনও পিছনে যত্নের প্রয়োজন নেই তা জেনেও । intstd::string\n
টনি ডেলরয়

2
@ টনিডি পুরোপুরি একমত আমি এর কারণ বলছি কারণ আমি মনে করি বেশিরভাগ লোকেরা যখন এটি পড়বে এবং অনুরূপ উত্তরগুলি পড়বে তখন তারা মনে করবে যে যদি এই স্ট্রিমটিতে "Hello"(কোনও পেছনের শ্বেত স্থান বা থাকে না \n) থাকে এবং std::stringএটি নিষ্কাশিত হয় তবে এটি থেকে চিঠিগুলি বের Hকরা o, নিষ্কাশন বন্ধ করবে এবং তারপরে EOF বিট সেট করবেন না । আসলে, এটি ইওএফ বিট সেট করবে কারণ এটি ইওএফই নিষ্কাশন বন্ধ করেছিল stopped মানুষের কাছে এটি পরিষ্কার করার আশা করছি।
জোসেফ ম্যানসফিল্ড

103

নীচে লাইন শীর্ষ: সাদা স্থান যথাযথভাবে পরিচালনার সাথে, নিম্নলিখিতটি কীভাবে eofব্যবহার করা যায় তা (এবং এমনকি fail()ত্রুটি পরীক্ষার চেয়ে আরও নির্ভরযোগ্য হতে হবে ):

while( !(in>>std::ws).eof() ) {  
   int data;
   in >> data;
   if ( in.fail() ) /* handle with break or throw */; 
   // now use data
}    

( ধন্যবাদ টনি ডি পরামর্শ উত্তর হাইলাইট করার জন্য। নিচে তার মন্তব্য দেখুন কেন এই আরো জোরালো হয় উদাহরণের জন্য। )


ব্যবহারের বিরুদ্ধে প্রধান যুক্তি eof()মনে হচ্ছে সাদা স্থানের ভূমিকা সম্পর্কে একটি গুরুত্বপূর্ণ সূক্ষ্মতা অনুপস্থিত। আমার প্রস্তাবটি হ'ল, eof()সুস্পষ্টভাবে চেক করা কেবল " সর্বদা ভুল " নয় - যা এই এবং অনুরূপ এসও থ্রেডগুলিতে একটি ওভাররাইডিং মতামত বলে মনে হয় - তবে সাদা স্থান সঠিকভাবে পরিচালনার সাথে সাথে এটি একটি ক্লিনার এবং আরও নির্ভরযোগ্য সরবরাহ করে ত্রুটি পরিচালনায়, এবং সর্বদা সঠিক সমাধান (যদিও এটি অদ্যাবধি প্রয়োজন হয় না)।

"যথাযথ" সমাপ্তি এবং পঠনের আদেশ হিসাবে কী পরামর্শ দেওয়া হচ্ছে তা সংক্ষেপে নিম্নরূপ:

int data;
while(in >> data) {  /* ... */ }

// which is equivalent to 
while( !(in >> data).fail() )  {  /* ... */ }

ইওফের বাইরে পড়ার চেষ্টা করার কারণে ব্যর্থতা সমাপ্তির শর্ত হিসাবে নেওয়া হয়। এর অর্থ হ'ল কোনও সফল স্ট্রিম এবং ইওফ ব্যতীত অন্য কারণে সত্যই ব্যর্থ হওয়ার মধ্যে পার্থক্য করার সহজ উপায় নেই। নিম্নলিখিত স্ট্রিম নিন:

  • 1 2 3 4 5<eof>
  • 1 2 a 3 4 5<eof>
  • a<eof>

while(in>>data)একটি সেট বন্ধ failbitজন্য সব তিনটি ইনপুট। প্রথম এবং তৃতীয়, eofbitএছাড়াও সেট করা হয়। অতএব লুপটি অত্যাধিক (২ য় এবং তৃতীয়) থেকে সঠিক ইনপুট (1 ম) পার্থক্য করার জন্য খুব কুরুচিপূর্ণ অতিরিক্ত যুক্তির প্রয়োজন।

তবে নিম্নলিখিতগুলি নিন:

while( !in.eof() ) 
{  
   int data;
   in >> data;
   if ( in.fail() ) /* handle with break or throw */; 
   // now use data
}    

এখানে, in.fail()যাচাই করা আছে যে যতক্ষণ পড়ার মতো কিছু আছে ততক্ষণ এটি সঠিক one এটির উদ্দেশ্য কেবলমাত্র লুপ টার্মিনেটর নয়।

এখন পর্যন্ত এত ভাল, তবে যদি স্রোতে পিছনের জায়গার জায়গা থাকে তবে কী ঘটে - eof()টার্মিনেটর হিসাবে প্রধান উদ্বেগের মতো কি মনে হচ্ছে ?

আমাদের ত্রুটি পরিচালনার জন্য আত্মসমর্পণের দরকার নেই; শুধু সাদা স্থান খেয়ে ফেলুন:

while( !in.eof() ) 
{  
   int data;
   in >> data >> ws; // eat whitespace with std::ws
   if ( in.fail() ) /* handle with break or throw */; 
   // now use data
}

std::wsস্ট্রিমটি স্থির করে রাখার সময় কোনও সম্ভাব্য (শূন্য বা তার বেশি) পিছনে স্থান এড়িয়ে যায় eofbitএবং নাfailbit । সুতরাং, in.fail()যতক্ষণ না কমপক্ষে একটি ডেটা পড়তে হয় ততক্ষণ প্রত্যাশার মতো কাজ করে। যদি সমস্ত ফাঁকা স্ট্রিমগুলিও গ্রহণযোগ্য হয় তবে সঠিক ফর্মটি হ'ল:

while( !(in>>ws).eof() ) 
{  
   int data;
   in >> data; 
   if ( in.fail() ) /* handle with break or throw */; 
   /* this will never fire if the eof is reached cleanly */
   // now use data
}

সংক্ষিপ্তসার: একটি সঠিকভাবে নির্মিত while(!eof)কেবল সম্ভব নয় এবং ভুলও নয়, তবে ডেটাগুলিকে সুযোগের মধ্যে স্থানীয়করণের অনুমতি দেয় এবং যথারীতি ব্যবসায় থেকে ত্রুটি পরীক্ষা করার ক্ষেত্রে একটি পরিষ্কারতর বিচ্ছেদ সরবরাহ করে। যা বলা হচ্ছে, while(!fail)অকারণে এটি আরও সাধারণ এবং সংক্ষুব্ধ প্রতিমা এবং এটি সাধারণ (পাঠের ধরণের প্রতি একক ডেটা) পরিস্থিতিতে পছন্দ করা যেতে পারে।


6
" সুতরাং লুপটির অতীতে কোনও অনুচিতের থেকে উপযুক্ত ইনপুটকে আলাদা করার কোনও সহজ (সহজ) উপায় নেই " " এক্ষেত্রে উভয় ক্ষেত্রে eofbitএবং failbitসেট করা থাকলেও অন্যটিতে failbitসেট করা থাকে। আপনাকে কেবল এটি পরীক্ষা করে নেওয়া দরকার যে লুপটি শেষ হওয়ার পরে একবারে প্রতিটি পুনরাবৃত্তির উপর নয়; এটি একবারে লুপটি ছেড়ে যাবে, সুতরাং এটি একবারে কেন লুপটি ছেড়ে যায় তা কেবল আপনাকে পরীক্ষা করতে হবে। while (in >> data)সমস্ত ফাঁকা প্রবাহের জন্য সূক্ষ্ম কাজ করে।
জোনাথন ওয়েকেলি

3
আপনি যা বলছেন (এবং এর আগে তৈরি একটি বিন্দু) এটি হ'ল খারাপ ফর্ম্যাট করা স্ট্রিমটি !eof & failঅতীত লুপ হিসাবে চিহ্নিত করা যায়। এমন কেস রয়েছে যেগুলিতে কেউ এর উপর নির্ভর করতে পারে না। উপরের মন্তব্যটি দেখুন ( goo.gl/9mXYX )। যাইহোক, আমি সর্বদা-সর্বোত্তম বিকল্প eofহিসাবে -চেক প্রস্তাব দিচ্ছি না । আমি কেবল বলছি, এটি "সম্ভবত অবশ্যই ভুল!" না হয়ে এটি করার একটি সম্ভাব্য এবং (কিছু ক্ষেত্রে আরও উপযুক্ত) উপায়! এটি এখানে প্রায় দাবি করা হয়।
স্লাই

2
"একটি উদাহরণ হিসাবে, বিবেচনা আপনি ত্রুটি যেখানে ডাটা ওভারলোড অপারেটর সঙ্গে একটি struct >> একযোগে একাধিক ক্ষেত্র পড়া জন্য কিভাবে পরীক্ষা চাই" - একটি অনেক সহজ যদি আপনার পয়েন্ট সমর্থন করছে stream >> my_intপ্রবাহ যেমন যেখানে রয়েছে "-": eofbitএবং failbitহয় সেট। এটি operator>>দৃশ্যের চেয়েও খারাপ , যেখানে ব্যবহারকারীর দ্বারা সরবরাহিত ওভারলোড কমপক্ষে eofbitসাপোর্টিংয়ের বিকল্পটি সমর্থন সমর্থন while (s >> x)ব্যবহারে ফিরে আসার আগে রয়েছে । আরও সাধারণভাবে, এই উত্তরটি একটি পরিষ্কার-পরিচ্ছন্নতা ব্যবহার করতে পারে - কেবল ফাইনালটি while( !(in>>ws).eof() )সাধারণত মজবুত এবং শেষদিকে এটি সমাধিস্থ হয়।
টনি দেলরোয়

74

কারণ প্রোগ্রামাররা যদি এটি না লিখেন তবে while(stream >> n)তারা সম্ভবত এটি লিখবেন:

while(!stream.eof())
{
    stream >> n;
    //some work on n;
}

এখানে সমস্যাটি হ'ল, আপনি some work on nপ্রথমে স্ট্রিমটি পঠন সফল হয়েছে কিনা তা যাচাই করা ছাড়া এটি করতে পারবেন না , কারণ যদি এটি ব্যর্থ হয়, তবে আপনার some work on nঅনাকাঙ্ক্ষিত ফলাফল প্রকাশিত হবে।

পুরো পয়েন্ট যে, eofbit, badbit, অথবা failbitনির্ধারণ করা হয় একটি প্রয়াস পর স্ট্রিম থেকে পড়তে তৈরি করা হয়। সুতরাং যদি stream >> nব্যর্থ হয়, তবে eofbit, badbitবা failbitতাত্ক্ষণিকভাবে সেট হয়ে গেছে, সুতরাং এটি লিখলে এটির আরও মূর্খতাবাদী while (stream >> n), কারণ প্রত্যাবর্তিত বস্তুটি প্রবাহ থেকে পড়াতে কিছুটা ব্যর্থতা দেখা দিয়েছে এবং ফলস্বরূপ লুপটি বন্ধ হয়ে যায় তা streamরূপান্তরিত falseকরে। এবং এটি রূপান্তরিত করে trueযদি পঠন সফল হয় এবং লুপটি অবিরত থাকে।


1
অপরিবর্তিত মানটির উপর কাজ করার সাথে উল্লিখিত "অনাকাঙ্ক্ষিত ফলাফল" বাদে , ব্যর্থ স্ট্রিম অপারেশনটি কোনও ইনপুট গ্রহণ না nকরলে প্রোগ্রামটি একটি অসীম লুপেও পড়তে পারে ।
mastov

10

অন্যান্য উত্তরগুলি ব্যাখ্যা করেছে যে যুক্তিটি কেন ভুল while (!stream.eof())এবং এটি কীভাবে ঠিক করা যায়। আমি আলাদা কিছুতে মনোনিবেশ করতে চাই:

কেন ইওফের জন্য স্পষ্টভাবে iostream::eofভুল ব্যবহার করছে তা পরীক্ষা করা হচ্ছে ?

সাধারণ কথায়, eof কেবলমাত্র অনুসন্ধান করা ভুল কারণ স্ট্রিম এক্সট্রাকশন ( >>) ফাইলের শেষের দিকে আঘাত না করে ব্যর্থ হতে পারে। যদি আপনার উদাহরণ থাকে int n; cin >> n;এবং স্ট্রিমটি থাকে helloতবে hএটি কোনও বৈধ অঙ্ক নয়, সুতরাং ইনপুটটির শেষে না পৌঁছানো ছাড়া নিষ্কাশন ব্যর্থ হবে।

এই ইস্যুটি স্ট্রিমের স্টেট থেকে এটি পড়ার চেষ্টা করার আগে এটি পরীক্ষা করার সাধারণ যুক্তিযুক্ত ত্রুটির সাথে মিলিত হয়েছে যার অর্থ এন ইনপুট আইটেমগুলির জন্য লুপটি N + 1 বার চলবে যা নিম্নলিখিত লক্ষণগুলির দিকে নিয়ে যায়:

  • স্ট্রিমটি খালি থাকলে লুপটি একবারে চলবে। >>ব্যর্থ হবে (পড়ার মতো কোনও ইনপুট নেই) এবং যে সমস্ত ভেরিয়েবলগুলি (দ্বারা stream >> x) সেট করার কথা ছিল তা আসলে অবিবেচনাযুক্ত। এটি আবর্জনা ডেটা প্রক্রিয়াজাতকরণের দিকে পরিচালিত করে, যা অযৌক্তিক ফলাফল হিসাবে প্রকাশ করতে পারে (প্রায়শই বিশাল সংখ্যা)।

    (যদি আপনার স্ট্যান্ডার্ড লাইব্রেরিটি সি ++ 11 এর সাথে সঙ্গতিপূর্ণ হয় তবে বিষয়গুলি এখন কিছুটা পৃথক: একটি ব্যর্থ >>এখন অখণ্ডনীয় পরিবর্তন 0ছাড়াই সংখ্যার ভেরিয়েবল সেট করে ( charগুলি ব্যতীত )))

  • স্ট্রিমটি খালি না হলে শেষ বৈধ ইনপুটটির পরে লুপটি আবার চলবে। যেহেতু শেষ পুনরাবৃত্তিতে সমস্ত >>ক্রিয়াকলাপ ব্যর্থ হয়, ভেরিয়েবলগুলি পূর্ববর্তী পুনরাবৃত্তির থেকে তাদের মানটি রাখে। এটি "শেষ লাইনটি দু'বার মুদ্রিত হয়েছে" বা "শেষ ইনপুট রেকর্ডটি দু'বার প্রক্রিয়াজাত করা" হিসাবে প্রকাশ করতে পারে।

    (এটি সি ++ 11 সাল থেকে কিছুটা আলাদাভাবে প্রকাশিত হওয়া উচিত (উপরে দেখুন): এখন আপনি বারবার শেষ লাইনটির পরিবর্তে শূন্যগুলির একটি "ভুত রেকর্ড" পান get)

  • স্ট্রিমে যদি ত্রুটিযুক্ত ডেটা রয়েছে তবে আপনি কেবল এটি পরীক্ষা করে থাকেন .eof, আপনি একটি অসীম লুপ দিয়ে শেষ করেন। >>স্ট্রিম থেকে কোনও ডেটা নিষ্কাশন করতে ব্যর্থ হবে, সুতরাং লুপটি শেষ পর্যন্ত পৌঁছায় না place


সংক্ষিপ্তবৃত্তি করতে: সমাধান সাফল্যের পরীক্ষার জন্যে >>অপারেশন নিজেই একটি পৃথক ব্যবহার না করার .eof()পদ্ধতি: while (stream >> n >> m) { ... }শুধু সি হিসাবে আপনি সাফল্যের পরীক্ষা scanfকল নিজেই: while (scanf("%d%d", &n, &m) == 2) { ... }


1
এটি সর্বাধিক সঠিক উত্তর, যদিও সি ++ 11 হিসাবে, আমি বিশ্বাস করি না যে
চলকগুলি আর অবিচ্ছিন্ন করা যায়
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.