آرایه اشاره گر نیست

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

int array[3];
array[2]=666;

کامپایلر زبان C و یا ++C مقدار [array[0 را به عنوان آدرسی به یک مقدار صحیح در نظر نگرفته و آن را مستقیما به عنوان یک مقدار در نظر می گیرد. دقیقا مثل نوشته زیر:

int *ptr = new int[۳];
ptr[2] = 66;

آشکارا مشخص است که var یک اشاره گر نیست؛ درست مثل [array[2

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

int *ptr = new int[۳];
ptr[2] = 66;

این دو برنامه مشابه هم هستند اما معنای آن ها برای کامپایلر متفاوت است. در اولین برنامه (خط دوم)، کامپایلر برای تولید کد آن به ترتیب زیر عمل می کند.
1) از [array[0 دو خانه به سمت جلو حرکت کن و آن را برابر ۶۶۶ قرار بده.
اما در برنامه ای که از اشاره گر استفاده نموده، عملکرد به صورت زیر است:
1) مقدار (آدرس) مربوط به [ptr[0 را بگیر.
2) آن را با دو جمع کن.
3) مقداری که اشاره گر به آن اشاره می کند را با ۶۶ مقداردهی کن.
در حقیقت مقدارهای مربوط به array ، &array و [array[0 با هم برابرند. اما array& دارای نوع متفاوتی است. (آدرس حافظه مربوط  به یک آرایه را با عضو آرایه اشتباه نگیرید.)
در این قسمت جهت درک بیشتر این مقاله از مثال دیگری استفاده می کنم. من قصد نوشتن برنامه ای را دارم که یک عدد صحیح را از کاربر گرفته، آن را با ۴ جمع و سپس نتیجه را چاپ می کند. این کار را یکبار با نوشتن یک اشاره گر از جنس عدد صحیح و یک بار با استفاده از مقدار عدد صحیح انجام می دهم.
با استفاده از عدد صحیح:

#include<iostream>
main(){
    int int_input;
    cin>>int_input;
    cout<<(int_input + 4)<<endl;
    return 0;
}

با استفاده از اشاره گر:

#include<iostream>
main(){
    int *int_ptr = new int[۱];
    cin>>*int_ptr;
    cout<< (*int_ptr + 4)<<endl;
    delete(int_ptr);
    return 0;
}

آیا واقعا کسی پیدا می شود که فکر کند این دو برنامه با هم یکسان هستند؟

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

۲۲۱۲: main(){
۰۰۴۰۱۰۰۰   push        ebp
۰۰۴۰۱۰۰۱   mov         ebp,esp
۰۰۴۰۱۰۰۳   sub         esp,44h
۰۰۴۰۱۰۰۶   push        ebx
۰۰۴۰۱۰۰۷   push        esi
۰۰۴۰۱۰۰۸   push        edi
۲۲۱۳:     int int_input;
۲۲۱۴:     cin>>int_input;
۰۰۴۰۱۰۰۹   lea         eax,[ebp-4]
0040100C   push        eax
0040100D   mov         ecx,offset cin (00414c58)
۰۰۴۰۱۰۱۲   call        istream::operator>> (0040b7c0)
۲۲۱۵:     cout<<(int_input+4)<<endl;
۰۰۴۰۱۰۱۷   push        offset endl (00401070)
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   add         ecx,4
۰۰۴۰۱۰۲۲   push        ecx
۰۰۴۰۱۰۲۳   mov         ecx,offset cout (00414c18)
۰۰۴۰۱۰۲۸   call        ostream::operator<< (0040b3e0)
0040102D   mov         ecx,eax
0040102F   call        ostream::operator<< (00401040)
۲۲۱۶:     return 0;
۰۰۴۰۱۰۳۴   xor         eax,eax
۲۲۱۷: }

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

۲۲۱۲: main(){
۰۰۴۰۱۰۰۰   push        ebp
۰۰۴۰۱۰۰۱   mov         ebp,esp
۰۰۴۰۱۰۰۳   sub         esp,4Ch
۰۰۴۰۱۰۰۶   push        ebx
۰۰۴۰۱۰۰۷   push        esi
۰۰۴۰۱۰۰۸   push        edi
۲۲۱۳:     int *int_ptr = new int[۱];
۰۰۴۰۱۰۰۹   push        4
0040100B   call        operator new (004011b0)
۰۰۴۰۱۰۱۰   add         esp,4
۰۰۴۰۱۰۱۳   mov         dword ptr [ebp-8],eax
۰۰۴۰۱۰۱۶   mov         eax,dword ptr [ebp-8]
۰۰۴۰۱۰۱۹   mov         dword ptr [ebp-4],eax
۲۲۱۴:     cin>>*int_ptr;
0040101C   mov         ecx,dword ptr [ebp-4]
0040101F   push        ecx
۰۰۴۰۱۰۲۰   mov         ecx,offset cin (00414c38)
۰۰۴۰۱۰۲۵   call        istream::operator>> (0040b8a0)
۲۲۱۵:     cout<< (*int_ptr + 4)<<endl;
0040102A   push        offset endl (004010a0)
0040102F   mov         edx,dword ptr [ebp-4]
۰۰۴۰۱۰۳۲   mov         eax,dword ptr [edx]
۰۰۴۰۱۰۳۴   add         eax,4
۰۰۴۰۱۰۳۷   push        eax
۰۰۴۰۱۰۳۸   mov         ecx,offset cout (00414bf8)
0040103D   call        ostream::operator<< (0040b4c0)
۰۰۴۰۱۰۴۲   mov         ecx,eax
۰۰۴۰۱۰۴۴   call        ostream::operator<< (00401070)
۲۲۱۶:     delete(int_ptr);
۰۰۴۰۱۰۴۹   mov         ecx,dword ptr [ebp-4]
0040104C   mov         dword ptr [ebp-0Ch],ecx
0040104F   mov         edx,dword ptr [ebp-0Ch]
۰۰۴۰۱۰۵۲   push        edx
۰۰۴۰۱۰۵۳   call        operator delete (۰۰۴۰۱۱۲۰)
۰۰۴۰۱۰۵۸   add         esp,4
۲۲۱۷:     return 0;
0040105B   xor         eax,eax
۲۲۱۸: }

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

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

منبع: سایت cplusplus.com نوشته SiavoshKC
ترجمه و ویرایش: مرجع فارسی سی پلاس پلاس به آدرس cplusplus.ir

نویسنده: تمدن

لازم به ذکر است که دامنه cplusplus.ir توسط من تهیه شده و در حال حاضر محتوای سایت را روی وبلاگ بارگذاری کرده ام ;)

برای مشاهدۀ فهرست مطالب به آدرس tamadon.net/cpp مراجعه فرمایید.

0 پاسخ

دیدگاه خود را ثبت کنید

تمایل دارید در گفتگو شرکت کنید؟
نظری بدهید!

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

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