سؤال

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

سؤالي هو: هل أحتاج إلى تحرير هذا المؤشر قبل نهاية الوظيفة؟

void functionName()
{
 char *variable = (char *) malloc(0);
    //variable is resized with realloc x number of times

 //should free be called here?
 return;
}

يجب أن أشير أيضًا إلى أنني حاولت تحرير المؤشر ، ومع ذلك ، GDB يعطيني تحذيرات عندما أفعل ذلك.

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

المحلول

نعم ، عليك تحريرها أو ستسرب الذاكرة. يجب أن يبدو رمزك شيئًا كهذا:

void function(void) 
{
    char *variable = (char *)malloc(0);

    variable = realloc(variable, 10);
    // do something with new memory

    variable = realloc(variable, 20);
    // do something with more new memory

    free(variable);  // clean up
}

الدعوة malloc(0) أعتقد أنه غريب بعض الشيء.

نصائح أخرى

بضع نقاط لصنعها:

لا أستطيع أن أرى كيف تستخدم realloc() في الكود الخاص بك ، ولكن إذا كنت تستخدمه مثل هذا ، فمن الخطأ:

variable = realloc(variable, amount);

عندما يكون غير قادر على تخصيص المزيد من الذاكرة ، realloc() عائدات NULL ولكن يترك المؤشر الأصلي دون تغيير. في السطر أعلاه ، هذا يعني ذلك variable هو NULL وقد فقدنا الوصول إلى الذاكرة التي أشار إليها ، ولكن لم يتم تحرير هذه الذاكرة. المصطلح الصحيح هو:

void *tmp = realloc(variable, amount);
if(tmp)
  {
    // success! variable invalid, tmp has new allocated data
    variable = tmp;
  }
else
  {
    // failure! variable valid, but same size as before, handle error
  }

السبب الذي يجب عليك استخدامه الثاني هو أنه مع realloc(), الفشل سيء ، ولكنه قابل للاسترداد تمامًا في العديد من المواقف ، على عكس malloc() حيث يعني الفشل عادة "توقف عن كل شيء ويموت".

هذه مشكلة أكثر إثارة للجدل ، ولكن من المشكوك فيها ما إذا كان يجب عليك إلقاء قيمة الإرجاع أم لا malloc() و realloc() مثلك. يعتبر:

// functionally identical in C
char *a = malloc(10);
char *b = (char *)malloc(10);

في C ++ ، المدلى بها يجب يتم صنعها ، لأنه في C ++ void * لا يمكن تحويلها ضمنيًا إلى نوع مؤشر آخر. (أعتقد أن هذا خطأ في اللغة ، لكنه ليس مكاني للحكم.) إذا كان رمزك C ++ ، فيجب أن تستخدم new و delete على أي حال. إذا كان الكود الخاص بك هو C ولكنه يحتاج إلى تجميع مع المترجمين C ++ (لسبب غير محدود) ، فليس لديك خيار سوى الإلقاء. إذا لم تكن بحاجة إلى تجميع كود C مع مجمعات C ++ (وهو ما يشبه الاضطرار إلى تشغيل رمز Ruby في مترجم Python) ، تابع إلى النقاط أدناه ، وهذا هو السبب في أنني لا ينبغي عليك إلقاؤه.

  1. في C89 ، إذا تم استخدام وظيفة دون إعلانها ، فسيتم إعلانها ضمنيًا على أنها عودة int. إذا ، على سبيل المثال ، نسينا ذلك #include <stdlib.h> ودعنا malloc(), ، قد يتسبب الإصدار بدون طاقم في حدوث خطأ في التحويل البرمجي (قوالب ضمنية من int ل char * غير مسموح به) ، في حين أن الإصدار مع الممثلين سيخبر (خطأ) المترجم "أعرف أن هذا يبدو مجنونًا ، لكن يلقيه على أي حال." سيعطيك معظم المترجمين تحذيرًا لإعلانات ضمنية (أو غير قابلة للتوافق) من الوظائف المدمجة مثل malloc(), ، لكن الممثلين يجعلون من الصعب العثور عليها.

  2. قل أن لديك بعض البيانات:

    float *array = (float *)malloc(10 * sizeof(float));
    

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

    double *array = (double *)malloc(10 * sizeof(double));
    

    إذا كتبت ، من ناحية أخرى ، كتبت:

    float *array = malloc(10 * sizeof *array);
    

    ستحتاج فقط إلى التغيير float ل double في مكان واحد. علاوة على ذلك ، استخدم دائمًا sizeof *obj بدلاً من sizeof(type) ولا تعني استخدام الممثلين أبدًا أن دعوة لاحقة إلى realloc() يمكن أن تعمل بدون أي تغييرات, ، أثناء استخدام القوالب وأسماء الأنواع الصريحة ، يتطلب العثور على أي مكان اتصلت به realloc وتغيير القوالب و sizeofس. أيضا ، إذا نسيت ، وقمت بذلك:

    double *array = (float *)malloc(10 * sizeof(float));
    

    على معظم المنصات ، array لن تكون الآن مجموعة من 5 عناصر فقط ، على افتراض أن المحاذاة لم يتم إيقافها ، ولا يشكو المترجم float * إلى double *. يعتبر البعض أن تحذير مشكلات التحويل البرمجية مفيدة ، لأنه يشير إلى خطوط غير صحيحة محتملة. ومع ذلك ، إذا تجنبنا sizeof(type) وتجنب الصب ، يمكننا أن نرى أن الخطوط متعود كن غير صحيح ، لذا فإن جذب الانتباه إلى المترجم هو إهدار الوقت الذي يمكن أن نستخدمه في البرنامج.

من صفحات الرجل:

إذا كان الحجم 0 ، فإن malloc () يعود إما فارغة ، أو قيمة مؤشر فريدة يمكن أن يتم تمريرها لاحقًا إلى Free ().

لذا ، أعتقد أن الجواب "نعم" :).

نعم ، تحتاج إلى استدعاء Free () مرة واحدة لإصدار كتلة الذاكرة. لا تحتاج إلى استدعاء مجاني لعمليات RealOcs () اللاحقة التي تقوم بها ، حتى لو كانت تلك تُرجع عناوين/مؤشر مختلف. يعلم مدير الذاكرة أن الكتلة القديمة ليست ضرورية بعد الآن وسوف تحرر ().

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

أيضا ، حيث تهيئة variable, ، يمكنك فقط ضبطه على NULL بدلا من الاتصال malloc; realloc سيعمل مثل malloc المرة الأولى.

ألقِ نظرة على بعض الإجابات التي قدمتها على سؤالين فيما يتعلق بإدارة الذاكرة:

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

أتمنى أن يساعد هذا ، مع أطيب التحيات ، توم.

int main(int argc, char *argv[])
{
        char *p = malloc(sizeof(argv[1]));

        p = argv[1];
        printf("%s\n", p);
        free(p);
        return 0;
}

أنا أحصل على خطأ GLIBC

hello
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x00007fff66be94c6 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x7eb96)[0x7f38dca1db96]
./a.out[0x4005ed]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xed)[0x7f38dc9c076d]
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top