سؤال

أنا أكتب تطبيقًا في C باستخدام Win32 API. عندما أحاول تكبير حجم صفيف بلدي ، باستخدام وظيفة HeprealLoc () ، فإنه يغير القيم الحالية في الصفيف ، بدلاً من نسخها. الرمز الذي أستخدمه لإعادة تخصيص الذاكرة:

BOOL ChangeFeedArraySize(UINT newSize)
{   
    char tempChar[20] = "";
    PFEED tempArr;
    if (newSize == 1)
    {
        tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
    }
    else
    {
        tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED));
        // FEED - a struct
        // PFEED - a pointer to the struct
        // categoryArray - array to be reallocated
    }

    if (tempArr != NULL)
    {
        MessageBox(NULL, ltoa(HeapSize(heap, 0, tempArr),tempChar,10) , "Heap size after reallocation", MB_OK | MB_ICONEXCLAMATION);
        feedArray = tempArr;
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

فيما يلي حالة المصفوفات عندما تكون في نقطة التوقف. تُظهر صفيف التغذية حالة الصفيف الحالية. تُظهر صفيف temp حالة الصفيف المعاد تخصيصها (وهي مختلفة).

صفيف التغذية:

Feedarray http://www.freeimagehosting.net/uploads/526b0b2172.jpg

صفيف درجة الحرارة:

Temparray http://www.freeimagehosting.net/uploads/17858f2e7e.jpg

الرجاء المساعدة ..:

رابط إلى وصف الوظيفة على MSDN

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

المحلول

تستشهد بوظيفة خاصة بنظام Windows ، ولكن هذا صحيح أيضًا realloc(), ، وهو المكافئ المعياري.

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

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

بشكل عام ، فإن النمط الذي تريد متابعته لهذا النوع من الأشياء هو مثل هذا:

void *newmem = realloc(oldmem, newsize);
if (!newmem)
{
   // TODO: handle failure
   // possibly free(oldmem); depending on how you want to handle errors
}
else
{
   oldmem = newmem;
}

اختصار مشترك يأخذه الناس هو "oldmem = realloc(oldmem, newsize);"، لكن هذا ليس رشيقًا كما سبق ، كما يتسرب oldmem عندما يكون هناك فشل.

تحديث بناءً على تحريرك:

شيء واحد أتساءل عنه في الكود الخاص بك هو هذا الجزء:

if (newSize == 1)
{
    tempArr = (PFEED)HeapAlloc(heap, HEAP_ZERO_MEMORY, sizeof(FEED));
}

يبدو أن هذا يفترض أن التخصيص الأول سيكون دائمًا من حجم واحد. هل أنت متأكد أنك لا تقصد أن تقول if (feedArray == NULL), ، ثم تخصيص newSize * sizeof(FEED)?

التحديث الثاني:

نعم. الشيء الآخر الذي يبرز هو:

    tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, فئة,
                                 newSize * sizeof(FEED));
    // Snip...

    if (tempArr != NULL)
    {
        // Snip...
        Feedarray = tempArr;

يجب أن تكون الأجزاء الجريئة هي نفسها.

نصائح أخرى

من الوثائق التي أرى ذلك:

يضمن HeapRealloc الحفاظ على محتوى الذاكرة التي يتم إعادة تخصيصها ، حتى لو تم تخصيص الذاكرة الجديدة في موقع مختلف. تتضمن عملية الحفاظ على محتوى الذاكرة عملية نسخة ذاكرة قد تستغرق وقتًا طويلاً للغاية.

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

بعد الدعوة إلى Heprealloc تم إصدار الفئة الأصلية ، لذا لم تعد تملكها. قد تكون هناك تخصيصات أخرى قد أعادت استخدامها لأغراض أخرى وقد تغير المحتوى. تحتاج إلى استخدام Temparr من الآن فصاعدًا:

tempArr = (PFEED)HeapReAlloc(heap, HEAP_ZERO_MEMORY, categoryArray, newSize * sizeof(FEED)); 
cetagoryArray = tempArr;

أين تعتني بالاتصال بـ Heprealloc؟ يجب أن تنظر في عاد المؤشر ، وليس الأصلي الذي تم تحريره بعد مكالمتك

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