سؤال

في كود C++ التالي، أدركت ذلك gcount() كان يعود بعدد أكبر مما أردت، لأنه getline() يستهلك حرف السطر الجديد الأخير ولكنه لا يرسله إلى دفق الإدخال.

لكن ما ما زلت لا أفهمه هو مخرجات البرنامج.بالنسبة للإدخال "Test "، لماذا أحصل على "est "؟كيف يؤثر خطأي على أولاً طبيعة السلسلة بدلاً من إضافة القمامة غير المرغوب فيها إلى النهاية؟وكيف يتعارض إخراج البرنامج مع الطريقة التي تبدو بها السلسلة في مصحح الأخطاء ("اختبار "، كما أتوقع)؟

#include <fstream>
#include <vector>
#include <string>
#include <iostream>

using namespace std;

int main()
{
    const int bufferSize = 1024;
    ifstream input( "test.txt", ios::in | ios::binary );

    vector<char> vecBuffer( bufferSize );
    input.getline( &vecBuffer[0], bufferSize );
    string strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() );
    cout << strResult << "\n";

    return 0;
}
هل كانت مفيدة؟

المحلول

ولقد تتكرر أيضا هذه النتيجة، ويندوز فيستا، فيجوال ستوديو 2005 SP2.

عند يمكنني معرفة ما هيك ما يحدث، وأنا سوف تحديث هذه الوظيفة.

تعديل : حسنا، هناك نذهب. المشكلة (ونتائج مختلفة الناس يزدادون) هي من \ ص. ما يحدث هو استدعاء input.getline ووضع النتيجة في vecBuffer. وظيفة getline شرائط قبالة \ ن، ولكن يترك \ ص في المكان.

وأنت ثم نقل vecBuffer إلى متغير سلسلة، ولكن استخدام وظيفة gcount من المدخلات، وهذا يعني أنك سوف تحصل شار واحد أكثر من اللازم، لأن المتغير إدخال ما يزال يحتوي على \ ن، وvecBuffer لا.

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

-       strResult   "Test"
        [0] 84 'T'  char
        [1] 101 'e' char
        [2] 115 's' char
        [3] 116 't' char
        [4] 13 '␍'  char
        [5] 0   char

وحتى ذلك الحين "اختبار" يتم طباعتها، تليها إرجاع (يضع المؤشر مرة أخرى في بداية السطر)، حرف فارغة (الكتابة فوق T)، وأخيرا \ ن، الأمر الذي يضع المؤشر بشكل صحيح على الخط الجديد.

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

نصائح أخرى

لقد قمت بتكرار مشكلة Tommy على نظام Windows XP Pro Service Pack 2 مع التعليمات البرمجية التي تم تجميعها باستخدام Visual Studio 2005 SP2 (في الواقع، تقول "الإصدار 8.0.50727.879")، والتي تم إنشاؤها كمشروع وحدة تحكم.

إذا كان ملف test.txt الخاص بي يحتوي على "اختبار" وCR فقط، فسيقوم البرنامج بإخراج "est" (لاحظ المسافة البادئة) عند التشغيل.

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


تحديث:بعد اللعب بها قليلاً، أنا متأكد من أن هذا ما يحدث.إذا نظرت إلى strResult في مصحح الأخطاء، فسترى أنه تم نسخه عبر قيمة عشرية 13 في النهاية.هذا هو CR، وهو في Windows-land هو ' '، وفي كل مكان آخر هو "العودة إلى بداية السطر".إذا قمت بدلاً من ذلك بتغيير المنشئ الخاص بك لقراءة:

سلسلة strResult( vecBuffer.begin(), vecBuffer.begin() + input.gcount() - 1 );

...(حتى لا يتم نسخ السجل التجاري) ثم تتم طباعة "اختبار" كما تتوقع.

أنا متأكد تمامًا من أن حرف T يتم كتابته بالفعل ثم يتم استبداله.يؤدي تشغيل نفس البرنامج في نافذة rxvt (cygwin) إلى إنتاج المخرجات المتوقعة.يمكنك القيام ببعض الأشياء.إذا تخلصت من ios::binary في جهازك المفتوح، فسيتم تحويله تلقائيًا إلى وستعمل الأمور كما تتوقع.

يمكنك أيضًا فتح الملف النصي الخاص بك في المحرر الثنائي من خلال النقر على السهم الصغير لأسفل الموجود على زر فتح في مربع حوار فتح الملف واختيار فتح باستخدام...->المحرر الثنائي.سيتيح لك ذلك إلقاء نظرة على ملفك والتأكد من أنه يحتوي بالفعل على وليس فقط.

يحرر:لقد قمت بإعادة توجيه الإخراج إلى ملف وهو يكتب:

Test\r\0\r\n

سبب حصولك على \0 هو أن gcount يُرجع 6 (تمت إزالة 6 أحرف من الدفق) ولكن لا يتم نسخ المحدد النهائي إلى المخزن المؤقت، بل يتم نسخ "\0" بدلاً من ذلك.عندما تقوم بإنشاء السلسلة، فأنت في الواقع تطلب منها تضمين '\0'.std::string ليس لديه مشكلة مع 0 المضمن ويخرجه كما هو مطلوب.يبدو أن بعض الأصداف تُخرج حرفًا فارغًا وتكتب فوق T، بينما لا تفعل قذائف أخرى أي شيء ويبدو الإخراج جيدًا، لكنه لا يزال على الأرجح خاطئًا لأنه يحتوي على '\0' المضمن

cout << strResult.c_str() << "\n";

سيؤدي تغيير السطر الأخير إلى هذا إلى التوقف عند \0 وسيحصل أيضًا على الإخراج المتوقع.

واختبرت التعليمات البرمجية باستخدام Visual Studio 2005 SP2 على نظام التشغيل Windows XP SP3 برو (32 بت)، ويعمل كل شيء على ما يرام.

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