اشاره گر ها در زبان C همراه با مثال

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

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

اشاره گر چگونه کار می کند؟

وقتی متغیر v از نوع int را تعریف می کنیم، در واقع v یک مقدار را ذخیره می کند.

اشاره گرها در برنامه نویسی زبان C

اکنون v برابر صفر است.

اما هر متغیری افزون بر مقدار، دارای آدرس(یا به زبان ساده، مکانی که در حافظه اشغال می کند) نیز می باشد. این آدرس را می توان با قراردادن یک امپرسند(&) قبل از نام متغیر بدست آورد.

اشاره گرها در برنامه نویسی زبان C

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

اجازه دهید در عمل این مسئله را ببینیم.

اشاره گرها در برنامه نویسی زبان C

خروجی این برنامه -480613588 است.

با این اوصاف، اشاره گر چیست؟ به جای ذخیره ی یک مقدار، اشاره گر y آدرس متغیر را ذخیره می کند.

Int *y = &v;

متغیر

یک مقدار در یک آدرس ذخیره سازی/حافظه نام گذاری شده ذخیره می شود.

اشاره گر

یک مقدار که به آدرس ذخیره سازی/حافظه یک متغیر دیگر اشاره می کند

در این مبحث خواهیم آموخت:

  • اشاره گر چیست؟
  • اشاره گر چگونه عمل می کند؟
  • اعلان یک اشاره گر
  • مقداردهی آغازین یک متغیر
  • اشاره گر Null
  • اشاره گر void
  • اشاره گر Wild
  • اشاره گرهای دسترسی مستقیم و غیرمستقیم
  • عملیات روی اشاره گرها
  • عملیات داری اولویت(تقدم)
  • اشاره گرها و آرایه ها
  • اشاره گرها و رشته ها
  • مزایای اشاره گرها
  • معایب اشاره گرها

اعلان یک اشاره گر

همانند متغیرها، اشاره گرها باید قبل از استفاده در برنامه اعلان شوند. اشاره گرها تا زمانی که ار قواعد نام گذاری C تبعیت کنند می توانند هرنامی داشته باشند.اعلان اشاره گرها به شکل زیر است:

data_type * pointer_variable_name;

در اینجا،

  • Data_type نوع داده پایه متغیر C بوده و نوع داده متغیری که اشاره گر قرار است به آن اشاره کند را بیان می کند.
  • ستاره(*:همین ستاره برای ضرب هم استفاده می شود) که عملگر غیرمستقیم است، یک متغیر را اعلان می کند.

اجازه دهید چند مثال صحیح اعلان اشاره گر را ببینیم:

int *ptr_thing; /* pointer to an integer */

int *ptr1,thing;/* ptr1 is a pointer to type integer and thing is an integer variable */

double *ptr2; /* pointer to a double */

float *ptr3; /* pointer to a float */

char *ch1 ; /* pointer to a character */

float *ptr, variable;/*ptr is a pointer to type float and variable is an ordinary float variable */

مقداردهی اولیه اشاره گر

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

مطلب پیشنهادی:  مدیریت فایل ها در زبان C - ایجاد، بازکردن، خواندن، نوشتن و بستن یک فایل

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

pointer = &variable;

یک برنامه ساده برای نمایش اشاره گرها در زیر آمده است:

#include <stdio.h>

int main()

{

int a=10; //variable declaration

int *p; //pointer variable declaration

p=&a; //store address of variable a in pointer p

printf("Address stored in a variable p is:%x\n",p); //accessing the address

printf("Value stored in a variable p is:%d\n",*p); //accessing the value

return 0;

}

خروجی:

Address stored in a variable p is:60ff08

Value stored in a variable p is:10

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

انواع اشاره گر

اشاره گر Null

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

برنامه زیر کاربرد اشاره گر Null را نشان می دهد:

#include <stdio.h>

int main()

{

int *p = NULL; //null pointer

printf(“The value inside variable p is:\n%x”,p);

return 0;

}

خروجی:

The value inside variable p is:

0

اشاره گر void

در برنامه نویسی C، اشاره گر void به عنوان اشاره گر عمومی هم شناخته می شود. این نوع اشاره گر هیچ نوع داده استانداری ندارد. اشاره گر void با کلیدواژه void ساخته می شود. این نوع اشاره گر را می توان برای ذخیره آدرس هرنوع متغیری بکار گرفت.

