سؤال

يعمل هذا الرمز كما هو مطلوب للجزء الأكبر ، وهو مطالبة المستخدم بحرف واحد ، وتنفيذ الإجراء المرتبط ، ومطالبة المستخدم بالضغط على الإرجاع ، والتكرار. ومع ذلك ، عندما أدخل ^d (eof) في المطالبة ، تحدث حلقة لا حصر لها. أقوم بمسح حالة الخطأ عبر std :: cin.clear () والاتصال std :: cin.ignore (...) لمسح المخزن المؤقت. ماذا يمكن أن يسبب حلقة لانهائي؟

#include <iostream>
#include <limits>

void wait()
{
    std::cout << std::endl << "press enter to continue.";
    std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
    std::cin.clear();
    std::cin.get();
}

int main()
{
    char response;

    while (true)
    {
        std::cout << "enter a character at the prompt." << std::endl << "> ";
        std::cin >> response;
        switch (response)
        {
            case 'q':
                exit(0);
                break;
        }
        wait();
    }
}

أقوم بتشغيل هذا في محطة Mac OS X ، إذا كان الأمر مهمًا.


تحديث: ما أطلبه حقًا هنا هو ، عندما يدخل المستخدم EOF (^D) في المطالبة, ، كيف يمكنني اكتشافها (ب) إعادة تعيين الدفق حتى يتمكن المستخدم من متابعة إدخال البيانات.

المثال التالي يختلف عن الكود أعلاه, ، ولكن يوضح نفس مبدأ مسح الدفق بعد اكتشاف ^d واستمراره في القراءة من هذا الدفق.

> a
you entered: a
> b
you entered: b
> ^D
you entered EOF
> c
you entered: c
...
هل كانت مفيدة؟

المحلول

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

أيضا ، أنت تستخدم std::endl في الإخراج السريع الخاص بك حيث لا معنى له. std::endl مطبوعات \n ثم تغسل المخزن المؤقت ، لكنك تقوم بعد ذلك بطباعة المزيد من الأحرف على الفور بحيث يكون التدفق زائدة عن الحاجة. مثل cin و cout هي (عادة) ربط, ، استدعاء وظيفة الإدخال ل std::cin سوف يسبب std::cout أن يتم مسحها في أي حال ، لذا يمكنك أيضًا وضع ملف \n في سلسلة المطالبة الخاصة بك وحفظها على الإضافات الإضافية << العاملين.

لماذا لا تجعل وظيفة المطالبة تقوم بطباعة المطالبة ، ويرجع الإدخال A إرجاع مرجع إلى الدفق بحيث يمكنك اختباره للنجاح باستخدام دفق المعتاد إلى تحويل النوع المنطقي.

بهذه الطريقة يمكنك التخلص من الاستراحة الحقيقية والصريحة.

std::istream& prompt_for_input( std::istream& in, std::ostream& out, char& response )
{
    out << "enter a character at the prompt.\n> ";
    in >> response;
    return in;
}

int main()
{
    char response;

    while ( prompt_for_input( std::cin, std::cout, response ) && response != 'q' )
    {
        wait();
    }
}

نصائح أخرى

السؤال لا معنى له حقًا للمدخلات القياسية. سيكون من الصعب قراءة شيء ما من الإدخال القياسي بعد انتهاء هذا الدفق-سيتعين عليك إعادة فتحه بطريقة أو بأخرى ، ولكن لا توجد طريقة لإعادة فتح المدخلات القياسية. قد يكون متصلاً بأنبوب ، أو إلى ملف ، أو إلى محطة - ولا يوجد سلوك مناسب لكل هذه.

لذلك سوف تقرأ صراحة من المحطة ، أفترض. على أنظمة UN*X ، وهذا يعني القراءة /dev /tty ، وإعادة فتحها عند الحاجة. إليك مثال بسيط يفعل ذلك ؛ تم حذف معظم فحص الأخطاء.

// Warning: UN*X-specific

#include <iostream>
#include <fstream>

using namespace std;

int main()
{
    for(unsigned i=0; ; i++) {
        ifstream tty("/dev/tty");
        if (! tty) {
            cerr << "Failed to open TTY" << endl;
            return 2;
        }
        string s;
        while (getline(tty,s))
            cout << i << ": " << s << endl;
    }
    return 0;   // (unreached)
}

ستحتاج إلى مسح الأعلام للحصول على الدفق للقيام بالكثير من أي شيء بعد مواجهته EOF.

خطأ ، قد أفتقد شيئًا ، لكنني لا أراك أبدًا break خارج ال while (true) عقدة.

// ...
while (true) {
    if (std::cin.eof()) {
        break;
    }
    // ...
}

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

ربما تريد قراءة الإدخال من مكان ما بعد أن أغلق المستخدم stdin الخاص بك مع ^d؟ في هذه الحالة ، سيتعين عليك إغلاق CIN وإعادة فتحه للقراءة من المكان الآخر الذي تريد قراءة الإدخال منها.

كما ذكرنا ، تحتاج إلى التأكد من أن الدفق ليس في حالة سيئة. أود أن أتغير أثناء شرط استخدام جيد (). لا تحقق فقط من EOF لأن هناك عدة طرق يمكن أن يصبح فيها تيار "سيئًا" بخلاف EOF.

while (std::cin.good()) {...
while ((std::cout << "Enter a character at the prompt ")
      && (!(std::cin >> response) || response =='q')) {
 std::cout << "Not a valid input";
 std::cin.clear();
 std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');

}

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top