اشاره گرها در سی

چرا از اشاره گر استفاده کنیم؟ اول, با استفاده از اشاره گرها می توانید در درون توابع خود مقدار آرگومان های ورودی به تابع رو عوض کنید. دوم, اشاره گر ها از تخصیص حافظه پویا پشتیبانی می کنند. سوم, با استفاده از اشاره گرها می توانید نحوه ی کار یک زیربرنامه رو بهبود ببخشید و در آخر با استفاده از اشاره گرها می توانید ساختمان داده های پویا از قبیل, درخت های دودویی, لیست های پیوندی و… درست کنید.همانطور که در کتاب مرجع سی گفته شده اشاره گرها ابزار بسیار قدرتمندی در زبان سی هستند ولی یکی از پرخطرترین ویژگی های آن هم هستند. برای مثال درصورت استفاده نادرست از اشاره گرها برنامه شما ممکن هست crash کند.در زبان سی هر متغیری که تعریف می‌شود یک محتوا و یک آدرس دارد و شما می‌توانید به محتوای آن با نوشتن نام آن و با نوشتن & قبل از نام آن به آدرس آن متغیر دسترسی پیدا کنید. (البته توابع هم دارای آدرس هستند ولی موضوع بحث فعلی ما نیست)اشاره گر ها متغیر هایی هستند که در آن‌ها آدرس قرار می‌گیرد(در واقع آدرس متغیر های دیگه یا به گفته کتاب مرجع سی, شی های دیگر) و باید در تعریف آن‌ها به طور صریح بگویید که این متغیر از نوع اشاره گر می‌باشد و همچنین بگویید که آدرس چه نوع داده‌ای در آن قرار می‌گیرد.(برای این باید به طورصریح بگویید که این متغیر به چه نوع متغیری اشاره می کند که در هنگام استفاده از اپراتور های ریاضی کامپایلر تشخیص دهد که برای مثال متغیری که بهش اشاره کردیم چقدر فضا گرفته است و چقدر باید بخونه)برای تعریف اشاره گرها به صورت زیر عمل می کنیمtype *name;که در آن type نوع های اولیه زبان سی و یا هر نوع داده ای معتبر در سی (مثل, int, float, structو…) می تواند باشد. در واقع در سی هرنوع داده ای اشاره گری می تواند به هرجایی از حافظه که بخواهد اشاره کند اما اعمال انجام شده بر روی آن ها باتوجه به نوع پایه (همون type) انجام می گیرید. برای مثال اگر یک متغیر را اشاره گری به نوع int تعریف کنید, یعنیint *pint;صرف نظر از آنکه pint به کجا اشاره می کند, کامپایلر فرض می کند که آن به یک عدد صحیح(که بیشتر سیستم های امروز ۴ بایت در نظر می گیرند) اشاره می کند.(یعنی کامپایلر هیچ اهمیتی نمیده که در اونجای حافظه شما واقعی عدد صحیح گذاشتید یا نه)اپراتور های اشاره گری دوتا هستند. * و & (که در باره & قبل گفته شده است). اپراتور * مکمل اپراتور & است و در واقع مقدار متغیری که ما بهش اشاره می کنیم رو برمی گردونه. برای مثال فرض کنید کد زیر را نوشته ایمint a = 1,b; int *pa; pa = &a; b = *pa;حال فرض کنید متغیر a در آدرس خانه 1000 و متغیر b در ادرس 1004 ذخیره شده باشند.با اجرای خط pa = &a; مقدار متغیر pa می شود آدرس a که همان1000 است.(یعنی الان اگر pa را با printf چاپ کنید عدد 1000 رو صفحه نمایش چاپ میشه)حال *pa یعنی مقدار جایی که pa دارد به آن اشاره می کند. چون pa به a اشاره می کنه وقتی *pa بنویسید نتیجه میشه مقداری که در a است که در اینجا میشه 1.تفاوت تعریف متغیر از نوع اشاره گر و متغیر های عادی در این است که متغیر های اشاره گری در خود آدرس داده‌ای از همان نوع که تعریف شده‌اند را در خود قرار می‌دهند اما متغیر های عادی داده‌ای از همان نوع را در خود قرار می‌دهند. در مثال بالا متغیر pInt آدرس مکانی که یک عدد صحیح در آنجا است را در خود قرار می‌دهد نه یک عدد صحیح عادی را.(درواقع خود آدرس ها هم عددی صحیح هستند)شما می توانید اشاره گرها را به یکدیگر انتساب کنید, از یکدیگر کم کنید, به آن ها عددی اضافه و یا کم کنید اما اشاره گرها را نمی توانید بایکدیگر جمع کنید پس عملیات زیر یک خطای کامپایل استint *a, *b, *c; c = a+b;اما اعمال زیر صحیح می باشدc = b – 1; c = --b; c = b – a;حال به عکس های زیر توجه کنیدوقتی یک متغیر تعریف می‌کنید و آن را مقدار دهی نمی‌کنید معلوم نیست چه مقداری در آن قرار می‌گیردو وقتی یک متغیر از نوع اشاره گر تعریف می‌کنید در آن NULL قرار می‌گیرد و این یعنی که آن متغیربه هیچ جا اشاره نمی‌کند. وقتی می نویسید type var; به اندازه sizeof(type) کامپایلر فضا می‌گیرد اما وقتی می نویسید type *var; کامپایلر به اندازه سیستم آدرس دهی کامپیوترتان (به طور معمول ۴ بایت و یا ۸ بایت) فضا می‌گیرید چون در این نوع متغیر قرار است آدرس یک خانه‌ای از حافظه قرار گیرید.حال به عملگر های ++ و –- و sizeof دقت کنید.فرض کنید متغیر و اشاره گری به آن به صورت روبرو تعریف شده باشد type var; type *pVar = &var;حال اگر بنویسید pVar += number و فرض کنید مقدار X در pVar باشد آنگاه مقدار جدید pVar می‌شود X + sizeof(type) * number یعنی pVar به number خانه بعد از خود اشاره می‌کند.حال اگر بنویسید(*pVar) + numberآنگاه مقدار آنجایی که pVar به آن اشاره می‌کند (در این مثال مقدار var) number واحد افزایش می‌یابد.به شکل زیر دقت کنید