هل تخصيص الذاكرة تلقائيا بالنسبة لي ؟

StackOverflow https://stackoverflow.com/questions/604104

  •  03-07-2019
  •  | 
  •  

سؤال

لقد تم كتابة C فقط قلة قليلة أسابيع و لم تتخذ في الوقت للقلق نفسي كثيرا عن malloc().في الآونة الأخيرة, على الرغم من, برنامج لي عاد سلسلة من الوجوه السعيدة بدلا من قيم true/false كان متوقعا لها.

إن إنشاء البنية مثل هذا:

typedef struct Cell {
  struct Cell* subcells;
} 

ثم في وقت لاحق تهيئة مثل هذا

Cell makeCell(int dim) {
  Cell newCell;

  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim -1);
  }

  return newCell; //ha ha ha, this is here in my program don't worry!
}

أنا ذاهب إلى نهاية المطاف الوصول إلى وجوه سعيدة تخزينها في الذاكرة في مكان ما, أو ربما الكتابة فوق الخلايا الموجودة سابقا أم ماذا ؟ سؤالي هو كيف ج تخصيص الذاكرة عندما كنت في الواقع لم malloc()إد كمية مناسبة من الذاكرة ؟ ما هو الافتراضي ؟

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

المحلول

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

newCell.subcells[i] = ...

فعال يصل بعض مؤكدة جزء من الذاكرة.تذكر أن subcells[i] ما يعادل

*(newCell.subcells + i)

إذا كان الجانب الأيسر يحتوي على بعض القمامة ، إضافة i أن قيمة القمامة و الوصول إلى الذاكرة في ذلك غير مؤكد الموقع.كما قلتم, سيكون لديك إلى تهيئة المؤشر للإشارة إلى بعض سارية منطقة الذاكرة:

newCell.subcells = malloc(bytecount)

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

  • malloc عودة المؤشر إلى كائن مع أي نوع.يمكنك ان تجعل مؤشر يشير إلى هذه المنطقة من الذاكرة ، ونوع الكائن ستصبح بالفعل نوع إلى نوع الكائن.الذاكرة لم يتم تهيئة إلى أي قيمة والوصول عادة أبطأ.الكائنات التي تم الحصول عليها حتى تسمى allocated objects.
  • يمكنك وضع الكائنات على الصعيد العالمي.الذاكرة سيتم تهيئة إلى الصفر.للحصول على نقاط ، سوف تحصل على مؤشرات فارغة ، يطفو سوف تحصل على السليم صفر أيضا.يمكنك الاعتماد على الصحيح القيمة الأولية.
  • إذا كان لديك المتغيرات المحلية ولكن استخدام static فئة تخزين محدد, ثم سيكون لديك نفس القيمة الأولية القاعدة العالمي الكائنات.الذاكرة عادة ما يتم تخصيص بنفس الطريقة مثل كائنات عمومية ، ولكن هذا لا ضرورة.
  • إذا كان لديك المتغيرات المحلية دون أي فئة تخزين محدد أو مع auto, ثم متغير سيتم تخصيص على المكدس (على الرغم من لا يعرف ذلك من خلال C, هذا ما المجمعين لا عمليا بالطبع).يمكنك أن تأخذ عنوانه في هذه الحالة فإن المترجم قد حذف التحسينات مثل وضعه في سجلات بالطبع.
  • المتغيرات المحلية استخدامها مع فئة تخزين محدد register, هي علامة وجود تخزين خاصة.ونتيجة لذلك, لا يمكنك أن تأخذ عنوانه بعد.في الآونة الأخيرة المجمعين ، هناك عادة لا حاجة لاستخدام register بعد متطورة أبتيميزر.إذا كنت حقا الخبراء ، ثم قد تحصل على بعض الأداء من أنه إذا كان استخدام ذلك.

الكائنات المرتبطة التخزين لفترات التي يمكن استخدامها لإظهار مختلفة تهيئة القواعد (رسميا, إلا أنها تحدد كم من الوقت على الأقل الكائنات الحية).أعلن الكائنات مع auto و register يكون التخزين التلقائي المدة لا تهيئة.عليك صراحة تهيئة لهم إذا كنت تريد لها أن تحتوي على بعض القيمة.إذا كنت لا, أنها سوف تحتوي على كل ما المترجم اليسرى على المكدس قبل بدأ مدى الحياة.الكائنات التي يتم تخصيصها من قبل malloc (أو وظيفة أخرى من تلك العائلة ، مثل calloc) خصصت مدة التخزين.التخزين هو لا تهيئة سواء.ويستثنى من ذلك عند استخدام calloc, في هذه الحالة فإن الذاكرة هي تهيئة صفر ("الحقيقي" الصفر.أنا.e جميع بايت 0x00, دون النظر إلى أي مؤشر فارغة التمثيل).الكائنات التي أعلنت مع static و المتغيرات العالمية قد ساكنة مدة التخزين.التخزين هو تهيئة صفر المناسب لكل منها نوع.علما أن الجسم لا يجب أن يكون نوع ، ولكن الطريقة الوحيدة للحصول على نوع أقل الكائن باستخدام التخزين المخصصة.(كائن في ج هو "منطقة التخزين").

