سؤال

int main()
{
   char myString = NULL;
   realloc(&myString, 5);
   strncpy((char *)&myString, "test", 5);
}

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


تحرير:شكرا على الردود, لذا أفترض هذا هو غير قانونية على قدم المساواة

//I want the code to change myString to "tests"
char myString[5] = "test";
realloc(&myString, strlen(myString)+2);
myString[4] = 's';
myString[5] = '\0';
هل كانت مفيدة؟

المحلول

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

char *myString = malloc(x);
myString = realloc(myString,y);
free(myString)

وأنت أفضل حالا باستخدام جديدة وحذف، وحتى أفضل حالا باستخدام الأمراض المنقولة جنسيا :: سلسلة، ولكن.

نصائح أخرى

بعض المشاكل مع الكود الذي نشر:

  • نعم تحتاج إلى تحرير كل تخصص مع malloc ، realloc الأخرى ذات الصلة C أسلوب تخصيص الذاكرة وظائف.
  • أعتقد أنك قصدت أن يكون شار *myString ليس شار.ويمر في عنوان شيئا على المكدس (الخاص بك شار) هو خاطئ تماما.
  • تحتاج إلى تهيئة هاتفك myString شار المؤشر فارغة قبل استخدامه في realloc.
  • يجب أن يمر من 4 إلى strncpy لا 5, إذا كان لديك أكبر سلسلة ستكون الكتابة الذاكرة.
  • يجب أن يتم تحرير المخزن المؤقت الذي قمت بإنشائه في المثال الخاص بك
  • يجب أن يتم التحقق من قيمة الإرجاع الخاصة بك realloc الاتصال.realloc()

[فيما يتعلق realloc قيمة الإرجاع:] عند الانتهاء بنجاح مع حجم لا يساوي 0 ، realloc() بإرجاع مؤشر (ربما انتقلت) المساحة المخصصة.إذا كان حجم هو 0 ، إما مؤشر فارغة أو فريدة من نوعها المؤشر التي يمكن أن اجتاز بنجاح حر() هو عاد.إذا لم يكن هناك ما يكفي من الذاكرة المتاحة ، realloc() بإرجاع null pointer و مجموعات errno إلى [ENOMEM].

  • إعادة الوك سوف تعمل مثل malloc عند تمرير NULL:

إذا ptr هو مؤشر null, realloc() يتصرف مثل malloc() عن الحجم المحدد.

أكثر C++ طريقة للقيام بذلك:

أنت معلم هذا مثل C++ على الرغم من أنها أكثر من نوع من الآمن استخدام C++'s المشغل الجديد.على الرغم من أن المشغل الجديد لا يسمح إعادة مخصصات أنه سوف يعمل على مخصصات إعادة استخدام القائمة مخازن (وضع جديد).

char *myString = new char[5];
strncpy(myString, "test", 4); 
//...
delete[] myString;

أو حتى:

#include <string>

//...

std::string str = "test";

المصدر من أعلى 2 يقتبس

وهذا يجب أن لا تعمل. كنت reallocing شيء لم يكن malloced في المقام الأول. ولا، انها لن تحصل على اطلاق سراح عندما يخرج من نطاق - عند استخدام malloc أو realloc، كل شيء متروك لكم

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

char* ptr = malloc(4);
ptr = realloc(ptr, 5);

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

وهذا أمر خطير! هذه الإرادة الفاسدين الكدسة. لو كنت لrealloc شيء على كومة من دالة ثم عاد إلى الرئيسية ()، وكنت فعلا في نهاية المطاف الكتابة فوق إطار مكدس والعودة في مكان آخر غير الرئيسية (). THIS IS A SECURITY هول محتملة.

وحاول تشغيل التالية. في حالة تعطله على realloc، كنت حصلت على الحظ. يمكنك القيام به أضرار جسيمة مع شيء من هذا القبيل memcpy (& myString).

int dostuff();

int main()
{
        dostuff();
        return 0;
}

int dostuff()
{
        char myString = NULL;
        realloc(&myString, 5);
        strncpy((char *)&myString, "test", 5);
        return 0;
}

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

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

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

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

