كيف تقرأ حتى EOF من السينما في C ++

أقوم بترميز برنامج يقوم بقراءة البيانات مباشرة من مدخلات المستخدم وكان يتساءل كيف يمكنني (بدون تكرار) قراءة جميع البيانات حتى EOF من الإدخال القياسي. كنت أفكر في استخدام cin.get (input، '\ 0') ولكن '\ 0' ليست حقا حرف EOF ، الذي يقرأ فقط حتى EOF أو '\ 0' ، أيهما يأتي أولاً.

أو يستخدم الحل الطريقة الوحيدة للقيام بذلك؟ إذا كان الأمر كذلك ، فما هي أفضل طريقة؟

67

10 إجابة

الطريقة الوحيدة التي يمكنك من خلالها قراءة كمية متغيرة من البيانات من stdin تستخدم الحلقات. لقد وجدت دائمًا std :: getline() تعمل بشكل جيد للغاية:

std::string line;
while (std::getline(std::cin, line))
{
    std::cout << line << std::endl;
}

افتراضيا getline() يقرأ حتى خط جديد. يمكنك تحديد حرف إنهاء بديلة ، ولكن EOF ليس حرفًا بحد ذاته لذا لا يمكنك ببساطة إجراء مكالمة واحدة إلى getline ().

59
وأضاف
هناك شيء يجب توخي الحذر هنا عندما تقرأ من الملفات التي تم توجيهها عبر stdin ، هو أن هذا ومعظم الإجابات المعطاة سيتم إلحاق تغذية خط إضافي في نهاية المدخلات الخاصة بك. لا تنتهي جميع الملفات بتغذية سطر ، ولكن كل تكرار للحلقة يلحق "std :: endl" بالدفق. قد لا يكون هذا مشكلة في معظم الحالات ، ولكن إذا كانت سلامة الملفات تمثل مشكلة ، فقد يعود ذلك إلى عضة لك.
وأضاف المؤلف Zoccadoum, مصدر
هذا لا ينبغي أن يكون الجواب الأكثر ربحا. انظر أدناه جواب ويكي المجتمع. أيضًا ، ربما يمكنك الاطلاع على هذا السؤال: stackoverflow.com/questions/3203452/&hellip،
وأضاف المؤلف loxaxs, مصدر

يمكنك إجراء ذلك دون استخدام حلقات صريحة باستخدام برامج تشغيل المتصفحات. أنا متأكد من أنه يستخدم نوعا من حلقة داخليا.

#include 
#include 
#include 
#include 
#include 

int main()
{
// don't skip the whitespace while reading
  std::cin >> std::noskipws;

// use stream iterators to copy the stream to a string
  std::istream_iterator it(std::cin);
  std::istream_iterator end;
  std::string results(it, end);

  std::cout << results;
}
43
وأضاف
لطيف. أما بالنسبة لـ "أنا متأكد من أنها تستخدم نوعًا ما من الحلقة داخليًا" - أي حل قد يحدث.
وأضاف المؤلف Michael Burr, مصدر
يبدو هذا لإزالة أحرف السطر الجديد من الإدخال ، حتى إذا كانت تحدث في الوسط.
وأضاف المؤلف Multisync, مصدر

باستخدام الحلقات:

#include 
using namespace std;
...
// numbers
int n;
while (cin >> n)
{
   ...
}
// lines
string line;
while (getline(cin, line))
{
   ...
}
// characters
char c;
while (cin.get(c))
{
   ...
}

مورد

37
وأضاف

بعد البحث عن حل KeithB باستخدام std :: istream_iterator ، اكتشفت < كود> الأمراض المنقولة جنسيا: istreambuf_iterator </القانون> .

اختبار البرنامج لقراءة كل المدخلات المنقولة بالأنابيب في سلسلة ، ثم كتابتها مرة أخرى:

#include 
#include 
#include 

int main()
{
  std::istreambuf_iterator begin(std::cin), end;
  std::string s(begin, end);
  std::cout << s;
}
16
وأضاف
ربما ينبغي أن يكون هذا هو الجواب القانوني.
وأضاف المؤلف Kerrek SB, مصدر
Downvoted. إذن ما هي الإيجابيات أو السلبيات مقارنة بحل KeithB؟ نعم ، أنت تستخدم std :: istreambuf_iterator بدلاً من std :: istream_iterator ، ولكن ماذا؟
وأضاف المؤلف Multisync, مصدر

