چگونه مدیریت حافظه در C کار می کند؟

وقتی یک متغیر را با استفاده از یک نوع داده اساسی اعلام می کنید، کامپایلر C به طور خودکار فضای حافظه را برای متغیر در یک استخر حافظه به نامپشته اختصاص می دهد .

برای مثال، هنگامی که اعلام می شود، یک متغیر شناور معمولا 4 بایت (بر اساس پلتفرم) می گیرد. ما می توانیم این اطلاعات را با استفاده از اپراتورsizeof به عنوان مثال زیر نشان داده شود

 #include <stdio.h>
 int main () {float x؛  printf ("اندازه شناور٪ d بایت" است، sizeof (x))؛  بازگشت 0؛}

خروجی خواهد بود:

  اندازه شناور 4 بایت است

همچنین یک آرایه با اندازه مشخص شده در بلوک های متوالی از حافظه اختصاص داده می شود، هر بلوک دارای اندازه یک عنصر است:

 #include <stdio.h>
 int main () {شناور arr [10]؛
 printf ("اندازه آرایه شناور با 10 عنصر٪ d"، sizeof (arr))؛  بازگشت 0؛}

نتیجه این است:

  اندازه آرایه شناور با 10 عنصر 40 است

همانطور که تا کنون آموخته شده است، هنگام اعلام یک نوع داده اولیه یا یک آرایه، حافظه به طور خودکار مدیریت می شود. با این حال، یک روند برای تخصیص حافظه وجود دارد که به شما امکان اجرای برنامه ای را می دهد که در آن اندازه آرایه تا زمانی که برنامه شما اجرا نمی شود (زمان اجرا) تعیین نشده است. این فرایند ” تخصیص حافظه پویا ” نامیده می شود.

در این آموزش، شما یاد خواهید گرفت –

تخصیص حافظه پویا

تخصیص حافظه پویا جنبه تخصیص و آزاد سازی حافظه با توجه به نیازهای شما است. حافظه پویا اداره می شود و با اشاره گرها به فضای جدید ذخیره شده حافظه در یک منطقه اشاره می کند که ما آن را می نامیم. حالا شما می توانید بدون هیچ مشکلی یک آرایه از عناصر را در زمان اجرا ایجاد و نابود کنید.

به طور خلاصه، مدیریت حافظه خودکار از پشته استفاده می کند و تخصیص حافظه پویا از پشته استفاده می کند.

کتابخانه <stdlib.h> توابع مسئول مدیریت حافظه پویا است.

تابع هدف
malloc حافظه اندازه درخواست شده را اختصاص می دهد و اشارهگر را به اولین بایت فضای اختصاص داده می کند.
calloc فضای عناصر یک آرایه را اختصاص می دهد. عناصر را به صفر اولیه می کند و اشاره گر را به حافظه می رساند.
realloc این برای تغییر اندازه فضای حافظه پیشین استفاده شده است.
رایگان فضای حافظه قبلا اختصاص داده شده را آزاد یا خالی کنید.

بگذارید در مورد توابع فوق با کاربرد خود بحث کنیم

تابع malloc

تابع malloc () تخصیص حافظه است. این یک تابع است که برای تخصیص یک بلوک از حافظه به صورت پویا استفاده می شود.این فضای حافظه از اندازه مشخص شده را ذخیره می کند و نشانگر صفر را به نقطه حافظه نشان می دهد. نشانگر بازگشتی معمولا از نوع خالی است. این بدان معنی است که ما می توانیم تابع malloc را به هر اشاره گر اختصاص دهیم.

نحو

  ptr = (cast_type *) malloc (byte_size)؛

اینجا،

  • ptr یک نشانگر cast_type است.
  • تابع malloc اشاره گر را به حافظه اختصاص داده شده از byte_size می دهد.
  مثال: ptr = (int *) malloc (50)

هنگامی که این بیانیه با موفقیت اجرا می شود، یک فضای حافظه از 50 بایت ذخیره می شود. آدرس اولین بایت فضای رزرو شده به اشاره گر ptr از نوع int اختصاص می یابد.

مثال دیگر را در نظر بگیرید:

 #include <stdlib.h>
 int main () {
 int * ptr؛
 ptr = malloc (15 * sizeof (* ptr))؛  / * یک بلوک از 15 عدد صحیح * /
     اگر (ptr! = NULL) {
       * (ptr + 5) = 480؛  / * اختصاص 480 به ششم عدد صحیح * /
       printf ("مقدار عدد صحیح ششم،٪ d است"، * (ptr + 5))؛
     }
 }

خروجی:

  مقدار عدد صحیح 6 عدد 480 است

  1. توجه داشته باشید که sizeof (* ptr) به جای sizeof (int) به کار گرفته شد تا کد را قوی تر کند، زمانی که declaration * ptr برای نوع داده های متفاوتی تایپ شده باشد.
  2. اگر حافظه کافی نباشد، تخصیص ممکن است خراب شود. در این مورد، یک نشانگر NULL را نشان می دهد. بنابراین، شما باید کد را برای نشانگر NULL بررسی کنید.
  3. به یاد داشته باشید که حافظه اختصاص داده شده همسو است و می تواند به عنوان یک آرایه رفتار شود. ما می توانیم با استفاده از arithmetic pointer برای دسترسی به عناصر آرایه به جای استفاده از brackets [] استفاده کنیم. توصیه می کنیم از + برای ارجاع به عناصر آرایه استفاده کنید زیرا استفاده از increment ++ یا + = آدرس آدرس های ذخیره شده توسط اشاره گر را تغییر می دهد.

تابع Malloc همچنین می تواند با نوع داده کاراکتر و همچنین انواع داده های پیچیده مانند ساختارها مورد استفاده قرار گیرد.

عملکرد آزاد

حافظه برای متغیرها به طور خودکار در زمان کامپایل مجددا تخلیه می شود. در تخصیص حافظه پویا، شما باید به طور صریح به حافظه اختصاص دهید. اگر انجام نشود، ممکن است از خطای حافظه برخورد کنید.

تابع free () برای انتشار / حذف حافظه نامیده می شود. با آزاد کردن حافظه در برنامه خود، بعدا برای استفاده بیشتر استفاده کنید.

مثلا:

 #include <stdio.h>
 int main () {
 int * ptr = malloc (10 * sizeof (* ptr))؛
 اگر (ptr! = NULL) {
   * (ptr + 2) = 50؛
   printf ("مقدار 2 عدد صحیح٪ d است"، * (ptr + 2))؛
 }
 رایگان (ptr)؛
 }

خروجی

  مقدار عدد صحیح دوم 50 است

عملکرد calloc

عملکرد calloc مستلزم تخصیص مجدد است. این تابع برای اختصاص بلوک های چندگانه از حافظه استفاده می شود. این یک تابع تخصیص حافظه پویا است که برای تخصیص حافظه به ساختارهای پیچیده داده مانند آرایه ها و ساختارها استفاده می شود.

تابع Malloc برای تخصیص یک بلوک واحد از حافظه استفاده می شود در حالی که تابع calloc برای تخصیص چندین بلوک فضای حافظه استفاده می شود. هر بلوک اختصاص داده شده توسط تابع calloc از یک اندازه است.

نحو:

  ptr = (cast_type *) calloc (n، size)؛
  • بیانیه فوق برای اختصاص دادن حافظه های حافظه ی n همان اندازه استفاده می شود.
  • پس از اختصاص فضای حافظه، تمام بایت ها صفر می شوند.
  • نشانگر که در حال حاضر در اولین بایت حافظه اختصاص داده شده بازگشته است.

هر گاه تخصیص فضای حافظه مانند کمبود حافظه خطایی رخ می دهد، یک اشاره گر صفر بازگردانده می شود.

برنامه زیر محاسبه مجموع توالی محاسباتی را محاسبه می کند.

 #include <stdio.h>
     int main () {
         int i، * ptr، sum = 0؛
         ptr = calloc (10، sizeof (int))؛
         اگر (ptr == NULL) {
             printf ("Error! memory not allocated.")؛
             خروج (0)؛
         }
         printf ("ساخت و محاسبه مجموع توالی از 10 اصطلاح اول \ n")؛
         برای (i = 0؛ i <10؛ ++ i) {* (ptr + i) = i؛
             مجموع + = * (ptr + i)؛
         }
         printf ("مجموع =٪ d"، مجموع)؛
         رایگان (ptr)؛
         بازگشت 0؛
     }

نتیجه:

 
 ساخت و محاسبه مجموع توالی 10 اصطلاح اول
 مجموع = 45

calloc vs malloc: تفاوت های کلیدی

عملکرد calloc به طور کلی مناسب تر و کارآمد تر از عملکرد malloc است. در حالی که هر دو توابع برای اختصاص فضای حافظه استفاده می شود، Calloc می تواند چندین بلوک را در یک زمان اختصاص دهد. شما مجبور نیستید هربار که خواستید یک بلوک حافظه داشته باشید. تابع calloc در ساختارهای اطلاعات پیچیده که نیاز به فضای حافظه بیشتر دارد استفاده می شود.

بلوک حافظه اختصاص داده شده توسط یک تابع calloc همیشه به صفر مقداردهی می شود در حالی که در malloc همیشه حاوی مقدار زباله است.

تابع realloc

با استفاده از تابع realloc () می توانید حافظه بیشتری را به حافظه اختصاص داده شده اضافه کنید. بلوک فعلی را گسترش می دهد و محتوی اصلی را همانطور که هست را ترک می کند. realloc مخفف مجدد حافظه است.

realloc همچنین می تواند برای کاهش حجم حافظه قبلا اختصاص داده شود.

نحو

  ptr = realloc (ptr، newsize)؛

بیانیه فوق یک فضای حافظه جدید را با یک اندازه مشخص در متغیر newsize اختصاص می دهد. بعد از اجرای تابع، اشارهگر به اولین بایت بلوک حافظه بازگردانده می شود. اندازه جدید می تواند بزرگتر یا کوچکتر از حافظه قبلی باشد. ما نمی توانیم مطمئن باشیم که اگر بلوک جدید اختصاص داده شده به همان محل همان بلوک حافظه قبلی اشاره شود. این تابع تمام داده های قبلی را در منطقه جدید کپی می کند. این اطمینان حاصل می کند که داده ها امن می شوند.

مثلا:

 #include <stdio.h>
 int main () {
    کاراکتر * ptr؛
    ptr = (char *) malloc (10)؛
    strcpy (ptr، "برنامه نویسی")؛
    printf ("٪ s، آدرس =٪ u \ n"، ptr، ptr)؛

    ptr = (char *) realloc (ptr، 20)؛  // ptr با اندازه جدید مجددا تعیین می شود
    strcat (ptr، "در" C ")؛
    printf ("٪ s، آدرس =٪ u \ n"، ptr، ptr)؛
    رایگان (ptr)؛
    بازگشت 0؛
 }

هر بار که realloc به یک عملیات ناموفق منجر می شود، یک نشانگر خالی را نشان می دهد و اطلاعات قبلی نیز آزاد می شود.