إذا تم تمرير عنوان متغير محلي إلى realloc ()، فإنه قد يحاول تحرير الذاكرة وتحيله مكان آخر. منذ العنوان ليس من كومة، وrealloc () تعمل على كومة، هذا ستفشل. معظم realloc المرجح () سيتم الكشف عن عنوان ليست من كومة وإحباط البرنامج.


وبصرف النظر عن ذلك، فإن البرنامج المثال يحتوي على بعض الأخطاء المنطقية.


char myString = NULL;

وتقوم بتعريف متغير لعقد شار، وليس سلسلة. سلسلة الطراز C ديها نوع char*، أي مؤشر إلى شار.

وNULL أيضا، يتم تعيين شار، الصفر عنوان الذي تم تعيينه تقليديا إلى مؤشرات غير صالحة. هذا يجمع لأن المعالج يحل محل NULL من قبل 0 الحرفي. حقا، قمت بتخزين بايت صفر في شار، الذي هو، أيضا اتفاقية، وفاصل من سلسلة الطراز C.


realloc(&myString, 5);

وكما ذكر أعلاه، هذا غير قانوني لأنك تمرير عنوان كائن كومة إلى كومة مخصص. تبقى هذه المشكلة في المثال رمز الثاني.

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


strncpy((char *)&myString, "test", 5);

وهذا هو الصحيح، ولكن المدلى بها لا لزوم لها.


وهنا هو نسخة الأصح من البرنامج:


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

int main()
{
   /* allocate space for, say, one character + terminator */
   char* myString = (char*) malloc(2);

   /* some code using myString omitted */

   /* get more space */
   myString = (char*) realloc(myString, 5);

   /* write to the string */
   strncpy(myString, "test", 5);

   /* free the memory */
   free(myString);

   return 0;
}

في C ++، فمن الأفضل لتجنب realloc () تماما. على سبيل المثال، يمكنك استخدام شيء كما يلي:


#include <string>

int main()
{
   std::string myString;

   /* some code using myString */

   myString = "test";

   return 0;
}

وليس لديك لmyString مجانا لأنه على المكدس (الذي يحصل على "الافراج" عندما يترك مجالا).

وrealloc غير قانوني هنا، عنوان لابد من NULL أو عنوان إرجاعها بواسطة مكالمة سابقة إلى realloc، malloc أو calloc.

وكل المتغير الذي يعلن على المكدس، حتى مؤشر:

وكثافة العمليات * س؛

ووx متغير على كومة! ومن نوع pointer ويحمل عنوان.

س = (عدد صحيح *) malloc (sizeof (الباحث))؛

وبتعيين عنوان إرجاعها بواسطة malloc إلى x متغير! محتوى x هو عنوان الذاكرة!

والمشكلة مع ما تفعلونه هو أنك التلويث مع شيء غير متغير. قمت بتعريفه myString كما شار، وبالتالي تحاول تغيير عنوانه. وهذا أمر سيئ.

لا يفترض realloc () وظيفة لتغيير أي شيء مرت فيه. فإنه يأخذ مؤشر إلى بعض الذاكرة على كومة (أو مؤشر فارغة، وإذا كان هو تخصيص شيء بالفعل) وإرجاع مؤشر إلى بعض الذاكرة على الكومة.

لذلك، توفر إما مؤشر فارغة أو مؤشر لشيء خصصتها malloc () أو realloc () أو calloc ()، وتخزين عاد المؤشر.

وشيء من هذا القبيل

char * myString = NULL;
myString = realloc(myString, 5);

والعمل، ولكن سوف تحتاج إلى تحرير () myString.

في C ++، ومع ذلك، استخدم الأمراض المنقولة جنسيا :: سلسلة.

وردا على رمز المثال الثاني:

نعم، وهذا هو أيضا غير قانوني. لم يتم تخصيص myString مع malloc (أو calloc)، لذلك لا يمكن تخصيصها مع realloc، أو إطلاق سراح مع مجانا.

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

myString = realloc(myString, strlen(myString)+2);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top