برنامه زیر کاربرد اشاره گر void را نشان می دهد:

#include <stdio.h>

int main()

{

void *p = NULL; //void pointer

printf("The size of pointer is:%d\n",sizeof(p));

return 0;

}

خروجی:

The size of pointer is:4

اشاره گر Wild

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

برنامه زیر کاربرد اشاره گر wild را نشان می دهد:

#include <stdio.h>

int main()

{

int *p; //wild pointer

printf("\n%d",*p);

return 0;

}

خروجی:

timeout: the monitored command dumped core

sh: line 1: 95298 Segmentation fault timeout 10s main

انواع دیگر اشاره گرها در ‘C’ به شرح زیر است:

  • اشاره گر معلق(Dangling pointer)
  • اشاره گر پیچیده(complex pointer)
  • اشاره گر نزدیک(near pointer)
  • اشاره گر دور(Far pointer)
  • اشاره گر کلان(Huge pointer)

اشاره گرهای دسترسی مستقیم و غیرمستقیم

در زبان C، دو راه مشابه برای دسترسی و دستکاری به محتوای یک متغیر وجود دارد:

  • دسترسی مستقیم: مستقیماً نام متغیر را بکار می بریم.
  • دسترسی غیرمستقیم: اشاره گر به متغیر را بکار می بریم.

اجازه دهید این مسئله را با کمک برنامه زیر درک کنیم:

#include <stdio.h>

/* Declare and initialize an int variable */

int var = 1;

/* Declare a pointer to int */

int *ptr;

int main( void )

{

/* Initialize ptr to point to var */

ptr = &var;

/* Access var directly and indirectly */

printf("\nDirect access, var = %d", var);

printf("\nIndirect access, var = %d", *ptr);

/* Display the address of var two ways */

printf("\n\nThe address of var = %d", &var);

printf("\nThe address of var = %d\n", ptr);

/*change the content of var through the pointer*/

*ptr=48;

printf("\nIndirect access, var = %d", *ptr);

return 0;}

بعد از کامپایل برنامه بدون خطا، نتیجه خواهد شد:

Direct access, var = 1

Indirect access, var = 1

The address of var = 4202496

The address of var = 4202496

Indirect access, var = 48

محاسبات اشاره گرها

عملیات اشاره گرها در شکل زیر خلاصه شده است:

مطلب پیشنهادی:  اشاره گرهای تابع در برنامه نویسی C

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

عملیات داری اولویت(تقدم)

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

  • عملگرهای * و & و عملگرهای یگانی(unary) اولویت یکسانی دارند(نفی ! ، افزایش ++، کاهش –)
  • در یک عبارت، عملگرهای یگانی *، &، !،++،– از سمت راست به چپ ارزیابی می شوند.

اگر اشاره گر P به متغیر X اشاره داشته باشد، آنگاه *P را می توان در هرجایی به جای X نوشت.

عبارات زیر هم ارز هستند:

محاسبات اشاره گرها

در مثال آخر، پرانتزها ضروری هستند: از آنجایی که عملگرهای یگانی * و ++ از راست به چپ ارزیابی می شوند، بدون پرانتزها اشاره گر P و نه چیزی که P به آن اشاره می کند افزایش خواهد یافت.

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

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

اشاره گرها و آرایه ها

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

#include <stdio.h>

int main()

{

int a[5]={1,2,3,4,5}; //array initialization

int *p; //pointer declaration

/*the ptr points to the first element of the array*/

p=a; /*We can also type simply ptr==&a[0] */

printf("Printing the array elements using pointer\n");

for(int i=0;i<5;i++) //loop for traversing array elements

{

printf("\n%x",*p); //printing array elements

p++; //incrementing to the next element, you can also write p=p+1

}

return 0;

}

خروجی:

1

2

3

4

5

اضافه کردن یک عدد به یک اشاره گر، مکان اشاره گر را به مقدار حاصله از عمل جمع منتقل می کند. فرض کنید p اشاره گری است که در حال حاضر به مکان 0 از حافظه اشاره دارد. اگر عمل جمع p+1 را انجام دهیم، این عمل به صورت زیر به انجام می رسد:

اشاره گرها در برنامه نویسی زبان C

جمع/افزایش اشاره گر

