برنامه نویسی

درک تخصیص حافظه در C

بررسی اجمالی،
هدف این مقاله ارائه یک نمای کلی واضح و مختصر از تخصیص حافظه در زبان برنامه نویسی C با استفاده از توابع malloc، calloc و realloc است. مدیریت حافظه یک جنبه حیاتی برنامه نویسی است و دانستن نحوه تخصیص و مدیریت حافظه در C برای نوشتن برنامه های کارآمد و موثر ضروری است.

سلب مسئولیت
نمودار تخصیص حافظه با جزئیات مورد بحث قرار نخواهد گرفت زیرا توابع مورد بحث در درجه اول بر تخصیص حافظه پویا متمرکز خواهند بود.

تخصیص حافظه

نمودار تخصیص حافظه

در C تخصیص حافظه می تواند به صورت استاتیک، خودکار یا پویا انجام شود. حافظه مورد بحث حافظه دسترسی تصادفی (RAM) است.

حافظه استاتیک حافظه ای است که در زمان کامپایل تخصیص داده می شود. کامپایلر با اختصاص مقدار ثابتی حافظه به یک متغیر یا ساختار داده، حافظه را تخصیص می دهد. توجه به این نکته ضروری است که حافظه در طول عمر برنامه ثابت می ماند، به این معنی که در طول زمان اجرا افزایش یا کاهش نمی یابد. حافظه استاتیک در بخش داده (همچنین به عنوان بخش bss شناخته می شود) ذخیره می شود. بخش داده شامل تمام متغیرهای استاتیک و سراسری اولیه است. بخش bss متغیرهای استاتیک و سراسری اولیه را ذخیره می کند. برخی از اشکالات حافظه استاتیک به شرح زیر است:

  • اگر کاربر مقادیری را در آرایه ای تعریف کند که اندازه آن کمتر از اندازه تعیین شده باشد، حافظه هدر می رود.

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

نمونه کد برای حافظه تخصیص یافته استاتیکی

{
    int arr[4] = { 2, 4, 6, 8}; 
     /*Here the allocated memory 4 is fixed */
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

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

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

با استفاده از Malloc

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

  • فقط حافظه رایگانی که توسط malloc اختصاص داده شده است.
  • همیشه حافظه رایگان اختصاص داده شده توسط malloc.
  • یک بلوک حافظه را بیش از یک بار آزاد نکنید.

نحو
ptr = (cast-type*) malloc(n * sizeof(type));
جایی که:

  • prt یک اشاره گر از نوع cast-type است
  • n تعداد عناصری است که می خواهید ذخیره کنید
  • نوع، نوع داده عناصر است
  • عملگر sizeof برای تعیین اندازه نوع داده استفاده می شود
  • cast-type برای ریختن بلوک حافظه اختصاص داده شده به نوع داده مناسب استفاده می شود.

هنگام استفاده از malloc، تایپ کست می تواند منجر به خطا شود. اطلاعات بیشتر را می توانید در اینجا بیابید: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc

نمونه کد برای تخصیص حافظه برای 5 عدد صحیح

int main()
{
    int *ptr;
    ptr = (int*) malloc(5 * sizeof(int));
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

همون کد بدون typecast

int main()
{
    int *ptr;
    ptr = malloc(5 * sizeof(int));
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

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

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

نحو
free(var_name);

نمونه کد

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


/**
 * Write a program that dynamically allocates an array of integers
 * of size n and initializes each element to its index value
*/


int main()
{
    int *arr;
    int i, n;


    n = 8; /*set the value of n*/


    arr = malloc(n * sizeof(arr + 1));


    for (i = 0; i < n; i++)
    {
        arr[i] = i; /*initialize each element to its index value*/
        printf("%d", arr[i]);
    }


    free(arr); //free the dynamically allocated memory
    return (0);
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

The output is 
01234567
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

نمونه کد دو

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


/**
 * Write a program that dynamically allocates a 2D array (matrix) of
 * size n x m and initializes each element to its product of
 * row and column index values.
*/


int main() {
    int n, m, i, j, **arr;

    /*get column and row number from user*/
    printf("Enter the number of rows: ");
    scanf("%d", &n);
    printf("Enter the number of columns: ");
    scanf("%d", &m);

    /*allocate memory for the 2D array*/
    arr = (int**) malloc(n * sizeof(int*));
    for (i = 0; i < n; i++) {
        arr[i] = (int*) malloc(m * sizeof(int));
    }


    /*initialize each element of the array*/
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            arr[i][j] = i * j;
        }
    }

    printf("The array is: \n");
    for (i = 0; i < n; i++) {
        for (j = 0; j < m; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }

    /*deallocate the dynamically allocated memory*/
    for (i = 0; i < n; i++) {
        free(arr[i]);
    }
    free(arr);
    return 0;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

The output
Enter the number of rows: 5
Enter the number of columns: 5
The array is:
0 0 0 0 0
0 1 2 3 4
0 2 4 6 8
0 3 6 9 12
0 4 8 12 16
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با استفاده از Calloc

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

نحو
ptr = (cast-type*)calloc(n, element-size);

جایی که

  • n تعداد عناصری است که باید تخصیص داده شود
  • اندازه عنصر اندازه هر عنصر بر حسب بایت است

اگر Calloc موفق شود، یک اشاره گر را به ابتدای بلوک حافظه اختصاص داده شده برمی گرداند. در غیر این صورت، یک اشاره گر تهی را برمی گرداند.
همچنین، هر دو calloc و malloc می توانند در تخصیص حافظه در صورت عدم وجود حافظه کافی در دسترس نباشند.

نمونه کد

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


/**
 * write a program thet allocates memory to an
 * array is integers and initializes them using calloc
*/


int main()
{
    int *arr, i;
    int n = 10;


    /*allocate the memory*/
    arr = (int*) calloc(n, sizeof(int));


    /*check if memory has been allocated*/
    if (arr == NULL)
    {
        printf("Memory allocation failed \n");
        exit(1);
    }



    printf("The array is: ");
    for (i = 0; i < n; i++)
    {
        printf("%d", arr[i]);
    }
    printf("\n");


    free(arr);
    return (0);    
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

The output
The array is: 0000000000
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

با استفاده از Realloc

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

نحو
ptr = (cast-type*)calloc(n, element-size);

نمونه کد

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


int main() {
  int *arr;
  int n, i;
  int new_n;


  printf("Enter the initial size of the array: ");
  scanf("%d", &n);


  arr = (int *) malloc(n * sizeof(int));


  printf("Enter %d integers:\n", n);
  for (i = 0; i < n; i++) {
    scanf("%d", &arr[i]);
  }


  printf("The array is:");
  for (i = 0; i < n; i++) {
    printf(" %d", arr[i]);
  }
  printf("\n");



  printf("Enter the new size of the array: ");
  scanf("%d", &new_n);


  arr = (int *) realloc(arr, new_n * sizeof(int));


  printf("Enter %d integers:\n", new_n);
  for (i = n; i < new_n; i++) {
    scanf("%d", &arr[i]);
  }


  printf("The resized array is:");
  for (i = 0; i < new_n; i++) {
    printf(" %d", arr[i]);
  }
  printf("\n");


  free(arr);
  return 0;
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

The output
Enter the initial size of the array: 5
Enter 5 integers:
2 5 7 9 3
The array is: 2 5 7 9 3
Enter the new size of the array: 6
Enter 6 integers:
5
The resized array is: 2 5 7 9 3 5
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

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

بنابراین دفعه بعد که روی یک پروژه برنامه نویسی کار می کنید این نکات را به خاطر بسپارید.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا