• آرایه پویا دو بعدی ج. آرایه های دینامیکی تک بعدی

    // اعلان یک آرایه پویا دو بعدی با 10 عنصر:

    float **ptrarray = شناور جدید* ; // دو رشته در آرایه

    برای (int count = 0; count< 2; count++)

    ptraray = شناور جدید ; // و پنج ستون

    // که در آن ptrarray آرایه ای از اشاره گرها به ناحیه حافظه اختصاص داده شده برای آرایه است اعداد واقعینوع شناور

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

    // انتشار حافظه اختصاص داده شده برای یک آرایه پویا دو بعدی:

    برای (int count = 0; count< 2; count++)

    حذف ptraray;

    // که در آن 2 تعداد ردیف های آرایه است

    #عبارتند از
    #عبارتند از
    #عبارتند از
    void main()
    {

    int*a; // اشاره گر به آرایه

    system("chcp 1251");

    scanf("%d"، &n);

    scanf("%d"، &m);

    // تخصیص حافظه

    a = (int*) malloc(n*m*sizeof(int));

    // عناصر آرایه را وارد کنید

    برای (i=0; i

    برای (j=0; j

    printf("a[%d][%d] = ", i, j);

    scanf("%d"، (a+i*m+j));

    // نمایش عناصر آرایه

    برای (i=0; i

    برای (j=0; j

    printf("%5d", *(a+i*m+j)); // 5 فاصله کاراکتر برای یک عنصر آرایه

    getchar(); getchar();
    }

    نتیجه اجرا

    تعداد خطوط را وارد کنید: 3

    تعداد ستون ها را وارد کنید: 4

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

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

    #عبارتند از
    #عبارتند از
    #عبارتند از
    void main()
    {

    int **a; // اشاره گر به اشاره گر به رشته

    system("chcp 1251");

    printf("تعداد خطوط را وارد کنید:");

    scanf("%d"، &n);

    printf("تعداد ستون ها را وارد کنید:");

    scanf("%d"، &m);

    // تخصیص حافظه برای اشاره گرها به رشته ها

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

    // عناصر آرایه را وارد کنید

    برای (i=0; i

    // تخصیص حافظه برای ذخیره رشته ها

    a[i] = (int*)malloc(m*sizeof(int));

    برای (j=0; j

    printf("a[%d][%d] = ", i, j);

    scanf("%d"، &a[i][j]);

    // نمایش عناصر آرایه

    برای (i=0; i

    برای (j=0; j

    printf("%5d", a[i][j]); // 5 فاصله کاراکتر برای یک عنصر آرایه

    رایگان (a[i]); // آزاد کردن حافظه برای رشته

    getchar(); getchar();
    }

    نتیجه اجرای برنامه مشابه مورد قبلی است.

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

    اشاره گرها

    اشاره گر متغیری است که مقدار آن آدرسی است که داده ها در آن قرار دارند. آدرس، شماره محل حافظه ای است که داده ها در آن یا با آن قرار دارند.

    با توجه به نوع داده در SI، اشاره گرها به موارد زیر تقسیم می شوند:

    اشاره گر تایپ شده نشانگری است که حاوی آدرس داده های یک نوع خاص (سیستم یا کاربر) است.

    اشاره گر تایپ نشده نشانگری است که حاوی آدرس داده هایی از نوع تعریف نشده (فقط یک آدرس) است.

    اعلامیه اشاره گر؛

    تنظیم نشانگر؛

    دسترسی به مقدار واقع در نشانگر. اعلان (توضیح) یک اشاره گر در زبان C به شرح زیر است:

    *name [=value] را تایپ کنید.

    یک اشاره گر در SI می تواند پس از اعلان با تعیین مقدار مربوطه از طریق علامت تخصیص مقداردهی اولیه شود. این مقدار باید آدرسی باشد که به یکی از اشکال زیر نوشته شده است:

    مقدار تهی (شناسه NULL)؛

    اشاره گر دیگر؛

    آدرس متغیر (از طریق عملیات گرفتن آدرس)؛

    عبارتی که نشانگر حسابی اشاره گر است.

    آدرس حاصل از تخصیص حافظه پویا.

    #عبارتند از

    int var; // متغیر عدد صحیح منظم

    int *ptrVar; // اشاره گر عدد صحیح (ptrVar باید از نوع int باشد، زیرا به متغیری از نوع int اشاره می کند)

    ptrVar = // آدرس سلولی در حافظه را که مقدار متغیر var در آن قرار دارد به اشاره گر اختصاص داد.

    scanf("%d"، &var); // مقدار وارد شده از صفحه کلید را در متغیر var قرار دهید

    printf("%d\n"، *ptrVar); // مقدار خروجی از طریق اشاره گر

    نتیجه اجرا: 6 6

    سخنرانی شماره 3.

    کارکرد.

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

    توصیف یک تابع در زبان C در هر نقطه ای از برنامه خارج از توضیحات سایر توابع انجام می شود و از سه عنصر تشکیل شده است:

    1. نمونه اولیه تابع.

    2. سربرگ تابع.

    3. عملکرد بدن.

    نمونه اولیه تابع بخشی اختیاری از توضیحات عملکرد است که برای اعلام برخی از عملکردها که رابط آن با یک نمونه اولیه مشخص شده مطابقت دارد. یک اعلان نمونه به شکل زیر است:

    نام تایپ (لیست انواع پارامترهای رسمی)؛

    پارامترهای تابع مقادیری هستند که هنگام فراخوانی تابع به آن ارسال می شوند.

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

    نام تایپ (لیست پارامترهای رسمی)

    مثال های سرصفحه تابع:

    int func(int i، double x، double y)

    void func (int ind، char *string)

    دو تابع (باطل)

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

    پیاده سازی تابعی در SI برای محاسبه فاکتوریل یک عدد.

    فاکتوریل دوگانه (بدون علامت)؛

    فاکتوریل دوگانه (عدد بدون علامت)

    دو واقعیت = 1.0;

    برای(بدون علامت i=1;i<=num;i++)

    واقعیت *= (دو) i;

    بازگشت واقعیت؛

    سازه های.

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

    اعلان SI یک ساختار به صورت زیر است:

    ساختار [نام را تایپ کنید]

    فیلد_1؛

    فیلد_2;

    فیلد_N;

    ) [فهرست متغیرها]؛

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

    فایل ها.

    یک فایل یک ناحیه نامگذاری شده از داده ها در یک رسانه ذخیره سازی است. انواع فایل (نسبت به زبان "SI"):
    متن;
    دودویی.
    عملیات اساسی انجام شده بر روی فایل ها:
    1.باز کردن فایل ها
    2. خواندن و نوشتن داده ها.
    3. بستن فایل ها.

    عملیات اضافی:
    1. پیمایش از طریق فایل.
    2. رسیدگی به خطاهای کار با فایل ها.
    3. حذف و تغییر نام فایل ها.
    4. شرح متغیر

    حالت های باز کردن فایل ها با SI

    تغییر مسیر جریان
    FILE * freopen (const char *نام فایل، const char *حالت، FILE *stream);

    تابع برمی گرداند:
    نشانگر فایل - همه چیز خوب است،
    NULL یک خطای تعریف مجدد است.

    بستن یک فایل
    int fclose(FILE *stream);

    تابع برمی گرداند:
    0 - فایل با موفقیت بسته شد.
    1 - هنگام بستن فایل خطایی رخ داد.

    بررسی پایان پرونده
    intfeof(FILE*stream);
    stream یک اشاره گر به یک فایل باز است.

    تابع برمی گرداند:
    0 - در صورتی که پرونده هنوز به پایان نرسیده باشد.
    0 - پایان فایل رسیده است.

    باز کردن فایل های متنی
    پارامتر دوم علاوه بر این کاراکتر t را مشخص می کند (اختیاری):
    rt، wt، در، rt+، wt+، at+

    خواندن از روی یک فایل متنی

    خواندن قالب بندی شده
    int fscanf(FILE *stream، const char * فرمت، ...);

    تابع برمی گرداند:
    > 0 - تعداد متغیرهای با موفقیت خوانده شده،
    0 - هیچ یک از متغیرها با موفقیت خوانده نشد،
    EOF - خطا یا پایان فایل رسیده است.
    خواندن یک خط

    تابع برمی گرداند:
    بافر - همه چیز خوب است،
    خواندن یک خط
    char * fgets (char * بافر، int maxlen، FILE *stream);

    تابع برمی گرداند:
    بافر - همه چیز خوب است،
    NULL - خطا یا پایان فایل رسیده است.
    خواندن یک شخصیت
    int fgetc(FILE *stream);
    تابع برمی گرداند:
    کد کاراکتر - اگر همه چیز خوب است،
    EOF - اگر خطایی رخ دهد یا به پایان فایل رسیده باشد.
    بازگرداندن یک شخصیت به جریان
    int ungetc(int c، FILE *stream);
    تابع برمی گرداند:
    کد کاراکتر - اگر همه چیز موفقیت آمیز باشد،
    EOF خطایی رخ داده است.

    در متن بنویسید فایل در SI

    خروجی فرمت شده
    int fprintf(FILE *stream، const char *قالب، ...);
    تابع برمی گرداند:
    تعداد کاراکترهای نوشته شده - اگر همه چیز خوب باشد،
    یک مقدار منفی - در صورت وجود خطا.
    ورودی رشته
    int fputs (const char *string, FILE *stream);
    تابع برمی گرداند:
    تعداد کاراکترهای نوشته شده - همه چیز خوب است،
    EOF خطایی رخ داده است.
    ورود نماد
    int fputc(int c، FILE *stream);
    تابع برمی گرداند:
    کد شخصیت نوشته شده - همه چیز خوب است،
    EOF خطایی رخ داده است.
    باز کردن فایل های باینری
    پارامتر دوم علاوه بر این کاراکتر b (اجباری) را مشخص می کند: rb، wb، ab، rb+، wb+، ab+
    خواندن از فایل های باینری
    size_t fread(void *buffer, size_t size, size_t num, FILE *stream);
    تابع تعداد بلوک های خوانده شده را برمی گرداند. اگر کمتر از num باشد، خطایی رخ داده است
    انتهای فایل

    نوشتن در یک فایل باینری
    size_t fwrite(const void *buffer, size_t size, size_t num, FILE *stream);
    تابع تعداد بلوک های نوشته شده را برمی گرداند. اگر کمتر از num باشد، خطایی رخ داده است.

    ناوبری فایل

    خواندن افست فعلی در یک فایل:
    طولانی int ftell(FILE *stream);
    تغییر افست فعلی در یک فایل:
    int fseek(FILE *stream, long int offset, int origin);

    SEEK_SET (0) - از ابتدای فایل.
    SEEK_CUR (1) - از موقعیت فعلی.
    SEEK_END (2) - از انتهای فایل.
    تابع برمی گرداند:
    0 - همه چیز خوب است،
    !0 - خطایی رخ داده است.
    انتقال به ابتدای یک فایل:
    void rewind(FILE *stream);
    خواندن موقعیت فعلی در یک فایل:
    int fgetpos(FILE *stream, fpos_t *pos);
    تنظیم موقعیت فعلی در فایل:
    int fsetpos(FILE *stream, const fpos_t *pos);
    بازگشت توابع:
    0 - همه چیز موفق است،
    !0 - خطایی رخ داده است.
    ساختار fpos_t:
    ساختار typedef fpos_t (
    طولانی مدت
    mbstate_t wstate;
    ) fpos_t;

    دریافت پرچم خطا:
    int ferror(FILE *stream);
    در صورت بروز خطا، تابع مقدار غیر صفر را برمی گرداند.
    عملکرد بازنشانی خطا:
    void clearer (FILE *stream);
    تابع خروجی پیام خطا:
    خطای خالی (const char *string);

    بافر کردن

    عملکرد پاکسازی بافر:
    int flush(FILE *stream);
    تابع برمی گرداند:
    0 - همه چیز خوب است.
    EOF خطایی رخ داده است.
    تابع مدیریت بافر:
    void setbuf(FILE *stream، char * buffer);

    یک بافر با اندازه BUFSIZ ایجاد می کند. قبل از ورودی یا خروجی به یک جریان استفاده می شود.

    فایل های موقت

    تابع ایجاد یک فایل موقت:
    FILE * tmpfile(void);
    یک فایل موقت در حالت wb+ ایجاد می کند. پس از بسته شدن فایل، دومی به طور خودکار حذف می شود.
    تابع تولید نام فایل موقت:
    char * tmpnam(char *buffer);

    حذف و تغییر نام دهید

    عملکرد حذف فایل:
    int remove(const char *filename);
    تابع تغییر نام فایل:
    int rename(const char *fname, const char *nname);
    بازگشت توابع:
    0 - در صورت موفقیت
    0 در غیر این صورت.

    سخنرانی شماره 4.

    پشته.

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

    هنگام کار با پشته ها، عملیات درج و استخراج یک عنصر اساسی است. این عملیات به طور سنتی "فشار بر روی پشته" (فشار) و "pop off the stack" (پاپ) نامیده می شود. بنابراین، برای پیاده سازی یک پشته، باید دو تابع بنویسید: push()، که یک مقدار را به پشته فشار می دهد، و pop()، که یک مقدار را از پشته خارج می کند. همچنین لازم است یک منطقه از حافظه اختصاص داده شود که به عنوان پشته استفاده می شود. برای این منظور می توانید با استفاده از توابع زبان C ارائه شده برای تخصیص حافظه پویا، آرایه ای را اختصاص دهید یا به صورت پویا یک قطعه از حافظه را اختصاص دهید. همانند صف، تابع بازیابی یک عنصر را از لیست می گیرد و اگر در جای دیگری ذخیره نشده باشد، حذف می کند. شکل زیر فرم کلی توابع push() و pop() است که روی یک آرایه عدد صحیح کار می کنند. پشته های داده از نوع متفاوت را می توان با تغییر نوع داده زیربنایی آرایه سازماندهی کرد.

    inttos=0; /* بالای پشته */

    /* عنصر را روی پشته فشار دهید. */

    فشار خالی (int i)

    if(tos >= MAX) (

    printf("پول پشته\n");

    /* عنصر بالای پشته را دریافت کنید. */

    اگر (به< 0) {

    printf("پشته خالی است\n");

    پشته بازگشت؛

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

    نمونه پشته.

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

    /* یک ماشین حساب ساده با چهار مرحله. */

    #عبارتند از

    #عبارتند از

    int*p; /* اشاره گر به فضای خالی حافظه */

    int *tos; /* اشاره گر به بالای پشته */

    int*bos; /* اشاره گر به پایین پشته */

    فشار خالی (int i);

    p = (int *) malloc(MAX*sizeof(int)); /* حافظه پشته دریافت کنید */

    printf("خطا در تخصیص حافظه\n");

    bos=p+MAX-1;

    printf("ماشین حساب چهار مرحله ای\n");

    printf("q" را برای خروج فشار دهید\n");

    printf("%d\n"، a+b);

    printf("%d\n"، b-a);

    printf("%d\n"، b*a);

    printf("تقسیم بر 0.\n");

    printf("%d\n"، b/a);

    case ".": /* محتویات بالای پشته را نشان می دهد */

    printf("مقدار فعلی در بالای پشته: %d\n"، a);

    ) while(*s != "q");

    /* هل دادن عنصر روی پشته. */

    فشار خالی (int i)

    if(p > bos) (

    printf("پول پشته\n");

    /* عنصر بالایی را از پشته دریافت کنید. */

    اگر (ص< tos) {

    printf("پشته خالی است\n");

    صف

    صف یک لیست خطی از اطلاعات است که بر اساس اولین ورود، اولین خروج مدیریت می شود. این اصل (و صف به عنوان یک ساختار داده) گاهی اوقات FIFO نیز نامیده می شود. این بدان معناست که اولین موردی که در صف قرار می گیرد اولین موردی است که در صف قرار می گیرد، دومین موردی که در صف قرار می گیرد دومین موردی است که باید بازیابی شود و غیره. این تنها راه کار با صف است. دسترسی تصادفی به عناصر فردی مجاز نیست.

    برای تصور اینکه صف چگونه کار می کند، دو تابع را معرفی می کنیم: qstore() و qretrieve() (از "store" - "save"، "retrieve" - ​​"receive"). تابع qstore() یک عنصر را در انتهای صف قرار می دهد و تابع qretrieve() یک عنصر را از سر صف حذف می کند و مقدار آن را برمی گرداند. جدول تأثیر دنباله ای از چنین عملیاتی را نشان می دهد.

    عمل محتوای صف
    qstore (A) آ
    qstore (B) A B
    qstore (C) A B C
    qretrieve() A را برمی گرداند قبل از میلاد مسیح
    qstore(D) B C D
    qretrieve() B را برمی گرداند سی دی
    qretrieve() C را برمی گرداند D

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

    در برنامه نویسی از صف ها برای حل بسیاری از مسائل استفاده می شود. یکی از رایج ترین انواع این گونه مسائل، شبیه سازی است. صف ها همچنین در زمانبندی وظایف سیستم عامل و در بافر I/O استفاده می شوند.

    /* زمانبندی رویداد کوچک */

    #عبارتند از

    #عبارتند از

    #عبارتند از

    #عبارتند از

    char *p، *qretrieve(void);

    void enter(void)، qstore(char *q)، review(void)، delete_ap(void);

    برای (t=0; t< MAX; ++t) p[t] = NULL; /* иницилизировать массив

    اشاره گرهای پوچ */

    printf("Enter (E)، List (L)، Delete (R)، Exit (Q):");

    *s = toupper(*s);

    /* یک جلسه جدید در صف قرار دهید. */

    باطل وارد (باطل)

    printf("نوبت %d را وارد کنید: ", spos+1);

    if(*s==0) ​​break; /* نوشته ای انجام نشد */

    p = (char *) malloc(strlen(s)+1);

    printf("حافظه تمام شده.\n");

    if(*s) qstore(p);

    /* محتویات صف را مشاهده کنید. */

    بررسی باطل (باطل)

    برای (t=rpos; t< spos; ++t)

    printf("%d. %s\n"، t+1، p[t]);

    /* جلسه را از صف حذف کنید. */

    void delete_ap(void)

    if((p=qretrieve())==NULL) return;

    printf("%s\n"، p);

    /* قرار ملاقات را درج کنید. */

    void qstore(char*q)

    printf("لیست کامل\n");

    /* قرار ملاقات را بازیابی کنید. */

    char *qretrieve(void)

    if(rpos==spos) (

    printf("دیگر برخورد نکنید.\n");

    بازگشت p;

    فهرست کنید.

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

    int data;//فیلد داده

    s *next;//عنصر بعدی

    ) *first,*curr;// first and current element

    مقداردهی اولیه:

    first->next=curr;

    برای دریافت اولین عنصر از first->data استفاده کنید

    برای افزودن یک عنصر جدید: curr->next=new s;

    curr=curr->next;//به آخرین مورد بروید

    و برای مثال 50 عنصر را از طریق یک حلقه تکرار در لیست دریافت کنید:

    curr=first;//پرش به اول

    برای (int i=0;i<50;i++)

    if(curr->next!=NULL)

    curr=curr->next;


    اطلاعات مشابه


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

    • با استفاده از تابع مالوک, calloc, تخصیص مجددو رایگان؛
    • از طریق اپراتور جدیدو حذف.

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

    void *malloc(size);

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

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

    void *calloc(nime, size);

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

    تابع تخصیص مجددتغییر اندازه می دهدحافظه تخصیص داده شده قبلی او را اینگونه خطاب می کنند:

    char *realloc (باطل *p، اندازه)؛

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

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

    void free (void *p size);

    اینجا پ- یک اشاره گر به یک ناحیه حافظه که قبلاً توسط توابع اختصاص داده شده است مالوک, callocیا تخصیص مجدد.

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

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

    int *mas=new int;

    به اندازه نیاز حافظه برای ذخیره 10 مقدار int اختصاص داده شده است.

    در واقع در متغیر ماآدرس عنصر صفر آرایه پویا ذخیره می شود. بنابراین آدرس اولین عنصر بعدی در ناحیه حافظه اختصاص داده شده است ما+1 و ما+i آدرس عنصر i است. دسترسی به عنصر i ام یک آرایه پویا می تواند به طور معمول mas[i] یا به روش دیگری انجام شود. *(mas+i) . مهم است که اطمینان حاصل کنید که از مرزهای منطقه حافظه اختصاص داده شده فراتر نروید.

    هنگامی که به آرایه پویا (در هر لحظه از عملیات برنامه) نیاز نیست، حافظه را می توان با استفاده از تابع آزاد کرد. رایگانیا اپراتور حذف.

    من پیشنهاد می کنم چندین کار را در نظر بگیرم که این درس را تقویت می کند:

    وظیفه 1

    مجموع عناصر واقعی یک آرایه پویا را بیابید.

    //نمونه ای از استفاده از malloc و توابع رایگان #include "stdafx.h" #include با استفاده از namespace std. int main() ( setlocale(LC_ALL,"Rus"); int i, n؛ float *a; //اشاره گر به float float s؛ cout<<"\n"; cin>>n; //ورودی بعد آرایه //تخصیص حافظه برای آرایه ای از n عنصر واقعی a=(float *)malloc(n*sizeof(float)); کوت<<"Введите массив A \n"; //ввод элементов массива for (i=0; i>*(a+i); ) //انباشته شدن مجموع عناصر آرایه برای (s=0, i=0; i

    //نمونه ای از استفاده از توابع malloc و free

    #include "stdafx.h"

    #عبارتند از

    با استفاده از namespace std ;

    int main()

    int i , n ;

    شناور * a ; //اشاره به شناور

    شناور s ;

    کوت<< "\n" ; cin >>n; //بعد آرایه را وارد کنید

    //تخصیص حافظه برای آرایه ای از n عنصر واقعی

    a = (float * ) malloc (n * sizeof (float ) );

    کوت<< "آرایه A را وارد کنید \n";

    //عناصر آرایه ورودی

    برای (i = 0 ؛ i< n ; i ++ )

    cin >> * (a + i ) ;

    //انباشته شدن مجموع عناصر آرایه

    برای (s = 0، i = 0؛ i< n ; i ++ )

    s += * (a + i ) ;

    //مقدار خروجی مجموع

    کوت<< "S=" << s << "\n" ;

    // حافظه خالی

    رایگان (a)؛

    system("مکث");

    بازگشت 0 ;

    وظیفه 2

    یک آرایه پویا از اعداد صحیح را تغییر دهید تا عناصر مثبت آن منفی شوند و بالعکس. برای حل مسئله، هر عنصر را در -1 ضرب می کنیم.

    //نمونه استفاده از عملگرهای جدید و حذف #include "stdafx.h" #include با استفاده از namespace std. int main() ( setlocale(LC_ALL,"Rus"); int i, n؛ //ورودی تعداد عناصر آرایه cout<<"n="; cin>>n; //تخصیص حافظه int *a=new int[n]; کوت<<"Введите элементы массива:\n"; //ввод массива for (i=0; i>a[i]; //خروجی آرایه داده شده برای (i=0; i

    //نمونه استفاده از عملگرهای جدید و حذف

    #include "stdafx.h"

    #عبارتند از

    با استفاده از namespace std ;

    int main()

    setlocale(LC_ALL، "Rus");

    int i , n ;

    //تعداد عناصر آرایه را وارد کنید

    کوت<< "n=" ; cin >>n;

    //تخصیص حافظه

    int * a = int جدید [ n ] ;

    کوت<< "عناصر آرایه را وارد کنید:\n";

    //ورودی آرایه

    با جمع آوری اطلاعات برای نوشتن این مقاله، یاد اولین آشنایی خود با اشاره گرها افتادم - غم و اندوه وجود داشت ... بنابراین، پس از مطالعه چندین بخش در این زمینه از کتاب های مختلف برنامه نویسی C ++، تصمیم گرفتم راه دیگری را طی کنم و موضوع اشاره گرهای C ++ را به ترتیبی که لازم می دانم بیان کنم. من فوراً یک تعریف کوتاه به شما ارائه می دهم و نکاتی را در کار در نظر خواهیم گرفت - با مثال. مقاله بعدی () تفاوت های ظریف، استفاده از اشاره گرها با رشته های سبک C (آرایه های کاراکتر) و موارد اصلی را که باید به خاطر بسپارید را پوشش می دهد.

    اشاره گر در C++ متغیری است که آدرس داده ها (مقادیر) را در حافظه ذخیره می کند و نه خود داده ها را.

    با در نظر گرفتن مثال های زیر، نکته اصلی را درک خواهید کرد - چرا در برنامه نویسی به اشاره گر نیاز داریم، چگونه آنها را اعلام و استفاده کنیم.

    فرض کنید در یک برنامه باید یک آرایه عدد صحیح ایجاد کنیم که اندازه دقیق آن را قبل از شروع برنامه نمی دانیم. یعنی ما نمی دانیم که کاربر باید چند عدد به این آرایه اضافه کند. البته می توانیم ایمن بازی کنیم و آرایه ای از چندین هزار عنصر (مثلاً 5000) را اعلام کنیم. این (به نظر ذهنی ما) باید برای کار کاربر کافی باشد. بله - در واقع - ممکن است کافی باشد. اما فراموش نکنیم که این آرایه فضای زیادی را در RAM اشغال خواهد کرد (5000 * 4 (نوع int) = 20000 بایت). سپس مطمئن شدیم و کاربر فقط 10 عنصر از آرایه ما را پر می کند. معلوم می شود که 40 بایت در واقع در حال کار است و 19960 بایت بیهوده حافظه را اشغال می کند.

    استفاده غیر منطقی از رم

    #عبارتند از با استفاده از namespace std. int main() (setlocale(LC_ALL، "rus")؛ const int SizeOfArray = 5000؛ int arrWithDigits = ()؛ cout<< "Массив занял в памяти " << sizeof(arrWithDigits) << " байт" << endl; int amount = 0; cout << "Сколько чисел вы введёте в массив? "; cin >> مقدار؛ کوت<< "Реально необходимо " << amount * sizeof(int) << " байт" << endl; for (int i = 0; i < amount; i++) { cout << i + 1 << "-е число: "; cin >> arrWithDigits[i]; ) برش<< endl; for (int i = 0; i < amount; i++) { cout << arrWithDigits[i] << " "; } cout << endl; return 0; }

    #عبارتند از

    با استفاده از namespace std ;

    int main()

    const int SizeOfArray = 5000 ;

    int arrWithDigits [SizeOfArray] = ();

    کوت<< "آرایه اشغال شده در حافظه"<< sizeof (arrWithDigits ) << " байт" << endl ;

    مقدار int = 0 ;

    کوت<< "چند عدد را در آرایه قرار خواهید داد؟";

    cin >> مقدار ;

    کوت<< "واقعا لازم است"<< amount * sizeof (int ) << " байт" << endl ;

    برای (int i = 0 ; i< amount ; i ++ )

    کوت<< i + 1 << "-е число: " ;

    cin >> arrWithDigits[ i ] ;

    کوت<< endl ;

    برای (int i = 0 ; i< amount ; i ++ )

    کوت<< arrWithDigits [ i ] << " " ;

    کوت<< endl ;

    بازگشت 0 ;

    به یک تابع کتابخانه استاندارد sizeof()ارسال آرایه اعلام شده arrWithDigitsخط 10. به اندازه بایتی که این آرایه در حافظه اشغال می کند، به سایت تماس برمی گردد. در پاسخ به این سوال که "چند عدد را وارد آرایه خواهید کرد؟" پاسخ - 10. در سطر 15، عبارت مقدار * sizeof(int)برابر 10 * 4 می شود، زیرا تابع اندازه (int) 4 (اندازه بر حسب بایت از نوع int) برمی گردد. در مرحله بعد، اعداد را از صفحه کلید وارد کنید تا برنامه آنها را روی صفحه نمایش دهد. به نظر می رسد که 4990 عنصر باقی مانده صفرها را ذخیره می کنند. پس نشان دادن آنها فایده ای ندارد.

    اطلاعات اصلی روی صفحه: آرایه 20000 بایت طول کشید، اما در واقعیت به 40 بایت نیاز دارد. چگونه از این وضعیت خارج شویم؟ شاید کسی بخواهد برنامه را بازنویسی کند تا کاربر اندازه آرایه را از صفحه کلید وارد کند و پس از وارد کردن مقدار، آرایه ای را با تعداد عناصر مورد نیاز اعلام کند. اما این کار را نمی توان بدون اشاره گر انجام داد. همانطور که به یاد دارید، اندازه یک آرایه باید ثابت باشد. یعنی یک ثابت عدد صحیح باید قبل از اعلان آرایه مقداردهی اولیه شود و نمی توانیم ورودی آن را از صفحه کلید درخواست کنیم. آزمایش - بررسی کنید.


    در اینجا ما توسط اپراتور با رنگ قرمز مشخص شده ایم >> زیرا نمی توانید یک مقدار ثابت را تغییر دهید.

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


    در اینجا به ما هشدار داده می شود که اندازه یک آرایه نمی تواند مقدار یک متغیر معمولی باشد. یک مقدار ثابت مورد نیاز است!

    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

    استفاده منطقی از RAM با استفاده از اشاره گرها

    #عبارتند از #عبارتند از با استفاده از namespace std. int main() (setlocale(LC_ALL، "rus")؛ int sizeOfArray = 0؛ // اندازه آرایه (ورودی کاربر) cout<< "Чтобы создать массив чисел, введите его размер: "; cin >>sizeOfArray؛ // توجه! int* arrWithDigits - اعلام یک اشاره گر // به یک قطعه از حافظه که توسط new int* arrWithDigits = new int تخصیص داده می شود. برای (int i = 0; i< sizeOfArray; i++) { arrWithDigits[i] = i + 1; cout << arrWithDigits[i] << " "; } cout << endl; delete arrWithDigits; // освобождение памяти return 0; }

    #عبارتند از

    #عبارتند از

    با استفاده از namespace std ;

    int main()

    setlocale(LC_ALL، "rus");

    int sizeOfArray = 0 ; // اندازه آرایه (ورودی کاربر)

    کوت<< "برای ایجاد یک آرایه از اعداد، اندازه آن را وارد کنید: ";

    cin >> sizeOfArray ;

    // توجه! int* arrWithDigits - اعلام اشاره گر

    // به ناحیه حافظه ای که جدید اختصاص می دهد

    int * arrWithDigits = int جدید [ sizeOfArray ] ;

    برای (int i = 0 ; i< sizeOfArray ; i ++ )

    arrWithDigits[ i ] = i + 1 ;

    کوت<< arrWithDigits [ i ] << " " ;

    کوت<< endl ;

    arrWithDigits را حذف کنید. // تخصیص حافظه

    بازگشت 0 ;

    کاربر یک مقدار را از صفحه کلید وارد می کند - خط 12. اشاره گر در زیر تعریف شده است: int * arrWithDigitsاین مدخل به این معنی است arrWithDigitsیک اشاره گر است. برای ذخیره آدرس سلولی که عدد صحیح در آن قرار خواهد گرفت ایجاد شد. در مورد ما arrWithDigitsبه سلول آرایه با شاخص 0 اشاره خواهد کرد * - همان چیزی که برای ضرب استفاده می شود. از زمینه، کامپایلر "درک" می کند که این یک اعلان اشاره گر است و نه یک ضرب. بعد علامت می آید = و اپراتور جدید، که یک منطقه از حافظه را اختصاص می دهد. ما به یاد داریم که حافظه ما باید به یک آرایه اختصاص داده شود، نه برای یک عدد. در حال ضبط جدید int[sizeOfArray]را می توان به صورت زیر رمزگشایی کرد: جدید(تخصیص حافظه) بین المللی(برای ذخیره اعداد صحیح) (در مقدار sizeOfArray ).

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

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

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

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

    تلاش برای تغییر متغیرهای ارسال شده به یک تابع

    #عبارتند از #عبارتند از با استفاده از namespace std. void changeData(int varForCh1، int varForCh2); int main() (setlocale(LC_ALL, "rus"); int variableForChange_1 = 0; int variableForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(variableForChange_1, variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int varForCh1, int varForCh2) { cout << "Введите новое значение первой переменной: "; cin >>varForCh1; کوت<< "Введите новое значение второй переменной: "; cin >> varForCh2; )

    #عبارتند از

    #عبارتند از

    با استفاده از namespace std ;

    void changeData (int varForCh1 , int varForCh2 ) ;

    int main()

    setlocale(LC_ALL، "rus");

    متغیر intForChange_1 = 0 ;

    متغیر intForChange_2 = 0 ;

    کوت<< "variableForChange_1 = " << variableForChange_1 << endl ;

    کوت<< "variableForChange_2 = " << variableForChange_2 << endl ;

    کوت<< endl ;

    changeData (variableForChange_1, variableForChange_2) ;

    کوت<< endl ;

    کوت<< "variableForChange_1 = " << variableForChange_1 << endl ;

    کوت<< "variableForChange_2 = " << variableForChange_2 << endl ;

    بازگشت 0 ;

    void changeData(int varForCh1، int varForCh2)

    کوت<< یک مقدار جدید برای متغیر اول وارد کنید:;

    cin >> varForCh1 ;

    کوت<< یک مقدار جدید برای متغیر دوم وارد کنید:;

    cin >> varForCh2 ;

    برنامه را اجرا کنید و مقادیر متغیر جدید را وارد کنید. در پایان خواهید دید که در انتهای تابع، متغیرها تغییر نکرده و برابر با 0 هستند.

    همانطور که به یاد دارید، این تابع مستقیماً با متغیرها کار نمی کند، بلکه کپی های دقیق آنها را ایجاد می کند. این کپی ها پس از خروج تابع از بین می روند. یعنی تابع مقداری متغیر را به عنوان پارامتر دریافت کرد، یک کپی از آن ایجاد کرد، با آن کار کرد و آن را از بین برد. خود متغیر بدون تغییر باقی می ماند.

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

    تغییر مقادیر متغیر با استفاده از نشانگرها

    #عبارتند از #عبارتند از با استفاده از namespace std. void changeData(int* varForCh1, int* varForCh2); int main() (setlocale(LC_ALL, "rus"); int variableForChange_1 = 0; int variableForChange_2 = 0; cout<< "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; cout << endl; changeData(&variableForChange_1, &variableForChange_2); cout << endl; cout << "variableForChange_1 = " << variableForChange_1 << endl; cout << "variableForChange_2 = " << variableForChange_2 << endl; return 0; } void changeData(int* varForCh1, int* varForCh2) { cout << "Введите новое значение первой переменной: "; cin >> *varForCh1; کوت<< "Введите новое значение второй переменной: "; cin >> *varForCh2; )

    اولین تایمر در این وب سایت، بنابراین به اینجا می رسد.

    من با C++ تازه کار هستم و در حال حاضر روی کتاب «ساختارهای داده با استفاده از C++ 2nd ed, D.S. Malik» کار می کنم.

    در کتاب، مالک دو راه برای ایجاد یک آرایه دو بعدی پویا ارائه می دهد. در روش اول، متغیر را به صورت آرایه ای از اشاره گرها اعلام می کنید که هر اشاره گر از نوع عدد صحیح است. به عنوان مثال،

    int *board;

    و سپس از یک حلقه for برای ایجاد "ستون" در حالی که از آرایه ای از اشاره گرها به عنوان "ردیف" استفاده می کنید، استفاده کنید.

    روش دوم، شما از یک اشاره گر به یک اشاره گر استفاده می کنید.

    Int **برد; برد = int جدید* ;

    سوال من این است: کدام روش بهتر است؟ تجسم روش ** برای من آسان تر است، اما روش اول را می توان تقریباً به همان روش استفاده کرد. از هر دو روش می توان برای ایجاد آرایه های دو بعدی پویا استفاده کرد.

    ویرایش: همانطور که در بالا گفته شد به اندازه کافی واضح نبود. این کدی است که من امتحان کردم:

    Int row, col; کوت<< "Enter row size:"; cin >> ردیف؛ کوت<< "\ncol:"; cin >>col; int *p_board; برای (int i=0; i< row; i++) p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_board[i][j] = j; cout << p_board[i][j] << " "; } cout << endl; } cout << endl << endl; int **p_p_board; p_p_board = new int* ; for (int i=0; i < row; i++) p_p_board[i] = new int; for (int i=0; i < row; i++) { for (int j=0; j < col; j++) { p_p_board[i][j] = j; cout << p_p_board[i][j] << " "; } cout << endl; }

    4 پاسخ

    روش اول را نمی توان برای ایجاد استفاده کرد پویاآرایه های دوبعدی زیرا:

    int *board;

    شما اساسا یک آرایه از 4 اشاره گر را به یک int اختصاص داده اید روی پشته. بنابراین اگر اکنون هر یک از آن 4 نشانگر را با یک آرایه پویا پر کنید:

    برای (int i = 0; i< 4; ++i) { board[i] = new int; }

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

    یک بار دیگر وقتی انجام می دهید:

    int *board;

    Const int x = 4; //<--- `const` qualifier is absolutely needed in this case! int *board[x];

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

    از طرف دیگر، وقتی انجام می دهید:

    Int **برد; برد = int جدید*;

    int x = 10; //<--- Notice that it does not have to be `const` anymore! int **board; board = new int*[x];

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

    در نتیجه، برای ایجاد یک آرایه دو بعدی پویا، باید از روش دوم استفاده کنید:

    Int **برد; برد = int جدید*; // آرایه پویا (اندازه 10) از اشاره گرها به int برای (int i = 0; i< 10; ++i) { board[i] = new int; // each i-th pointer is now pointing to dynamic array (size 10) of actual int values }

    ما به تازگی یک آرایه 2 بعدی مربعی 10 در 10 ایجاد کردیم. برای عبور از آن و پر کردن آن با مقادیر واقعی مانند 1، می توانیم از حلقه های تو در تو استفاده کنیم:

    برای (int i = 0; i< 10; ++i) { // for each row for (int j = 0; j < 10; ++j) { // for each column board[i][j] = 1; } }

    آنچه برای روش دوم توضیح می دهید فقط یک آرایه 1 بعدی را ارائه می دهد:

    int *board = new int;

    این فقط یک آرایه با 10 عنصر را اختصاص می دهد. شاید منظور شما چیزی شبیه به این بوده است:

    Int **board = new int*; برای (int i = 0; i< 4; i++) { board[i] = new int; }

    در این مورد، ما 4 int*s را تخصیص می‌دهیم، و سپس هر یک به آرایه‌ای با 10 int ثانیه اختصاص داده شده است.

    بنابراین اکنون ما این را با صفحه int* مقایسه می کنیم. . تفاوت اصلی این است که هنگام استفاده از چنین آرایه ای، تعداد "ردیف ها" باید در زمان کامپایل مشخص باشد. این به این دلیل است که آرایه‌ها قرار است اندازه‌های زمان کامپایل ثابتی داشته باشند. اگر بخواهید احتمالاً آن آرایه را از int*s برگردانید، ممکن است مشکل داشته باشید، زیرا آرایه در پایان محدوده خود از بین می رود.

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

    برای (int i = 0; i< 4; i++) { delete board[i]; } delete board;

    من باید به جای آن استفاده از ظرف استاندارد را توصیه کنم. می توانید از std::array استفاده کنید 4> یا شاید std::vector >، که با اندازه مناسب مقداردهی اولیه می کنید.

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

    این سؤال اساساً معادل سؤال زیر است:

    int* x = int جدید است. "بهتر" از int x؟

    پاسخ این است "نه، مگر اینکه شما نیاز به انتخاب اندازه آرایه به صورت پویا داشته باشید."

    این کد با الزامات کتابخانه خارجی بسیار کمی به خوبی کار می کند و استفاده اولیه از آرایه **int را نشان می دهد.

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

    این برنامه آرگومان های STDIN را در قالب زیر می گیرد:

    2 2 3 1 5 4 5 1 2 8 9 3 0 1 1 3

    کد برنامه در زیر آمده است...

    #عبارتند از int main() (int **array_of_arrays; int num_arrays, num_queries; num_arrays = num_queries = 0; std::cin >> num_arrays >> num_queries; //std::cout<< num_arrays << " " << num_queries; //Process the Arrays array_of_arrays = new int*; int size_current_array = 0; for (int i = 0; i < num_arrays; i++) { std::cin >> size_current_array. int *tmp_array = int جدید; برای (int j = 0; j< size_current_array; j++) { int tmp = 0; std::cin >> tmp; tmp_array[j] = tmp; ) array_of_arrays[i] = tmp_array; ) //کوئری ها را پردازش کنید int x, y; x=y=0; برای (int q = 0; q< num_queries; q++) { std::cin >> x >> y; //std::out<< "Current x & y: " << x << ", " << y << "\n"; std::cout << array_of_arrays[x][y] << "\n"; } return 0; }

    این یک پیاده سازی بسیار ساده از int main است و فقط به std::cin و std::cout بستگی دارد. Barebones، اما به اندازه کافی خوب است که نشان دهد چگونه با آرایه های چند بعدی ساده کار کنید.

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

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

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

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

    اعلان آرایه های پویا یک بعدی

    بر اساس اعلامیه تک بعدی آرایه پویااعلان یک اشاره گر به یک متغیر از یک نوع معین را درک کنید تا بتوان از این متغیر به عنوان استفاده کرد آرایه پویا.

    نحو :

    نوع * ArrayName;

    نوع - نوع عناصر اعلام شده آرایه پویا. عناصر آرایه پویاتوابع و عناصری از نوع void وجود ندارد.

    مثلا:

    int*a; دو برابر *d;

    در این مثال‌ها، a و d نشانگرهای ابتدای ناحیه حافظه اختصاص‌یافته هستند. اشاره گرها مقدار آدرس ناحیه حافظه اختصاص داده شده را به ترتیب برای مقادیر نوع int و نوع double می گیرند.

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

    تخصیص حافظه برای یک آرایه پویا یک بعدی

    به منظور تخصیص حافظه برای یک بعدی آرایه پویادر زبان C++ 2 راه وجود دارد.

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

    نحو :

    ArrayName = نوع جدید [ConstantTypeExpression];

    ArrayName - شناسه آرایه، یعنی نام اشاره گر برای بلوک حافظه اختصاص داده شده.

    ExpressionTypeConstants- تعداد عناصر را تنظیم می کند ( بعد) آرایه. یک عبارت نوع ثابت در زمان کامپایل ارزیابی می شود.

    مثلا:

    int *mas; mas = int جدید ; /* تخصیص حافظه پویا 100*sizeof(int) bytes*/ double *m = new double [n]; /*تخصیص n*sizeof(دو) بایت حافظه پویا*/ طولانی (*lm); lm = بلند جدید ; /*تخصیص 2*4*اندازه (طولانی) بایت حافظه پویا*/

    هنگام تخصیص حافظه پویا، ابعاد آرایه باید کاملاً مشخص باشد.

    2) با استفاده از تابع کتابخانه malloc (calloc) که برای تخصیص حافظه پویا استفاده می شود.

    نحو :

    ArrayName = (نوع *) malloc(N*sizeof(Type));

    ArrayName = (نوع *) calloc(N, sizeof(Type));

    ArrayName - شناسه آرایه، یعنی نام اشاره گر برای بلوک حافظه اختصاص داده شده.

    Type نوع اشاره گر به آرایه است.

    N تعداد عناصر آرایه است.

    مثلا:

    شناور *a; a=(float *)malloc(10*sizeof(float)); // یا a=(float *)calloc(10,sizeof(float)); /*تخصیص اندازه حافظه پویا 10*sizeof(float) bytes*/

    از آنجایی که تابع malloc(calloc) برمی گردد اشاره گر تایپ نشده void * ، سپس باید نتیجه را تبدیل کنید