يبدو أن Malloc داخل استدعاء دالة يتم تحريره عند العودة؟

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

  •  01-07-2019
  •  | 
  •  

سؤال

أعتقد أنني قد وصلت إلى الحالة الأساسية:

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * arr) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

الإخراج هو هذا:

> ./a.out 
 car[3]=-1869558540
 a.out(4100) malloc: *** error for object 0x8fe01037: Non-aligned pointer
                         being freed
 *** set a breakpoint in malloc_error_break to debug
>

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

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

المحلول

يمكنك تمرير المؤشر حسب القيمة، وليس حسب المرجع، لذا فإن أي شيء تفعله باستخدام arr داخل foo لن يحدث فرقًا خارج الدالة foo.كما كتب m_pGladiator إحدى الطرق هي الإعلان عن إشارة إلى مؤشر مثل هذا (ممكن فقط في C++ راجع للشغل.C لا يعرف عن المراجع):

int main(int argc, char ** argv) {
  int * arr;

  foo(arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int * &arr ) {
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
}

هناك طريقة أخرى (أفضل imho) وهي عدم تمرير المؤشر كوسيطة ولكن إرجاع المؤشر:

int main(int argc, char ** argv) {
  int * arr;

  arr = foo();
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

int * foo(void ) {
  int * arr;
  arr = (int*) malloc( sizeof(int)*25 );
  arr[3] = 69;
  return arr;
}

ويمكنك تمرير مؤشر إلى مؤشر.هذه هي طريقة C لتمرير المرجع.يعقد بناء الجملة قليلاً ولكن جيدًا - هكذا تكون لغة C...

int main(int argc, char ** argv) {
  int * arr;

  foo(&arr);
  printf("car[3]=%d\n",arr[3]);
  free (arr);
  return 1;
}

void foo(int ** arr ) {
  (*arr) = (int*) malloc( sizeof(int)*25 );
  (*arr)[3] = 69;
}

نصائح أخرى

لقد قمت بتخصيص arr في foo، ولكن يتم تخزين قيمة المؤشرات في مكدس الاستدعاءات.إذا كنت ترغب في القيام بذلك، فافعل ذلك على النحو التالي:

void foo( int ** arr) {
    *arr = (int *)malloc( sizeof(int) * 25 );
    (*arr)[3] = 69;
}

وبشكل رئيسي، ما عليك سوى تمرير المؤشر إلى foo (مثل foo(&arr))

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

إحدى الطرق لإصلاح ذلك هي الحصول على foo لإرجاع المؤشر:

int * foo() {
  return (int*) malloc( sizeof(int)*25 );
}

int main() {
    int* arr = foo();
}

آخر هو تمرير foo مؤشر إلى مؤشر

void foo(int ** arr) {
   *arr = malloc(...);
}

int main() {
    foo(&arr);
}

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

void foo(int * & arr)

نظرًا لأنك تقوم بتمرير المؤشر حسب القيمة، فإن مؤشر arr داخل main لا يشير إلى الذاكرة المخصصة.وهذا يعني أمرين:لقد حصلت على تسرب للذاكرة (لا، لم يتم تحرير الذاكرة بعد اكتمال الوظيفة foo)، وعندما تصل إلى مؤشر arr داخل main، فإنك تصل إلى نطاق عشوائي من الذاكرة، وبالتالي لا تحصل على 3 مطبوعة out وبالتالي يرفض free() العمل.أنت محظوظ لأنك لم تحصل على خطأ تجزئة عند الوصول إلى arr[3] داخل main.

لا يمكنك تغيير قيمة الوسيطة (arr) إذا لم يتم تمريرها حسب المرجع (&).بشكل عام، قد ترغب في إرجاع المؤشر، لذا يجب أن تكون طريقتك كما يلي:

arr=foo();

من السيئ محاولة إعادة تعيين الحجج؛لا أوصي بالحل (&).

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