وب سایت مهندسی نرم افزار

انجمن علمی دانشجویی مهندسی کامپیوتر دانشگاه شهید چمران اهواز


نویسنده: jafar
بازدید: 2411

اشاره گر ها در زبان C


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

یعنی چی؟ یعنی مثلا ما میومدیم میگفتیم :

char mychar = 'a'

این a تبدیل میشد به 97 که معادل کد اسکیش هست و 97 میرفت به مبنای دو و میشد 1100001 و در نهایت یه خونه ای توی RAM مقدار 1100001 رو میگرفت. در اینجا فرض کنید این مقدار وارد خونه‌ی fafb حافظه شده. دقت کنید که fafb در مبنای 16 هست.

نکته: برای پیدا کردن آدرس یک متغیر معمولی در RAM قبل ازاسم متغیر علامت & میزاریم و برای نمایش اون در تابع printf از %p استفاده میکنیم:

printf("%p",&mychar);

فرض کنید خروجی این کد شد fafb. باید بدونید که نمیشه به &mychar مقدار داد، یعنی نمیتونین آدرس یک متغیر عوض کنین، برای همین از اشاره گر ها استفاده میشه.

Value Address
1100001  fafb

برای تعریف اشاره گر قبل از اسم متغقر علامت * رو میزاریم. اشاره گر نوع داره، یعنی باید تعیین کنید اشاره گر شما از چه جنسی هست، دلیلشم اینه که اشاره گر باید بدونه زمانی که داره به یه آدرس اشاره میکنه قراره چند خونه از اون آدرس به بعد رو بخونه؟ مثلا اگه به خونه ی fafb اشاره میکرد و نوعش char بود زمانی که میخواست مقدار خونه رو چاپ کنه یک بایت رو میخوند ولی اگه از نوع int بود باید 2 یا 4 بایت رو میخوند مثلا باید خونه های fafb,fafc,fafd,fafe رو برای بدست آوردن مقدار خونه‌ی int میخوند.

int *p;

 

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

اگه از کاراکتر * استفاده نکنیم منظورمون آدرسیه که اشاره گر میخواد بهش اشاره کنه.

 

حالا میخوایم یک اشاره گر تعریف کنیم که به خونه ی mychar اشاره کنه، سینتکس کد اینشکلیه:

int *p;
p = &mychar;

 

 توی RAM یه همچین حالتی پیش میاد:

Value Address Variable Name
1100001  fafb mychar
 fafb fafc p*

 

حالا با استفاده از اشاره گر، میخوایم مقدار mychar رو عوض کنیم:

*p = 'z'

برای دیدن نتیجه کافیه مقدارmychar رو دوباره چاپ کنیم، کد کامل:

int main(){

  char mychar = 'a';
  printf("Value of mychar before using pointer: %c",mychar);

  char *p;
  p  = &mychar;
  *p = 'z';

  printf("\nValue of mychar after using pointer: %c",mychar);

    return 0;
}

خروجی:

Value of mychar before using pointer: a
Value of mychar after using pointer: z

 

یعنی بدون اینکه به mychar دست بزنیم مقدارش رو عوض کردیم. خب الان یه عده میگین (منم یکیشون بودم  ) خسته نباشی این چه کاریه نابغه؟؟ چرا لقمه رو میپیچونی؟ همون اول مقدارش رو عوض میکردی!!

جواب: خیلی وقتا برای عوض کردن مقدار یه متغیر به اون متغیر دسترسی نداریم، ولی اگه آدرسش رو بفرستیم میتونیم مقدارش رو عوض کنیم. مثلا همین تابع scanf، دقت کردین چرا داریم آدرس متغیر رو میفرستیم؟

 

 

حالا یکم کاربردی تر به مسئله نگاه کنیم، همونطور که میدونیم هر تابع یا هیچی بر نمیگردونه که اصطلاحا میگیم void یا اینکه یک مقدار رو برمیگردونه. برای تمرین بیایم و با اشاره گر یک تابع بنویسیم که چند مقدار برگردونه و خروجی void داشته باشه !

 

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

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

void areaEnv(int width,int height,int *area,int *env){
    *area = (width*height);
    *env  = (width+height) * 2 ;
}

int main(){
    int myarea,myenv;
    areaEnv(2,3,&myarea,&myenv);
    printf("Area:%d\nEnvironment: %d",myarea,myenv);
    return 0;
}

 

خروجی:

Area:6
Environment: 10

 

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

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

 

تمرین 2: برنامه ای بنویسید که با استفاده از یک تابع و اشاره گر، بزرگترین مقدار یک آرایه را برگرداند.

نکته1: نکته این تمرین بهتر متوجه شدن مفهوم ستاره هست که در حقیقت میخواد مقدار داخل خونه‌ی حافظه ای رو بخونه که جلوش اومده.

نکته2: با اضافه کردن هر واحد به مقدار اشاره گر، در حقیقت اشاره گر داره به اندازه بایت های نوع خودش به جلو میره.

 

کد کامل:

int max_func(int *ap,int arrsize){
    int max = *ap ;
    int i;
    for(i=1;i<arrsize;i++){
        if( *(ap+i) > max ){
            max = *(ap+i);
        }
    }
    return max;
}



int main(){
    int grades[] = { 6,13,16,12,15};
    int max = max_func(grades,5);
    printf("%d",max);

    return 0;
}

خروجی:

16

 

برای تمرین بیشتر برنامه ای بنویسید که با استفاده از یک تابع، آرایه ای را از ورودی دریافت کنه و به تک تک خونه هاش یک 5 تا اضافه کنه.

 

خروجی اشاره گر در تابع:

نکته مهمی که عمر هر متغیر در بلوک خودشه؛ یعنی اگه شما نمیتونید آدرس یک متغیر محلی داخل تابع رو برگردونید و باید آدرس یک متغیر global رو برگردونید.

int a=2;

int *pret(){
    a+=10;
    return &a;
}

int main(){
    int *p = pret();
    printf("%d",*p);
    
    return 0;
}

خروجی:

12

 

اشاره گر به اشاره گر:

زبان c به شما این قابلیت رو میده که که اشاره گری بسازید که به یک اشاره گر اشاره میکنه، مثلا همون مثال اول رو در نظر بگیرید، اینبار با اشاره گر به اشاره گر مقدار یک خونه رو تغییر میدیم:

int main(){
    char mychar = 'a';
    char *p1;
    p1 = &mychar;

    char **p2;
    p2 = &p1;

    **p2 = 'z';

    printf("mychar: %c ",mychar);

    return 0;
}

 

ایام به کام

jafar
1393 عضو از سال

درباره نویسنده:


جعفر آخوندعلی در حال حاضر در دوره ی کارشناسی رشته ی نرم افزار مشغول تحصیل در دانشگاه شهید چمران است.
برای تماس با او میتونید از طریق ایمیل jafar.akhondali@yahoo.com اقدام کنید.
برای نظر دادن باید وارد شوید،
عضو نیستید؟ از اینجا در کمتر از 20 ثانیه ثبت نام کنید :)