فما هو ماذا ؟ هنا هو رمز ثابت.لأنه بمجرد تخصيص كتلة من الذاكرة لا يمكن أن تحصل مرة أخرى بعد الآن كم عدد العناصر التي يمكنك تخصيص أفضل دائما المخزن الذي عد في مكان ما.لقد قدم variale dim إلى البنية التي تحصل على الاعتماد المخزنة.

Cell makeCell(int dim) {
  /* automatic storage duration => need to init manually */
  Cell newCell;

  /* note that in case dim is zero, we can either get NULL or a 
   * unique non-null value back from malloc. This depends on the
   * implementation. */
  newCell.subcells = malloc(dim * sizeof(*newCell.subcells));
  newCell.dim = dim;

  /* the following can be used as a check for an out-of-memory 
   * situation:
   * if(newCell.subcells == NULL && dim > 0) ... */
  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim - 1);
  }

  return newCell;
}

الآن الأمور تبدو مثل هذا خافت=2:

Cell { 
  subcells => { 
    Cell { 
      subcells => { 
        Cell { subcells => {}, dim = 0 }
      }, 
      dim = 1
    },
    Cell { 
      subcells => { 
        Cell { subcells => {}, dim = 0 }
      }, 
      dim = 1
    }
  },
  dim = 2
}

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

makeCells(0).dim++

سوف تحتاج إلى "وظيفة خالية" أن الحرة المخصصة الذاكرة مرة أخرى.لأن تخزين الأشياء المخصصة لم يتم تحرير تلقائيا.عليك الاتصال free إلى أن ذاكرة كل subcells المؤشر في شجرة الخاص بك.إنه ترك تمرين لكتابة هذا :)

نصائح أخرى

الجواب القصير: ليس المخصصة لك.

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

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

على newCell متغير في الدالة التلقائي, و لم يتم تهيئة.يجب إصلاح هذا برونتو.إما إعطاء newCell.subcells معنى القيمة فورا ، أو في NULL حتى يمكنك تخصيص بعض المساحات.وبهذه الطريقة سوف رمي تجزئة انتهاك إذا كنت تحاول إلغاء مرجعية قبل تخصيص بعض الذاكرة عن ذلك.

والأسوأ من ذلك أنك العودة Cell من حيث القيمة ، ولكن تعيين Cell * عند محاولة ملء subcells الصفيف.إما عودة مؤشر إلى كومة تخصيص كائن أو تعيين القيمة إلى محليا تخصيص الكائن.

المعتاد المصطلح هذا من شأنه أن يكون على شكل شيء مثل

Cell* makeCell(dim){
  Cell *newCell = malloc(sizeof(Cell));
  // error checking here
  newCell->subcells = malloc(sizeof(Cell*)*dim); // what if dim=0?
  // more error checking
  for (int i=0; i<dim; ++i){
    newCell->subCells[i] = makeCell(dim-1);
    // what error checking do you need here? 
    // depends on your other error checking...
  }
  return newCell;
}

على الرغم من أنني قد تركت لك بعض المشاكل للتوصل الى..

مع ملاحظة أن عليك أن تتبع كل بت من الذاكرة التي سوف تحتاج في نهاية المطاف إلى deallocated...

وأي شئ غير المخصصة على كومة (عبر malloc ودعوات مماثلة) يتم تخصيص على المكدس، بدلا من ذلك. وبسبب ذلك، سيتم تدمير أي شيء إنشاؤها في وظيفة معينة دون أن malloc'd عندما تنتهي المهمة. التي تتضمن كائنات عادت. عندما يتم المساس بها كومة بعد استدعاء دالة يتم نسخ الكائن عاد إلى مساحة المخصصة لذلك على المكدس بواسطة الدالة المتصل.