أبسط محتمل وفعال بشكل عام:

#include 
int main()
{
    std::cout << std::cin.rdbuf();
}

إذا لزم الأمر ، استخدم دفق أنواع أخرى مثل std :: ostringstream كمخزن مؤقت بدلاً من دفق الإخراج القياسي هنا.

4
وأضاف
كنت تعرف بالفعل ، ولكن قد تكون مفيدة لبعض: std :: ostringstream std_input؛ std_input << std :: cin.rdbuf ()؛ std :: string s = std_input.str() . لديك جميع المدخلات في s (كن حذراً مع std :: string إذا كان الإدخال كبير جداً)
وأضاف المؤلف ribamar, مصدر

يمكنك استخدام std :: istream :: getline() ( أو يفضل أن يكون يعمل على السلسلة std :: string ) للحصول على سطر كامل . كلاهما يحتوي على إصدارات تسمح لك بتحديد المحدد (حرف نهاية السطر). الافتراضي لإصدار السلسلة هو '\ n'.

2
وأضاف

ملاحظة جانبية حزينة: قررت استخدام C ++ IO لتكون متسقة مع الشفرة المعززة. من الإجابات على هذا السؤال اخترت أثناء (std :: getline (std :: cin، line)) . باستخدام g + + الإصدار 4.5.3 (-O3) في cygwin (mintty) حصلت على 2 ميغابايت/ثانية الإنتاجية. Microsoft Visual C ++ 2010 (/ O2) جعلها 40 ميغابايت/ثانية لنفس رمز.

بعد إعادة كتابة IO إلى C نقية بينما (fgets (buf، 100، stdin)) قفزت سرعة النقل إلى 90 ميجابايت/ثانية في كلا المركبين المختبرين. هذا يحدث فارقا لأي مدخلات أكبر من 10 ميغابايت ...

2
وأضاف
لا حاجة لإعادة كتابة التعليمات البرمجية الخاصة بك إلى C خالص ، فقط قم بإضافة std :: iOS :: sync_with_stdio (false)؛ قبل الدورة الخاصة بك. قد يساعد cin.tie (NULL) ؛ أيضًا إذا قمت بتبادل القراءة والكتابة.
وأضاف المؤلف R D, مصدر
while(std::cin) {
//do something
}
1
وأضاف
هذه كارثة رهيبة من إجابة ، لأنه يكاد يكون من المؤكد أن يؤدي إلى رمز خاطئ.
وأضاف المؤلف Kerrek SB, مصدر

أحد الخيارات هو استخدام حاوية ، على سبيل المثال ،

std::vector data;

إعادة توجيه كل الإدخال في هذه المجموعة حتى يتم تلقي EOF ، أي

std::copy(std::istream_iterator(std::cin),
    std::istream_iterator(),
    std::back_inserter(data));

ومع ذلك ، قد تحتاج الحاوية المستخدمة إلى إعادة تخصيص الذاكرة كثيرًا ، أو ستنتهي باستثناء std :: bad_alloc عندما يخرج النظام من الذاكرة. لحل هذه المشكلات ، يمكنك حجز كمية ثابتة N من العناصر ومعالجة هذه الكمية من العناصر بمعزل ، بمعنى

data.reserve(N);    
while (/*some condition is met*/)
{
    std::copy_n(std::istream_iterator(std::cin),
        N,
        std::back_inserter(data));

    /* process data */

    data.clear();
}
0
وأضاف

انتظر ، أنا أفهمك بشكل صحيح؟ أنت تستخدم cin لإدخال لوحة المفاتيح ، وتريد إيقاف قراءة الإدخال عندما يقوم المستخدم بإدخال حرف EOF؟ لماذا يقوم المستخدم بكتابة حرف EOF؟ أو هل تقصد أنك تريد التوقف عن القراءة من ملف في EOF؟

إذا كنت تحاول بالفعل استخدام cin لقراءة حرف EOF ، فلماذا لا نحدد فقط EOF كمحدد؟

// Needed headers: iostream

char buffer[256];
cin.get( buffer, '\x1A' );

إذا كنت تقصد إيقاف القراءة من ملف في EOF ، فكل ما عليك هو استخدام getline وحدد مرة أخرى EOF كمحدد.

// Needed headers: iostream, string, and fstream

string buffer;

    ifstream fin;
    fin.open("test.txt");
    if(fin.is_open()) {
        getline(fin,buffer,'\x1A');

        fin.close();
    }
0
وأضاف