سؤال

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

while (!finished)
{
    printf("Guess the word '%s'\n",covered);

    scanf("%c", &currentGuess);

    i=0;
    while (i<=wordLength)
    {
        if (i == wordLength)
        {
            --numLives;
            printf("Number of lives: %i\n", numLives);
            break;
        } else if (currentGuess == secretWord[i]) {
            covered[i] = secretWord[i];
            secretWord[i] = '*';
            break;
        }
        ++i;
    }

    j=0;
    while (j<=wordLength)
    {
        if (j == (wordLength)) {
            finished = 1;
            printf("Congratulations! You guessed the word!\n");
            break;
        } else {
            if (covered[j] == '-') {
                break;
            }
        }
        ++j;

        if (numLives == 0) {
            finished = 1;
        }

    }
}

أفترض أن المشكلة تفكر في تفكيرها أنه أخذ شيء ما عندما لا يكون كذلك، لكن ليس لدي أي فكرة عن السبب. هل يوجد لدى أحد أي فكرة؟ أنا أستخدم GCC 4.0.1 على Mac OS X 10.5.

هل كانت مفيدة؟

المحلول

عندما تقرأ إدخال لوحة المفاتيح مع scanf(), ، يتم قراءة الإدخال بعد الضغط على المدخل ولكن لا يتم استهلاك Newline الناتج عن المفتاح ENTER من خلال المكالمة scanf(). وبعد هذا يعني في المرة القادمة التي تقرأها من الإدخال القياسي، سيكون هناك حدوث جديد في انتظاركم (مما سيجعل التالي scanf() استدعاء العودة على الفور مع عدم وجود بيانات).

لتجنب ذلك، يمكنك تعديل التعليمات البرمجية الخاصة بك بشيء مثل:

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

ال %*c يطابق حرف واحد، ولكن يشير النجمة إلى أن الحرف لن يتم تخزينها في أي مكان. هذا له تأثير استهلاك حرف Newline الناتج عن المفتاح ENTER بحيث تكون المرة التالية التي تتصل بها scanf() أنت تبدأ بمعالج مدخل فارغ.

مذكرة قانونية: إذا ضغط المستخدم على مفتاحين، ثم اضغط على ENTER، scanf() سيعود ضغط المفاتيح الأول، وتناول الثاني، وترك Newline لمكالمات الإدخال التالية. quirks مثل هذا سبب واحد لماذا scanf() وتجنب الأصدقاء من قبل العديد من المبرمجين.

نصائح أخرى

خطوط جيولاين.

أول مرة من خلال حلقة، SCANF () يقرأ الحرف. ثم يقرأ الخط الجديد. ثم يقرأ الحرف التالي؛ كرر.

كيفية إصلاح؟

نادرا ما تستخدم SCANF ()، ولكن إذا كنت تستخدم سلسلة تنسيق "%.1s", ، يجب أن تخطي المساحة البيضاء (بما في ذلك الخطوط الجديدة) ثم اقرأ حرف مساحة غير بيضاء. ومع ذلك، سوف تتوقع مجموعة شخصية بدلا من حرف واحد:

char ibuff[2];

while ((scanf("%.1s", ibuff) == 1)
{
    ...
}

كسر المشكلة إلى أجزاء أصغر:

int main(void) {
    char val;
    while (1) {
        printf("enter val: ");
        scanf("%c", &val);
        printf("got: %d\n", val);
    }
}

الناتج هنا هو:

enter val: g
got: 103
enter val: got: 10

لماذا أراد scanf أعطيك "10" آخر هناك؟

نظرا لأننا طباعنا رقم ASCII لقيمتنا، فإن "10" في ASCII "أدخل" scanf يجب أيضا الاستيلاء على مفتاح "أدخل" كحرف.

بالتأكيد بما فيه الكفاية، والنظر في الخاص بك scanf سلسلة، أنت تسأل عن حرف واحد في كل مرة من خلال حلقة الخاص بك. تعتبر أحرف التحكم أيضا أحرفا، وسيتم التقاطها. على سبيل المثال، يمكنك الضغط على "ESC" ثم "أدخل" في حلقة أعلاه والحصول على:

enter val: ^[
got: 27
enter val: got: 10

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

scanf(" %c", &fooBar);

لاحظ الفضاء قبل %c. وبعد هذا مهم، لأنه يطابق جميع المسابقة المسبقة المسبقة.

جيم وجوناثان أليس كذلك.

للحصول على خط Scanf الخاص بك للقيام بما تريد (تستهلك حرف Newline W / o وضعه في المخزن المؤقت) سأغيره إليه

scanf("%c\n", &currentGuess);

(لاحظ ال \n)

التعامل مع الأخطاء في هذا فظيع على الرغم من. على الأقل، يجب عليك التحقق من قيمة الإرجاع من SCANF مقابل 1، وتجاهل الإدخال (مع تحذير) إذا لم يعد ذلك.

بضع نقاط لاحظت:

  • scanf("%c") سيتم قراءة حرف واحد واحتفظ بالمدخل في المخزن المؤقت للإدخال في المرة القادمة من خلال الحلقة
  • أنت زيادة i حتى عندما لا تتطابق الحرف القراءة من المستخدم من الحرف في secretWord
  • متى covered[j] من أي وقت مضى الحصول على "-"؟

أعتقد: يعالج الرمز الخاص بك جديد كأحد التخمينات عند إدخال البيانات. لقد قمت دائما بتجنب أسرة * SCANF () بسبب معالجة الأخطاء لا يمكن السيطرة عليها. حاول استخدام FGETS () بدلا من ذلك، ثم سحب أول شار / بايت.

أرى بعض الأشياء في التعليمات البرمجية الخاصة بك:

  1. SCANF إرجاع عدد العناصر التي تقرأها. ربما تريد التعامل مع الحالات التي ترجع فيها 0 أو eof.
  2. سيكون تخميني هو أن المستخدم يضرب حرف + أدخل وأنت تحصل على الخط الجديد كحرف ثان. وسيتم إضافة طريقة سهلة للتحقق من إضافة عبارة طباعة تصحيح الأخطاء لإظهار الحرف الذي تم إدخاله.
  3. سيتطابق الرمز الخاص بك فقط من الحدوث الأول لحرف المباراة، أي إذا كانت الكلمة كانت "اختبارا"، ويدخل المستخدم "T"، فسيطابق الكود الخاص بك فقط "T"، وليس كلاهما. تحتاج إلى ضبط حلقة الأولى الخاصة بك للتعامل مع هذا.

عند إدخال الحرف، يجب عليك إدخال حرف Whitespace للمضي قدما. هذه الأحرف المسافة بيضاء موجودة في المخزن المؤقت للإدخال، stdin ملف، وقراءة من قبل scanf() وظيفة. يمكن حل هذه المشكلة عن طريق استهلاك هذه الشخصية الإضافية. يمكن القيام بذلك بواسطة USNIG getchar() وظيفة.

scanf("%c",&currentGuess);  
getchar();   // To consume the whitespace character.

أفضل أن أقترح عليك تجنب استخدام scanf() وبدلا من ذلك استخدام getchar(). وبعد ال scanf()يتطلب الكثير من مساحة الذاكرة. getchar() هي وظيفة خفيفة. لذلك يمكنك أيضا استخدام

char currentGuess;  
currentGuess=getchar();  
getchar();  // To consume the whitespace character.
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top