<القوي> تحذير: إذا كنت ترغب في عودة كائن له مؤشرات على كائنات أخرى في ذلك، تأكد من أن الكائنات أشارت إلى يتم إنشاؤها على كومة، والأفضل من ذلك، خلق هذا الكائن على كومة، أيضا، إلا إذا ليس الغرض منه البقاء على قيد الحياة وظيفة التي يتم إنشاؤه.

<اقتباس فقرة>   

وسؤالي هو، كيف C تخصيص الذاكرة عندما يكون لدي لم يكن في الواقع malloc () إد كمية مناسبة من الذاكرة؟ ما هو الافتراضي؟

للا تخصيص الذاكرة. لديك لإنشاء صراحة على كومة أو حيوي.

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

<اقتباس فقرة>   

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

وأنت محظوظ أنك حصلت على وجه سعيد. على واحدة من تلك الأيام سيئ الحظ، فإنه يمكن لقد مسحت النظام الخاص بك نظيفة.)

<اقتباس فقرة>   

وسؤالي هو، كيف C تخصيص الذاكرة عندما يكون لدي لم يكن في الواقع malloc () إد كمية مناسبة من الذاكرة؟

وولا. ومع ذلك، ما يحدث هو عند تعريف لك سيل newCell، تتم تهيئة مؤشر subCells إلى قيمة القمامة. والذي قد يكون 0 (في هذه الحالة كنت الحصول على العطل) أو بعض صحيحا كبيرة بما يكفي لجعلها تبدو وكأنها عنوان الذاكرة الفعلية. المترجم، في مثل هذه الحالات، سوف تجلب بسعادة أي قيمة المقيمين هناك واعادتها لك.

<اقتباس فقرة>   

ما هو الافتراضي؟

وهذا هو في السلوك إذا لم يكن لتهيئة المتغيرات الخاصة بك. وتبدو وظيفة makeCell الخاص بك قليلا المتخلفة.

وهناك في الحقيقة ثلاثة أقسام حيث يمكن تخصيص الأشياء - البيانات، كومة كومة و

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

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

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

والمتغيرات المحلية و"تخصيص" على المكدس. المكدس كمية preallocated من الذاكرة لعقد تلك المتغيرات المحلية. المتغيرات تتوقف لتكون صالحة عندما سيتم الكتابة فوق إنهاء الدالة وكل ما يأتي المقبل.

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

سأتظاهر أنني الكمبيوتر هنا, قراءة هذا الرمز...

typedef struct Cell {
  struct Cell* subcells;
}

هذا يقول لي:

  • لدينا البنية نوع يسمى خلية
  • أنه يحتوي على مؤشر يسمى subcells
  • المؤشر يجب أن يكون شيئا من نوع struct الخليوي

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

Cell makeCell(int dim) {
  Cell newCell;

الخلايا الجديدة البنية, مع غير معروف subcells المؤشر.كل هذا لا يتم حجز القليل جزء من الذاكرة يسمى newCell هذا هو حجم الخلية البنية.لا تغيير القيم التي كانت في تلك الذاكرة - أنها يمكن أن تكون أي شيء.

  for(int i = 0; i < dim; i++) {
    newCell.subcells[i] = makeCell(dim -1);

من أجل الحصول على newCell.subcells[أنا] ، حساب تعويض من subcells من أنا, ثم وهذا هو dereferenced.على وجه التحديد, هذا يعني القيمة التي يتم سحبها من أن عنوان الذاكرة.خذ على سبيل المثال, i==0...ثم نود أن يكون dereferencing على subcells مؤشر نفسها (لا تعوض).منذ subcells هو غير معروف يمكن أن تكون أي شيء.حرفيا أي شيء!لذلك هذا من شأنه أن تسأل عن قيمة من مكان عشوائي تماما في الذاكرة.لا يوجد أي ضمان من أي شيء مع النتيجة.قد طباعة شيء قد تحطم.بالتأكيد لا ينبغي القيام به.

  }

  return newCell;
}

في أي وقت يمكنك العمل مع المؤشر ، من المهم للتأكد من تعيين قيمة قبل إلغاء مرجعية ذلك.على المترجم أن أعطيك أي تحذيرات يمكن أن العديد من حديث المجمعين يمكن التقاط هذا النوع من الشيء.يمكنك أيضا إعطاء مؤشرات رائع القيم الافتراضية مثل 0xdeadbeef (نعم!هذا هو عدد عشري, إنها أيضا كلمة ، بحيث يبدو مضحكا) بحيث تبرز.(من %p خيار printf مفيد لعرض المؤشرات ، كما شكل خام من التصحيح.المصحح البرامج أيضا يمكن أن تظهر لهم بشكل جيد جدا.)

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