چون p در حال حاضر به مکان صفر اشاره دارد، پس از اضافه کردن یک، مقدار برار 1 شده، و در نتیجه اشاره گر به مکان 1 از حافظه اشاره می کند.

اشاره گرها و رشته ها

رشته آرایه ای از char ها بوده که به کارکتر null ‘\0’ ختم می شود. می توان رشته ها را با استفاده از اشاره گرها دستکاری کرد. در زیر مثالی آمده که این بخش را توضیح می دهد:

#include <stdio.h>

#include <string.h>

int main()

{

char str[]="Hello Guru99!";

char *p;

p=str;

printf("First character is:%c\n",*p);

p =p+1;

printf("Next character is:%c\n",*p);

printf("Printing all the characters in a string\n");

p=str; //reset the pointer

for(int i=0;i<strlen(str);i++)

{

printf("%c\n",*p);

p++;

}

return 0;

}

خروجی:

First character is:H

Next character is:e

Printing all the characters in a string

H

e

l

l

o

G

u

r

u

9

9

!

راه دیگر برای دستکاری رشته ها آرایه ای از اشاره گرهاست که در برنامه زیر می بینیم:

#include <stdio.h>

int main(){

char *materials[ ] = { "iron", "copper", "gold"};

printf("Please remember these materials :\n");

int i ;

for (i = 0; i < 3; i++) {

printf("%s\n", materials[ i ]);}

return 0;}

خروجی:

Please remember these materials:

iron

copper

gold

مزایای اشاره گرها

  • اشاره گرها برای دسترسی به مکانهای حافظه سودمند هستند.
  • اشاره گرها روش کارآمدی برای دسترسی به عناصر یک آرایه فراهم می کنند.
  • اشاره گرها برای اختصاص و آزادسازی حافظه پویا(دینامیک) بکار می روند.
  • اشاره گرها برای تشکیل ساختارهای داده پیچیده مانند لیست پیوندی(linked list)، گراف ، درخت و … بکار می روند.
مطلب پیشنهادی:  آموزش کار با CMake

معایب اشاره گرها

  • درک اشاره گرها اندکی دشوار است.
  • اشاره گرها به خطاهای متعددی مانند segmentation faults منجر شده و یا ممکن است به مکان حافظه ای دسترسی پیدا کنند که اصلا مورد نیاز نبوده است.
  • اگر برای یک اشاره گر مقدار نادرستی فراهم شود، ممکن است منجر به ازبین رفتن حافظه(memory corruption) شود.
  • اشاره گرها همچنین باعث نشت حافظه(memory leakage) می شوند.
  • اشاره گرها در مقایسه با متغیرها کندتر هستند.
  • کارکردن با اشاره گرها برای برنامه نویسان دشوار است؛ این وظیفه برنامه نویس است که اشاره گرها را با دقت بکار بندد.

خلاصه اشاره گر ها در زبان C

  • اشاره گر چیزی جز مکانی از حافظه که داده در آن ذخیره می شود نیست.
  • اشاره گر برای دسترسی به مکان حافظه بکار می رود.
  • اشاره گرها انوع مختلفی مانند اشاره گر null، اشاره گر wild، اشاره گر void و دیگر انواع دارند.
  • اشاره گرها را می توان با آرایه ها و رشته ها برای دسترسی کارآمدتر به عناصر بکار برد.
  • می توان اشاره گرهای تابعی را برای احضار یک تابع به صورت پویا بکار برد.
  • عملیات جبری را می توان روی اشاره گرها بکار برد که محاسبات اشاره گر(pointer arithmetic) نامیده می شود.
  • اشاره گرها همچنین می توانند به یک تابع اشاره کنند که در این صورت فراخوانی توابع مختلف برای تعریف آرایه اشاره گرها آسان خواهد شد.
  • زمانی که بخواهیم با انواع مختلفی از نوع داده کار کنیم، می توانیم از تبدیل داده(typecast) اشاره گر void استفاده کنیم.

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

اگر این نوشته‌ برایتان مفید بود لطفا کامنت بنویسید.

مطالعه دیگر جلسات این آموزش<< جلسه قبلی                    جلسه بعدی >>

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

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

2 دیدگاه

  1. خوب بود ممنون

  2. سلام. خیلی ممنونم بابت آموزش های خوب و کاملتون.
    فقط برام سوال پیش اومد که تفاوت p% با x% در مواقع پرینت کردن اشاره گر ها چیه؟