زبان C – اشاره گرها (جلسه ۳)
زمان تقریبی مطالعه این مقاله: ۷ دقیقه
سلام به دوستان میکرولرنی فعال 🙂 🙂 🙂
این مقاله در ۱۶ اردیبهشت ۱۴۰۰ به روز رسانی شده.
نوبت رسید به جلسه سوم از زبان C که قولشو داده بودم. در این جلسه میخوایم در مورد مبحث زیبا و البته خیلی مهم اشاره گر در زبان C صحبت کنیم. کار با اشارهگر برای کسی که به زبان C کد میزنه، از نون شب واجب تره پس سعی کنید خیلی خوب یادش بگیرید. قبل از هرچیز بگم که اگه علاقه دارید این جلسه را خوب یاد بگیرید؛ بهتره مطالب جلسه قبل (متغیر در زبان C) رو به خوبی بلد باشید. اگه آمادهاید با میکرولرن، مرجع برنامه نویسی C همراه بشید تا شروع کنیم.
فهرست مطالب
مروری بر متغیر
جلسه قبل به انواع متغیر در زبان C اشاره شد. بیان شد که دادههای ساده میتوانند شامل کاراکتر، عدد صحیح، عدد اعشاری و اشاره گر باشند. دادهها در حافظه نگهداری میشوند و هر خانهی حافظه هم یک آدرس مشخص دارد. وقتی یک متغیر برای ذخیره کردن دادهای خاص تعریف میشود، در واقع نام آن متغیر یک اسم مستعار برای آدرس آن متغیر در حافظه است. دانستن نام متغیر این امکان را فراهم می کند تا بدون درگیر شدن با آدرس در حافظه، بتوان داده را ذخیره یا بازیابی کرد.
فرض کنید مقدار ۱۰ در متغیری با نام a که آدرس آن خانه ۸۰F(عدد هگزا دسیمال است) حافظه است ذخیره شده است. a یک نام مستعار برای خانه ۸۰F حافظه است. چیزی که برنامه نویس در عمل با آن کار میکند a و نه ۸۰F است.
برای درک بهتر به مثال زیر دقت کنید:
int height = 8;
در این مثال محلی از حافظه که ۲ بایت ظرفیت دارد(چون متغیر int دو بایت فضا اشغال میکند) برای ذخیره سازی عدد ۸ در نظر گرفته شده است.(نام این محل در حافظه height است) آیا معلوم است آدرس متغیر height کجای حافظه قرار دارد؟
مشخص است که مکان آن نامعلوم است و البته دانستن آن هم اهمیتی ندارد.
تا این جا مشخص شد که اگر نوع متغیر معلوم شود؛ میتوان بدون دانستن آدرس حافظه مقدار دلخواه را در آن ذخیره کرد.
اما نوع دیگری از دادههای ساده به نام اشاره گر وجود دارد. این نوع از داده چیست و چه کاربردی دارد؟
اشارهگر در زبان C
گاهی در برنامه نویسی لازم است به جای نام متغیر با آدرس متغیر کار کرد. اشارهگرها یا pointerها میتوانند آدرس یک متغیر از حافظه (که یک مقدار عددی است) را در خود نگه دارند. اشاره گر در زبان C کاربرد فراوانی دارد، بهطوریکه اغلب قابلیتهای زبان C به نقش اشارهگر در این زبان بر میگردد.
همانند سایر دادههای ساده که ابتدا نیاز به تعریف داشتند، اشاره گر هم باید تعریف شود. نحوهی تعریف اشاره گر بدین صورت است:
<نام اشاره گر>* <نوع اشاره گر>;
ابتدا باید نوع اشاره گر مشخص شود. نوع اشاره گر می تواند char یا int یا float یا دادههای مرکب باشد. با معین کردن نوع اشاره گر مشخص میشود که اشاره گر به چه نوع متغیری اشاره می کند.
برای فهم موضوع به مثال زیر دقت کنید:
char *pointer;
در این خط متغیری با نام pointer اعلان شده است که از نوع اشاره گر به یک متغیر char است.
مقدار دهی به اشاره گر
آیا با خود فکر کردهاید که چگونه میتوان به این متغیر مقدار دهی کرد؟
برای این منظور، ابتدا باید یک متغیر از نوع char تعریف شده باشد. به مثال زیر دقت کنید:
char alphabet = 'A';
char *pointer;
pointer = &alphabet;
- در خط یک متغیری از نوع کاراکتر با نام alphabet تعریف شده و کد اسکی کاراکتر A در آن ذخیره شده است.
- در خط دو متغیری با نام pointer از نوع اشاره گر به یک متغیر char تعریف شده است.
- در خط سه آدرس متغیر alphabet توسط عملگر آدرس (&) استخراج شده و در اشاره گر pointer ذخیره شده است.
روش مقدار دهی به اشاره گر بدین شکل است. یعنی باید از عملگر آدرس (&) استفاده کرد.
انطباق نوع اشاره گر و متغیر
توجه شود که نوع اشاره گر در زبان C و متغیری که به آن اشاره میکند باید یکسان باشد. به مثال زیر دقت کنید:
char alphabet = 'A';
int *pointer;
pointer = &alphabet;
- در خط یک متغیری از نوع کاراکتر تعریف مقدار دهی شده است
- در خط دو متغیری با نام pointer از نوع اشاره گر به یک متغیر int تعریف شده است.
- در خط سه اشاره گر مقداردهی شده است. اما این مقدار دهی اشتباه است، چرا که اشاره گری از نوع int به متغیری از نوع char اشاره میکند.
می توانید دلیل اشتباه بودن را توضیح دهید؟ اگر صبر کنید، تا انتهای این پست پاسخ را خواهید یافت.
دسترسی به اشاره گر
تا این جا نحوه مقدار دهی اشاره گر در زبان C بیان شد. اما دسترسی به محتوای آن ها چگونه است؟
برای دسترسی به محتوای اشاره گرها باید از عملگر ستاره (*) استفاده شود. این عملگر محتوای اشاره گر (محتوای خانهای که اشاره گر به آن اشاره می کند.) را استخراج می کند. برای درک بهتر به مثال زیر توجه کنید :
int *x;
int z, y;
y = 142;
x = &y;
z = *x;
- در خط یک اشاره گری از نوع int تعریف شده است.
- در خط دو متغیرهای z و y از نوع int تعریف شده اند.
- در خط سه متغیر y با عدد۱۴۲ مقدار دهی شده است.
- در خط چهار آدرس متغیر y درون اشاره گر x قرار داده شده است.
- در خط پنج محتوای خانهای که اشاره گر x به آن اشاره میکند (x به آدرس متغیر y اشاره میکند) درون متغیر z قرار داده شده و z دارای مقدار ۱۴۲ می شود.
عملیات روی اشاره گرها
در این قسمت میخواهیم انواع عملیات مجاز بر روی اشارهگرها را بهصورت مختصر مرور کنیم:
تخصیص
میتوان مقدار یک اشارهگر را به اشارهگر دیگر اختصاص داد، البته نکتهی مهم آن است که باید هم نوع باشند. دو اشارهگر غیر هم نوع را نمیتوان به هم تخصیص داد مگر اینکه از type casting استفاده کنیم. برای مثال اگر ptr اشاره گری از نوع char و p اشاره گری از نوع int باشد، p = ptr اشتباه بوده و باید به شکل p = (int *)ptr نوشته شود که type casting نام دارد.
type casting یا شکل دهی نوع باعث می شود تا داده ای از یک نوع، مشابه داده ای از نوع دیگر عمل کند. برای درک این موضوع، ابتدا به مثال زیر دقت کنید:
float x;
x = 7/2;
- در خط یک متغیر x از نوع float تعریف شده است.
- در خط دو حاصل تقسیم ۷ بر ۲ به x تخصیص داده شده است. آیا مقدار x عشاری خواهد بود؟
- خیر مقدار x صحیح است، چرا که مقسوم و مقسوم علیه صحیح هستند. پس راه حل در چیست؟ باید از type casting به شکل زیر استفاده کنیم:
float x;
x = (float)7/2;
- در این حالت وجود float باعث cast کردن شده و در واقع به حالص تقسیم ۷ بر ۲ شکل می دهد و مقدار اعشاری در x قرار می گیرد.
توجه شود که نوعهای مقادیر معمولی با اشارهگر تفاوت اساسی داشته و به همین دلیل تخصیص یک مقدار غیر اشارهگر به یک مقدار اشارهگر کار صحیحی نیست.
تنها تخصیص مجاز از این نوع تخصیص صفر به اشارهگر است. درواقع کامپایلر زبان C تضمین میکند که محلی با حافظه صفر در حافظه برنامه موجود نبوده و این تخصیص به معنای این است که اشارهگر بهجای خاصی اشاره نمیکند.
مقایسه
میتوان برای بررسی خالی بودن یا نبودن یک اشارهگر آن را با صفر مقایسه کرد و این عملیات مجاز است. البته به جای صفر از ثابت نمادی NULL استفاده میشود که در فایل سرآمد stdio.h موجود است. (فایل های سرآمد یا سرآیند یا header کتابخانه های استاندارد زبان سی هستند که در تمام کامپایرها موجود بوده و شامل توابع و ثابت های پرکاربرد و استاندارد زبان سی میباشند.)
عمل مقایسه دو اشارهگر هم امکانپذیر است، البته به شرطی که هر دو اشارهگر به خانههای یک آرایه اشاره کنند. اما اگر دو اشارهگر که به خانههای دو آرایه مختلف اشاره میکنند باهم مقایسه شوند نتیجهای غیر قابل پیشبینی رخ خواهد داد.
برای آشنایی با آرایهها میتوانید به جلسه آرایه مراجعه کنید.
افزایش و کاهش با یک عدد
برای آشنایی با عملگرها می توانید مقاله عملگرها در زبان C را مطالعه کنید. عملیات جمع (+)، تفریق (-)، افزایش یک واحدی (++) و کاهش یک واحدی (–) را میتوان روی متغیرهای اشارهگر انجام داد. چون اشارهگر حاوی آدرسی در حافظه است وقتی محاسباتی روی آن انجام میگیرد رفتار متفاوتی نشان میدهد.
اگر a یک مقدار مثبت فرض شود. وقتی عمل جمع a با متغیر اشارهگر صورت میگیرد، اشارهگر به اندازه ی a*(تعداد بایتهای نوع دادهای که اشاره گر به آن اشاره میکند) جلو میرود. گیج کننده بود؟ 😉 پس به مثال زیر دقت کنید:
int *p, a;
p = &a;
p = p+4;
- در خط یک متغیر a و اشاره گر p از نوع int تعریف شده اند.
- در خط دو آدرس متغیر a درون اشاره گر p قرار داده شده است.
- در خط سوم اشاره گر p با ۴ جمع شده است. p از نوع int و دو بایتی است. پس هنگامی که با ۴ جمع می شود به اندازه ۴*۲ یعنی ۸ بایت جلو می رود.
- توضیح بیشتر: اشاره گر int آدرس متغیرهای دو بایتی را در خود نگه می دارد. وقتی با ۴ جمع می شود منظور آن است که به ۴ آدرس جلوتر اشاره کن و هر آدرس هم ۲ بایت را اشغال می کند. پس حاصل جمع با ۴ به ۸ بایت جلوتر اشاره می کند.اگر آدرس متغیر a برابر با ۱۰۰۰ باشد. حاصل این جمع برابر با ۱۰۰۸ می شود.
حال می توانید جواب سوال بالا را بدهید.چرا باید اشاره گر و متغیری که به آن اشاره می کند از یک نوع باشند؟ برای پاسخ از مثال بالا کمک گرفته می شود. اگر اشاره گر از نوع char بود، حاصل جمع به ۴ بایت جلوتر اشاره می کرد. در واقع معیار اشاره گر در این حالت خانه های یک بایتی است در حالی که متغیر مورد نظر دو بایتی است.
عملگر افزایش یک واحدی (++) مقدار متغیر معمولی را یکی اضافه میکند درحالی که متغیر اشارهگر را به تعداد بایتهای نوع داده آن حرکت میدهد. مثلا برای اشارهگر به نوع دادهی float ،چون float چهار بایت دارد با افزایش اشارهگر ۴ واحد به آن اضافه میشود. بنابراین به ۴ بایت بعدی حافظه اشاره میکند.
تفریق
میتوان تفاضل دو اشارهگر را به دست آورد. البته شرط اصلی آن است که هر دو به خانههای یک آرایه اشاره کنند و نتیجه آن تعداد خانههای موجود بین دو خانه مورد اشاره است. درصورتیکه دو اشارهگر به خانههای دو آرایه مختلف اشاره کنند نتایج غیرقابلپیشبینی رخ خواهد داد.
چاپ
میتوان محتویات یک اشاره کر را با مشخصه تبدیل فرمت d% بهصورت عدد صحیح مبنای ده چاپ کرد که البته روش استانداردی نیست. میتوان اشاره کر را به مشخصه تبدیل فرمت p% در قالب عددی در مبنای ۱۶ چاپ کرد و این مشخصه تبدیل فرمت برای اشارهگرها همواره درست است.
لازم است این نکته توضیح داده شود که مشخصه تبدیل فرمت از مباحث بسیار مهم در زبان C بوده و در جلسه معرفی توابع می توانید درباره تبدیل فرمت مطالعه کنید.
عملیات غیر مجاز
بهجز عملهایی که به آنها اشاره شد، انجام هرگونه عمل دیگری بر روی اشارهگرها اشتباه بوده و کامپایلر زبان C آن را خطا در نظر میگیرد؛ مثلاً اشارهگرها را نمیتوان باهم جمع یا در هم ضرب کرد. یا آنها را در عملهایی مانند شیفت نمیتوان استفاده کرد.
سخن آخر
جلسه اشاره گر در زبان C کمی طولانی شد اما مطالب مهمی بود که باید یاد میگرفتید. تعریف و مقدار دهی اشاره گر، خواندن مقدار موجود در اشاره گر و ریزه کاریهای دیگه. البته اصلا انتظار نداشته باشید که با یک بار خوندن این مقاله همه چیز را یاد بگیرید. حتما لازمه چند بار بخونیدش و بعد هم خودتون تمرین کنید تا مسلط بشید. جلسه آینده میریم سراغ آرایهها و حسابی باهاشون وارد چالش میشیم. خسته نباشید دوستای خوبم 🙂
اما برای کسانی که دوست دارن زبان C را خیلی عمیقتر و حرفهایتر کار کنند تا از اون در میکروکنترلرها، کارهای نرم افزاری و پروژههای دانشگاه و … بتونند به خوبی استفاده کنند دوره حرفهای زبان C میکرولرن را پیشنهاد میکنم. برای اطلاع از جزئیات دوره روی تصویر زیر کلیک کنید.
درباره احسان عبداللهی
مدیر و موسس میکرولرن | برنامه نویسی پاسخی ظریف به یک نیاز در دنیای واقعی هست.
نوشته های بیشتر از احسان عبداللهیمطالب زیر را حتما مطالعه کنید
دوره های آموزشی مرتبط
آموزش جنگو
آموزش پایتون
آموزش الگوریتم و فلوچارت – تفکر برنامه نویسی
آموزش برنامه نویسی C برای میکروکنترلر
آموزش الکترونیک دیجیتال
24 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
خداقوت بابت مطلب مفیدتون ، در مورد اینکه آدرس یک بخش از حافظه را توسط اشاره گر بخوانیم و مقدار دهی کنیم میتونین بهم کمک بکنین؟
سلام
ممنونم از شما
سوالتون را با جزئیات کافی مطرح کنید تا پاسخ داده بشه.
تونستم به خوبی مرور کنم. ممنون
سلام مهندس
خدا قوت خیلی عالی توضیح دادیند
اگه امکان داره مطالب بیشتری را در قالب فایل اموزشی ارایه دهیند حتما استقبال خوبی میشه
ممنون
تشکر بسسسسسسسسسسسسسسسسسیار فراوان.دوست عزیز
خوشحالم که براتون مفید بوده.
بسیار بسیار روان و شیوا توضیح دادید ، متشکر از زحمات شما.
مرسی از مطالب خوبتون
و این که شما نمیدونید دلیل اینکه چرا وقتی دارم با گوشیم کامنت میذارم این عکس که نمیدونم از کجا اومده روی کامنتم میاد؟؟ عصبی میشم اینو میبینم
اگه ثبت نام کرده باشید این عکس را موقع ثبت نام روی پروفایل قرار دادید. می تونید حذفش کنید.
سلام.خیلی عالی توضیح دادی، خدا خیرت بده …
سلام و تشکر از زحماتتون و سایت خوبتون.من همرو فهمیدم فقط نمیفهمم اشاره گر به چه دردی میخوره وقتی همه کارارو میشه با متغیر ها انجام داد ؟ ممنون میشم پاسخ بدید
با سلام
حتما پست های بعدی در خصوص رشته ها، آرایه ها، ساختار و توابع را به دقت مطالعه کنید. مفصل توضیح داده شده. از همراهیتون متشکریم
جناب عبداللهی عزیز خیلی از مطالب مفیدی که قراردادین سپاسگزارم
از خداوند بهترین ها را برایتان آرزو دارم
دوست عزیز خوشحالم که این مطلب تونسته کمکی به شما کنه
عالی بود اما کم. یعنی نیاز به توضیح بیشتر داشت.
من در کنارش، ۲ بخش اول این رو هم
http://www.cplusplus.com/doc/tutorial/pointers/
خوندم تا بهتر متوجه بشم.
سلام این قضیهfloatو۱۰۰۰واقعا نفهمیدم دوباره توضیح میدین توی قسمت اخر که به جمع و تفریق اشاره میکنه؟
سوال دوم اینه که من متن فهمیدم ولی واقعا مفهوم اشاره گر و مشخص شدن ادرس حافظه گه گفتین یه عدد هست رو نفهمیدم.چیزی که من درک کردم اینه که اشاره گرها صرفا یک متغیر واسطه هستن
درود
بسیار روان توضیح داده شده. اگ متوجه نشدید حتما چند بار با دقت کافی مطالعه کنید. اگه اون وقت ابهامی باقی مونده بود مطرح کنید
انواع داده از نوع شمارشی (enum) رو تو آموزش های خوبتون از قلم انداختید جناب مهندس.
بله درست می فرمایید. البته ما هدفمون ارائه مهمترین نکات زبان سی در تعدادی جلسه محدود بود. انشالله به زودی آموزش های ویدیویی جامع تهیه میشه و اطلاع رسانی میشه.
واقعا عالی توضیح میدید . هر ابهامی که یک فرد میتونه داشته باشه رو رفع میکنید . واقعا تشکر میکنم به خاطر حوصله و دقتی که در تالیف مطالبتون صرف میکنید .
هدف ما اینه که به ساده ترین زبان، مطالب را برای شما توضیح بدیم تا ابهامی باقی نمونه و بتونید راه را بهتر پیش برید. حتما اگه سوالی براتون پیش اومد در بخش نظرات مطرح کنید تا پاسخ داده بشه.
بسیار عالی اگه امکان داره مطالب را هم در تلگرام بزارید
می تونید از مطالب ما در کانال تلگرام هم استفاده کنید.
https://telegram.me/microlearn