سؤال

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

شكرًا لك.

 char **stringArr;
 int size=4, i;

 stringArr=(char**)malloc(size*sizeof(char*));
 for (i=0; i<size; i++)
    stringArr[i]=(char*)malloc(10*sizeof(char));

 strcpy(stringArr[0], "abcdefgh");
 strcpy(stringArr[1], "good-luck");
 strcpy(stringArr[2], "mully");
 strcpy(stringArr[3], "stam");

 for (i=0; i<size; i++) {
  printf("%s\n", stringArr[i]);
  printf("%d  %u\n\n", &(stringArr[i]), stringArr[i]);
 }

انتاج:

ABCDEFGH 9650064 9650128

لحسن الحظ 9650068 9638624

Mully 9650072 9638680

Stam 9650076 9638736

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

المحلول

عادة عندما تطلب الذاكرة من خلال malloc(), ، ستقوم مكتبة وقت التشغيل C بتدوير حجم طلبك حتى بعض الحد الأدنى من حجم التخصيص. هذا يضمن أن:

  • تحتوي مكتبة وقت التشغيل على مساحة لمعلومات مسك الدفاتر
  • من أكثر كفاءة بالنسبة لمكتبة وقت التشغيل لإدارة الكتل المخصصة التي جميعها مضاعفات من بعض الحجم (مثل 16 بايت)

ومع ذلك ، فهذه تفاصيل التنفيذ ولا يمكنك الاعتماد حقًا على أي سلوك معين malloc().

نصائح أخرى

لكن عندما أقوم بطباعة العناوين ، لا يبدو أنها مخصصة واحدة تلو الأخرى ...

لذا؟

هل أفعل شيئًا خاطئًا أم أنه نوع من آلية الدفاع التي ينفذها نظام التشغيل لمنع تدفقات المخزن المؤقت الممكنة؟

ربما "لا".

فقط بدافع الاهتمام ، ما هي العناوين التي تحصل عليها؟

يجب ألا تعتمد على أي طلب معين أو تباعد للقيم التي يتم إرجاعها بواسطة Malloc. يتصرف بطرق غامضة ولا يمكن التنبؤ بها.

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

لا يمكنك الاعتماد على malloc لمنحك عناوين متجاورة. الأمر متروك تمامًا للتنفيذ ويفترض أن الوضع الحالي للكومة ؛ بعض التطبيقات قد ، كثيرون لن يفعلوا ذلك.

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

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

ولكن حتى لو تصادف أن الكتل واحدة تلو الأخرى ، فمن المحتمل ألا تشكل كتلة متجاورة. من أجل تقليل التفتت ، يخصص مدير الكومة فقط كتل ذات حجم محدد ، على سبيل المثال طاقة اثنين (64 ، 128 ، 256 ، 512 إلخ). لذلك ، إذا كنت تحجز 10 بايت لسلسلة ، فقد يكون هناك 22 أو 54 بايت غير مستخدم بعد ذلك.

تعد النفقات العامة للذاكرة سببًا آخر لأنه ليس من الجيد استخدام تخصيص الذاكرة الديناميكية ما لم يكن ذلك ضروريًا. إنه أسهل بكثير وأكثر أمانًا فقط لاستخدام صفيف ثابت.

بما أنك مثير للاهتمام في معرفة العناوين التي تم إرجاعها بواسطة malloc(), ، يجب عليك التأكد من أنك تطبعها بشكل صحيح. من خلال "بشكل صحيح" ، أعني أنه يجب عليك استخدام محدد التنسيق المناسب ل printf() لطباعة العناوين. لماذا تستخدم "%u" لواحد و "%d" لآخر؟

يجب أن تستخدم "%p" لطباعة المؤشرات. هذه أيضًا واحدة من الحالات النادرة التي تحتاج فيها إلى فريق C في ج: لأن printf() هي وظيفة متنوعة ، لا يمكن للمترجم معرفة أن المؤشرات التي تمر بها كوسيطة لها يجب أن تكون من النوع void * أم لا.

أيضا ، يجب ألا يلقي قيمة الإرجاع malloc().

بعد إصلاح ما سبق ، البرنامج هو:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
    char **stringArr;
    int size=4, i;

    stringArr = malloc(size * sizeof *stringArr);

    for (i=0; i < size; i++)
        stringArr[i] = malloc(10 * sizeof *stringArr[i]);

    strcpy(stringArr[0], "abcdefgh");
    strcpy(stringArr[1], "good-luck");
    strcpy(stringArr[2], "mully");
    strcpy(stringArr[3], "stam");

    for (i=0; i<size; i++) {
        printf("%s\n", stringArr[i]);
        printf("%p %p\n", (void *)(&stringArr[i]), (void *)(stringArr[i]));
    }
    return 0;
}

وأحصل على الإخراج التالي عندما أقوم بتشغيله:

abcdefgh
0x100100080 0x1001000a0
good-luck
0x100100088 0x1001000b0
mully
0x100100090 0x1001000c0
stam
0x100100098 0x1001000d0

على حاسوبي، char ** المؤشرات طولها 8 بايت ، لذلك &stringArr[i+1] هو في 8 بايت أكبر من &stringArr[i]. هذا مضمون حسب المعيار: إذا كنت malloc() بعض المساحة ، تلك المساحة متجاورة. قمت بتخصيص مساحة لأربعة مؤشرات ، وعناوين هذه المؤشرات الأربعة بجوار بعضها البعض. يمكنك أن ترى ذلك بشكل أكثر وضوحًا من خلال العمل:

printf("%d\n", (int)(&stringArr[1] - &stringArr[0]));

هذا يجب أن يطبع 1.

حول اللاحقة malloc()S ، منذ كل stringArr[i] تم الحصول عليها من منفصلة malloc(), ، التنفيذ مجاني لتعيين أي عناوين مناسبة لهم. في تنفيذي ، مع هذا التشغيل بالذات ، تكون العناوين كلها بايت 0x10.

لتنفيذك ، يبدو الأمر كذلك char ** المؤشرات طويلة 4 بايت.

حول عناوين السلسلة الفردية الخاصة بك ، يبدو الأمر كذلك malloc() يفعل نوعا من التوزيع العشوائي (والذي يُسمح له بذلك).

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