زبان C – ساختارها (جلسه ۶)
زمان تقریبی مطالعه این مقاله: ۱۰ دقیقه
سلام به میکرولرنیهای عزیز 🙂 🙂 🙂
این مقاله در ۲۴ اردیبهشت ۱۴۰۰ به روز رسانی شده
تا این بخش از آموزشهای زبان C، به بحثهای پایهای پرداختیم که با استفاده از دکمههایی که در ادامه میبینید در بخش یادآوری برای شما قابل دسترسی هستند. اما در این جلسه نوبت به اون رسیده که در مورد ساختار در زبان C صحبت کنیم. معادل ساختار در انگلیسی کلمه structure هست.
ساختار قدرت خیلی زیادی به شما که میخواید به زبان C کد نویسی کنید میده. توضیح دادن ساختار قبل از شرح دادن جزئیات اون کمی سخته اما در همین حد بدونید که میتونید به وسیلهی ساختار خیلی انعطاف پذیرتر با دادهها کار کنید.
لطفا قبل از مطالعه این مقاله، در صورتی که نیاز به یادآوری دارید؛ مباحث زیر را مطالعه کنید:
فهرست مطالب
ساختار – structure
همانطور که تا اینجا آموختیم، آرایهها میتوانند برای جمعآوری گروهی از دادههای هم نوع استفاده شوند؛ اما نمیتوان آرایهای تعریف کرد که مثلا شامل پنج خانه از نوع صحیح و پنج خانه از نوع اعشاری باشد.
از طرفی در کاربردهای مختلف برنامهنویسی نیاز به تعریف کردن عناصر مختلف در کنار هم و نسبت دادن یک نام به همهی آنها است تا بتوان مجموعهی آنها را بهصورت یکجا مورد پردازش (مانند بازنویسی آنها بهصورت یکجا، ارسال کل آنها به یک تابع و یا آمادهسازی و برگرداندن همهی آنها بهعنوان نتیجه یک تابع) قرار داد.
فرض کنید دادههای مربوط به یک دانشجو مثل شماره دانشجویی، نام خانوادگی، نام، جنسیت، تعداد واحد گذرانده شده و معدل کل را که دارای نوعهای متفاوتی هستند را بخواهیم تحت یک نام تعریف کنیم.
یا بهعنوانمثال دیگر، بخواهیم اطلاعات مربوط به کارکنان شرکتی را که شامل نام کارمند (از نوع کاراکتری)، شماره کارمندی (از نوع عدد صحیح)، حقوق (از نوع عدد صحیح) و … است، تحت یک نام ذخیره کنیم، در این صورت متغیر معمولی و آرایه پاسخگوی نیاز ما نیستند.
اکنون میخواهیم بدانیم که چگونه دادههایی را که نوع یکسان ندارند اما به هم دیگر مربوط هستند را تعریف کنیم؟
تعریف ساختار در زبان C
پاسخ این است که میتوان متغیرهایی با نوعهای مختلف را با دادهای به نام ساختار ( structure ) گروهبندی کرد. بنابراین میتوان گفت که ساختار در زبان C، نامی برای مجموعهای از متغیرهاست که این متغیرها میتوانند هم نوع نباشند.
یعنی ساختار میتواند انواع مختلف دادهها ازجمله float, int, char, unsigned char و … را تحت عنوان یک نام در خود داشته باشد و کاربر در هر زمان به آنها دسترسی داشته باشد. قالب تعریف ساختار را در زیر مشاهده میکنیم:
struct [structure tag]{
member definition
member definition
...
member definition
}[one or more structure variables];
- در نوشتن برنامه از [ ] استفاده نمیشود و فقط در این مرحله برای نمایش قالب کلی استفاده شده است.
- نام ساختار یا (structure tag ) از قانون نامگذاری برای متغیرها تبعیت میکند که در مقاله متغیرها به آن اشاره کردیم.
- عضوهای ساختار یا (member)، متغیرهایی هستند که قسمتی از ساختار میباشند و همانند یک متغیر معمولی یا آرایه، باید اسم و نوع هرکدام مشخص باشد.
- لیست نامها یا (structure variables) هم متغیرهایی هستند که قرار است ساختمان این ساختار را داشته باشند.
- برای استفاده از عناصر ساختار معرفیشده باید متغیرهایی از نوع ساختار پس از آن معرفی شود. اگر کمی (فقط کمی 😀 ) گیج شدید، برای رفع گیجی ادامه بحث را دنبال کنید.
روش اول
دو روش برای معرفی متغیرهایی از نوع ساختار وجود دارد. در زیر قالب روش اول را مشاهده میکنید:
struct نام ساختار{
عناصر ساختار
}نام متغیرها;
برای درک روش اول به مثال زیر توجه کنید:
struct student_record{
long student_number;
char first_name[21];
char last_name[31];
char gender_code;
float average;
int passed_units;
}student1;
- در خط یک ساختاری با نام الگوی student record تعریف شده است.
- توجه شود که نام ساختار متغیر نیست بلکه فقط اسمی برای آن ساختار است. مثلا برای دانشجو می توان ساختاری با نام پروفایل دانشجو یا student_profile تعریف کرد.
- حال هر دانشجو به صورت جدا گانه از این ساختار جهت ذخیره اطلاعاتش استفاده میکند. پس باید برای هر دانشجو یک متغیر جدا از نوع این ساختار تعریف شود.
- در خطوط ۲ تا ۷ انواع متغیرهای لازم برای ذخیره اطلاعات پروفایل دانشجو تعریف شدهاند.
- در خط ۸ یک متغیر با نام student1 از نوع ساختار student_record تعریف شده است. پس در حافظه فقط به اندازه همین یک متغیر حافظه اشغال میشود.student1 نام متغیری است با ساختمان این ساختار، که دارای شش عضو است.
- اگر بخواهیم متغیرهای بیشتری از این ساختار تعریف کنیم کافی است آنها را بعد از student1 با کاما از هم جدا کنیم.
- درصورتی که بعد از خاتمهی تعریف ساختار (بعد از { ) نام متغیری نوشته نشود، فقط یک ساختار تعریفشده است و چون متغیری با ساختمان این ساختار تعریف نشده، حافظهای هم اشغال نخواهد شد.
روش دوم
همانطور که گفته شد، اگر متغیری از نوع ساختار نوشته نشود؛ میتوان در ادامهی برنامه از کلمهی struct و نام ساختار برای تعریف متغیرهای موردنیاز استفاده کرد. در زیر قالب روش دوم را میبینید که پس از معرفی ساختار صورت میگیرد:
struct <نام متغیرها> <نام ساختار>;
به این مثال دقت کنید:
struct student_record S1, S2;
- متغیرهایی بانام S1 و S2 از نوع ساختار student_record معرفیشدهاند. هرکدام از این متغیرها حاوی کل ساختار معرفیشده، میباشند.
- توجه کنید که در روش دوم حتما باید ساختار از قبل تعریف شده باشد تا در اینجا بتوان متغیرهایی از نوع آن تعریف کرد.
- هر تعداد متغیر که بخواهیم میتوانیم با کاما جدا کرده و تعریف کنیم.
مقدار دهی اولیه به structure
مقداردهی اولیه به ساختار (مشابه مقداردهی آرایهها) مجاز است. برای مثال ابتدا ساختاری برای ذخیره اطلاعات یک دانشجو را تعریف میکنیم.
struct student{
long int id;
char name[20];
float average;
int age;
};
سپس متغیری از جنس ساختار student با نام s تعریف کرده و به شکل زیر مقدار دهی اولیه میکنیم.
struct student s = {83201012, "ali", 16.90, 19};
در مقداردهی اولیه میتوان مجموعهای از مقادیر را به یک ساختار نسبت داد، ولی انجام چنین کاری در متن برنامه بهصورت دستور اجرایی امکانپذیر نیست.
دسترسی به عناصر ساختار
برای مقدار دهی در حین برنامه یا خواندن مقادیر موجود در ساختار باید به عناصر آن دسترسی داشته باشیم. قالب دسترسی به عناصر ساختار را در زیر مشاهده میکنید:
<نام عناصر موردنظر در ساختار>.<نام متغیر از نوع ساختار>
- نام متغیری از جنس ساختار مورد نظر و نام عضو دلخواه از ساختار با عملگر عضو ساختار که علامت آن نقطه است به یکدیگر مرتبط میشوند.
- این عملگر که دارای بالاترین تقدم عملیات بوده ترتیب اجرایش از چپ به راست است.
- توجه شود که بهصورت قراردادی در دو طرف عملگر نقطه فاصله خالی گذاشته نمیشود.
- اگر عنصر داخلی ساختار از نوع آرایه باشد، ذکر اندیس آرایه جهت دستیابی به آن عنصر ضروری است. برای آشنایی با عملگرها میتوانید مقالهی عملگرها را مطالعه کنید.
- ساختاری با نام student شامل ۴ عضو داخلی برای اطلاعات دانشجو تعریف شده است.
- متغیری بنام s از نوع ساختار student تعریف شده است.
- اکنون متغیر s شامل کلیه عناصر تعریف شده در ساختار مورد نظر است و کامپایلر C بهصورت خودکار حافظه لازم را به این متغیر ساختار اختصاص میدهد.
مثال: اکنون میخواهیم به عناصر متغیر ساختاری s که در مثال قبل تعریف کردیم در میان برنامه مقدار دهی کنیم.
s.id = 990133710;
strcpy(s.name, "reza");
s.average = 17.64;
s.age = 18;
- همان طور که چند خط بالاتر توضیح داده شد، ابتدا نام متغیر ساختاری و سپس نقطه نوشته می شود. بعد از آن نام عنصر دلخواه ساختار نوشته شده و مقداردهی انجام میشود.
- نکته مهم: در خط ۲ نمیتوانیم به رشته name که عضوی از ساختار است به صورت “s.name = “reza مقدار دهی کنیم. چرا که این کار فقط در تعریف اولیه مجاز است.
- بنابراین باید کتابخانه string.h را به برنامه include کرده و از تابع strcpy استفاده کنیم.
تخصیص ساختار در زبان C
تنها عمل تخصیص که در مورد structure در زبان C تعریفشده است، تخصیص یک ساختار به ساختار دیگری با ساختمان دقیقا یکسان (هر دو ساختار از طریق یک struct تعریفشده باشند) است که در این صورت محتویات هر عنصر از ساختار مبدأ به عنصر متناظر از ساختار مقصد منتقل میشود. ساختار مبدأ میتواند متغیری در برنامه یا خروجی یک تابع باشد.
آرایه ای از ساختار ها
در زبان C، نام آرایه را میتوان در مقابل نام ساختار قرار داد تا آرایهای از ساختارها اعلام شود. یکی از بیشترین موارد کاربرد ساختارها، استفاده از آنها بهعنوان عناصری از آرایه است.
برای تعریف آرایهای از ساختارها، ابتدا نوع ساختار را تعریف کرده سپس همانند متغیرهای معمولی، آرایهای از آن نوع ساختار را تعریف میکنیم. برای فهم بیشتر مثال زیر را در نظر بگیرید:
struct student{
char name[21];
int stno;
float ave;
};
struct student st[100];
- در این دستورات، آرایه ۱۰۰ عنصری st طوری تعریف شده که هر یک از عناصر آن، از نوع ساختار student است.
- در هر خانه از آرایه میتوان اطلاعات یک دانشجو را به صورت مجزا ذخیره کرد.
ارسال ساختار به تابع
فراخوانی تابع به معنای ارسال آرگومان به تابع و تحویل گرفتن خروجی است. فراخوانی به دوشکل انجام میشود. فراخوانی تابع با مقدار (call by value) و فراخوانی تابع با ارجاع (call by reference). اگر با بحث تابع در زبان C آشنایی کافی ندارید مقاله تابع را مطالعه کنید.
در فراخوانی تابع میتوان، یک متغیر از نوع ساختار را به عنوان آرگومان ورودی به تابع ارسال کرد. ارسال ساختار به تابع نسخهی کاملی از ساختار را به تابع میفرستد. این کار باعث مصرف حافظه بیشتر و کند شدن برنامه میشود. برای حل این مشکل میتوان از اشاره گر استفاده کرد.
تعریف اشاره گر به ساختار
در زبان C تعریف اشارهگر از نوع ساختار، همانند تعریف سایر انواع اشارهگرها امکانپذیر است. پس همانطور که در فراخوانی تابع میتوان اشارهگری را که به آرایه اشاره میکند ارسال کرد، میتوان اشارهگری را که به ساختار اشاره میکند نیز ارسال کرد.
ارسال اشارهگر به ساختار فقط آدرس ساختار را به تابع میفرستد. سپس تابع میتواند جهت دستیابی مستقیم به اعضای ساختار از آدرس استفاده کند. بنابراین این روش نسبت به ارسال خود ساختار به تابع کارآمدتر است.
وقتیکه ساختارها از طریق فراخوانی به روش ارجاع به توابع منتقل میشوند، سرعت انجام عملیات بر روی آنها بیشتر میگردد. لذادر حین فراخوانی توابع، بهتر است بهجای ساختار، آدرس آن را منتقل نمود.
تعریف اشارهگرهای ساختار مانند تعریف متغیرهای ساختار است، با این تفاوت که قبل از اسم متغیر، علامت * قرار میگیرد. مثال زیر را در نظر بگیرید:
struct bal{
float balance;
char name[80];
}person, *p;
در این دستورات person یک متغیر ساختار و p یک اشارهگر ساختار است.
اکنون دستور زیر را در نظر بگیرید:
p = &person;
با این دستور، آدرس متغیر ساختار person در اشارهگر p قرار میگیرد.
دسترسی به عناصر ساختار با اشارهگر
برای دسترسی به محتویات عناصر ساختار از طریق اشارهگر، باید اشارهگر را در داخل پرانتز قرار داد. به کد زیر دقت کنید:
(*p).balance;
- دستور بالا موجب دسترسی به عنصر balance از ساختار person میشود.
- علت قرار دادن متغیر اشارهگر در پرانتز، این است که تقدم عملگر (.) از * بالاتر است.
بهطورکلی برای دسترسی به عناصر ساختاری که یک اشارهگر به آن اشاره میکند به دو روش میتوان عمل کرد:
- ذکر نام اشارهگر در داخل پرانتز و سپس نام عناصر موردنظر که با نقطه از هم جدا میشوند. (مثل دسترسی به عنصر balance از ساختار person توسط اشارهگر p)
- استفاده از عملگر <- که روش مناسبتری است. اگر بخواهیم با استفاده از عملگر < – به عنصر balance از ساختار person دسترسی داشته باشیم باید به طریق زیر عمل کنیم (علامت <- متشکل از علامت منها و علامت بزرگتر است.)
p -> balance;
تقدم عملگرها
در اینجا بیان این نکته ضروری است که آرایهها، اشارهگرها و ساختارها دارای ارتباط نزدیکی باهم هستند. در ضمن عملگرهای مربوط به آنها شامل زیر نویس یا [ ]، عضو ساختار یا نقطه و دستیابی غیرمستقیم به عضو ساختار یا <- همگی دارای بالاترین تقدم هستند.
عملگرهای دستیابی غیرمستقیم یا * و استخراج آدرس یا & هم دارای تقدم دوم میباشند. حال اگر این عبارتها همراه یکدیگر در عبارتی ظاهر شوند باید کمی با دقت کد مورد نظر نوشته شود.
برای درک بحث گیج کنندهی تقدم ها ( 😀 ) و فهم بیشتر انواع ساختارها به مثال زیر دقت کنید:
struct point{
float x;
float y;
};
struct line{
struct point first;
struct point last;
char name;
}a = {{1, 1},{10, 20}, 'a'};
struct line m[] = { { {2, 3},{4, 5}, 'c'}, { {4, 6}, {8, 1}, 'm'}, { {8, 5},{4, 2}, 'x'} };
struct line *pa = &a;
struct line *pm = &m[1];
- چون در مثال های بالا نکات ریز ساختار کاملا توضیح داده شده است، در این جا قسمت های مهم را توضیح می دهیم.
- در خطوط ۱ تا ۴ ساختاری با نام point تعریف شده ولی هیچ متغیری برایش تعریف نشده است.
- در خطوط ۶ تا ۱۰ ساختاری با نام Line تعریف شده و متغیری با نام a برای آن تعریف و مقدار دهی اولیه شده است.
- دو عنصر اول ساختار line، ساختار point است. پس عناصر یک ساختار می توانند ساختار هم باشند.
- در خط ۱۲ یک متغیر ساختار برای line تعریف و مقدار دهی شده است. در این جا هم متغیر m آرایه ای از ساختار است.
- در خط ۱۴آدرس متغیر a در اشاره گر pa قرار داده شده است.
- در خط ۱۵آدرس خانه دوم آرایه m در اشاره گر pm قرار داده شده است.
با توجه به تعاریف بیان شده و اینکه ترتیب اجرای دو عملگر عضو ساختار و دستیابی غیرمستقیم از چپ به راست است، عبارتهای زیر معادل هستند:
a.first.x
pa->first.x
(a.first).x
(pa->first).x
(*pa).first.x
- خط یک: a متغیری از نوع ساختار line است که به وسیله نقطه به عضو first دسترسی پیدا کردیم. first هم یک متغیر ساختاری از نوع point است که به وسیله نقطه به عضو x آن دسترسی پیدا کردیم.
- خط دو: pa اشاره گر به متغیر ساختاری a است. پس با عملکر <- می توانیم به اعضای آن دسترسی پیدا کنیم.
- با توجه به توضیحات داده شده سایر خط ها را برای خودتان تفسیر کنید. اگر سوالی داشتید حتما در بخش نظرات بپرسید.
دو عبارت زیر نیز یک معنی میدهند:
m[1].last.y
pm->last.y
- در خط یک: دستیابی از طریق اندیس خانهی یکم آرایهی m که یک ساختار است به عضو last و سپس به عضو y انجام شده است.
- در خط دو: دستیابی به عضو last از طریق آدرس خانهی یکم آرایهی m که در متغیر pm قرار دارد انجام شده است.
سخن آخر
خسته نباشید میگم به میکرولرنی های قوی 🙂
مقاله ساختار در زبان C هم به پایان رسید. کمی که تمرین کنید تمام مفاهیمش خوب توی ذهنتون شکل میگیره. یادتون نره که باید برنامه نویسی رو پای لپ تاپ یا سیستمتون تمرین کنید. فقط خوندن قوانینش نمیتونه کمک کننده باشه. برای جلسه بعد میخوایم روی انواع عملگرها در زبان C کار کنیم.
راستی یه پیشنهاد ویژه دارم برای اون دسته از دوستانی که علاقه دارند خیلی عمیقتر زبان C را یاد بگیرن و برای میکروکنترلرها یا کارهای نرم افزاری ازش استفاده کنند. دوره جامع زبان C را براتون تهیه کردم که فوق العاده پروژه محور و کاربردیه. خوش حال میشم در اون دوره شما رو ببینم. برای دسترسی به دوره میتونید روی عکس زیر کلیک کنید.
درباره احسان عبداللهی
مدیر و موسس میکرولرن | برنامه نویسی پاسخی ظریف به یک نیاز در دنیای واقعی هست.
نوشته های بیشتر از احسان عبداللهیمطالب زیر را حتما مطالعه کنید
دوره های آموزشی مرتبط
آموزش جنگو
آموزش پایتون
آموزش الگوریتم و فلوچارت – تفکر برنامه نویسی
آموزش برنامه نویسی C برای میکروکنترلر
آموزش الکترونیک دیجیتال
23 دیدگاه
به گفتگوی ما بپیوندید و دیدگاه خود را با ما در میان بگذارید.
عالی بود دمت گرم
سلام ممنون از آموزش هاتون.
من میخوام برای میکرو کد بزنم و به یه مشکلی خوردم:
میخوام بنویسم که هر وقت پیام “Led On” را میکرو فرستاد led من روشن بشه.
البته میخوام دوتا میکرو stm32 را با uart به هم وصل کنم ولی توی این تیکه اش موندم که وقتی رسیو کردم چجوری این عبارت بالا رو بهش بفهمونم
سلام
کار سختی نیست. شما زمانی که uart دیتا دریافت کرد اون را داخل یک رشته ذخیره کنید. حالا باید با رشته “led on” مقایسه کنید. اگه منطبق نبود که هیچ وگرنه led را روشن کنید. برای درک بهتر باید روی زبان C و رشته ها کار کنید. توی دوره جامع زبان C مثال های زیادی زدیم که میتونه به شما کمک کنه. پیشنهاد میکنم این دوره را تهیه کنید و در کنار کارهاتون دانش زبان C را ارتقا بدید.
https://microlearn.ir/product/c-prog-micro
سلام ، ممنون بابت اموزش نابتون 🙂
ارایه m در ساختمان line نباید بصورت دو بعدی تعریف میشد ؟
سلام
ممنون از لطف شما. خیر نیازی به دو بعدی بودن نیست. چرا که هر عضو آرایه یک متغیر از نوع ساختار است. در واقع در آرایه یک سطر داریم که در هر خانهی آن یک ساختار قرار داده ایم. میتونید در محیط code blocks تست کنید.
سلام یه سوال
چطوری میشه تابعی ساخت که ورودی آن یه ساختار باشد؟
سلام.
پارامتر ورودی را باید از نوع ساختار تعریف کنید
سلام متن مفید و عالی.تشکر.struct چه میزان حافظه اشغال می کند؟
سلام و درود
این سوال خیلی کلیه. بستگی داره چه میزان متغیر داخلی داره و چه میزان متغیر از نوع ساختار تعریف می کنید.
سلام چطوری دوتا استراکچر رو باهم مقایسه کنیم
سلام. باید حلقه بزنید
با سلام و خسته نباشید خدمت شما.
مطالب و اموزش هاتون واقعا خوب و مفید ولی مثالها کمه.میشه لطف کنید تعدادی سوال و تمرین بذارید برای حل کردن که یه مقدار عملی هم کار کنیم و فقط تیوری نباشه.
ولی در کل خیله سایتتون خوبه و مرسی بابت اموزش ها.
سلام دوست عزیز
توجه کنید که مطالبی که برای شما تهیه شده به صورت رایگان هست. تمرین های بیشتر در قالب رایگان قابل ارائه نیست. میتونید برای تمرین های و دوره های عملی و پیشرفته در دروره های آموزشی vip ما شرکت کنید.
بسیار عالی بود
سپاس از شما
نسبت به اشاره گر و تابع که عالی آموزش دادین، این خیلی عالی نبود.
منظور از آرایهای از ساختارها
یعنی الان میتونیم آرایه ای داشته باشیم که همه نوعی رو داره ؟
که قبلا گفتین آرایه فقط یک نوع رو میتونه داشته باشه.
سلام
خیر. با دقت بیشتری بخونید. اینجا آرایه ای از ساختارها داریم و با آرایه های معمولی فرق داره.
سلام ، ممنون مهندس ، واقعا فکرم از مطالب تون بازتر شد و بهتر تونستم درک کنم ، فقط مونده کمی تمرین کنم تا برام جا بیفته —>>>ضمنا این مطالب شما رو درسایتی دیدم ک بدون اینکه نامی از سایت شما بیاره ب عنوان منبع مطالبش ،، واو ب واو مطالبتون رو کپی کرده بود —>>>
براشون متاسفم .
درود
از نظرتون متشکرم. حتما با مرور و تمرین، بهتر مطالب را فرا خواهید گرفت. در خصوص توجه شما به حق نشر مطالب هم متشکرم. از طریق ادمین سایت مورد نظر در حال پیگیری هستیم. موفق باشید
سلام
آیا هر structcher variable باید حاوی تمام اعضای استراگچر باشه؟ مثلا” ۱۰ متغیر برای یک استراکچر تعریف کردیم و مثلا” ۳ تا structcher variable . در این حالت هر کدوم از این structcher variable ها باید دیتای هر ۱۰ متغیر رو در خودشون ذخیره کنند؟ یا میشه مثلا” ۵ تا بگیرن و خطا بوجود نیاد
اگر بشه اموزش هاتون رو بصورت pdf در بیارید عالیه . خیلی اوقات اینترنت درست حسابی نداریم به سایتتون سر بزنیم . ممنون از اموزش خوبتون
سلام وقت بخیر
عالییییییییییییییییییییییییییییییییییییییی بود….ولی ساختار خیلی گیج کنندس
سلام – مطلب خوبی نوشتی داش – ممنون.
لطف داری عزیز 🙂