FPGA, آموزش میکروبلیز و زبان C, توصیه شده, مقاله

آموزش میکروبلیز قسمت ششم : آموزش زبان برنامه‌نویسی C

آموزش میکروبلیز از مبتدی تا پیشرفته

بسم‌الله‌الرحمن‌الرحیم

اگر تاکنون این سری از آموزش‌ها را دنبال کرده باشید به مباحثی از زبان برنامه‌نویسی C از جمله متغیر‌ها، کلاس‌های حافظه، عملگر‌ها، رشته‌ها، آرایه‌ها و کاراکتر‌ها پرداختیم که توصیه می‌کنم حتما مقالاتی که نوشته شده‌اند حتی در صورتیکه فکر می‌کنید به این مباحث مسلط هستید مجددا بخوانید (یاداوریش که ضرر نداره). حال در این مقاله می‌خواهیم به مبحث بسیار کاربردی و همینطور خطرناک حلقه‌ها بپردازیم. حالا چرا خطرناک؟ برای جواب به این سوال توصیه می‌کنم که این مقاله را تا انتها بخوانید.

حلقه در زبان برنامه‌نویسی C چیست؟

اجازه دهید این قسمت را با ذکر یک مثال توضیح دهیم. فرض کنید به شما گفته شده است برنامه ای بنویسید که یک عبارت دلخواه را  1000 بار در خروجی چاپ کند. یکی از روش ها این است که عبارت موردنظر را هزار بار در برنامه بنویسیم که این عمل، بسیار حجم کد را بالا می‌برد و همچنین خوانایی برنامه را به شدت پایین می‌آورد. روش دیگر استفاده از دستور goto است ( دقت کنید قبل از اینکه از حلقه‌ها در برنامه‌ استفاده کنند از goto استفاده می‌شده و البته همچنان هم می‌توان از این دستور استفاده کرد البته به شرط استفاده رو به جلو یعنی اینکه رو به عقب پرش انجام ندهیم که شرایط خاص خودش رو داره که اینجا بحث ما نیست.) به این ترتیب که در برنامه بگوییم از خط 1 به خط 20 پرش را انجام دهد و مجددا همین روند صورت گیرد و یا به خط دیگری از برنامه رود که این روش هم اصلا استاندارد نیست و ترجیحا در برنامه‌هایتان در صورتیکه پرش به خطوط قبل می‌خواهید انجام دهید اصلا و ابدا این کار را انجام ندهید و فقط طبق استاندارد MISRA-C پرش رو به جلو توسط این دستور اشکالی ندارد.( میدونم بخشیش جدید بود و براتون خیلی سوال پیش اومده ولی اینجا اگه بخوام توضیح بدم کلا رشته کلام از دستم میره فقط به عنوان راهنمایی اگر خیلی کنجکاوید مبحث MISRA-C رو سرچ کنید.) خب طبق توضیحاتی که دادیم از این دستور هم نمی‌توان به صورت کلی استفاده کرد و در اینجا بود که مفهوم حلقه ایجاد شد. و همچنان هم از این مفهوم به روش های متفاوت در برنامه‌نویسی استفاده می‌کنند.

در واقع اگر بخواهیم حلقه را تعریف کنیم. باید بگوییم یک گوی را که دارای یک نقطه شروع و پایان است، را در نظر بگیرد وسپس گوی را بچرخانید (با فرض چرخش محدود گوی). چیزی که مشاهد می‌کنید این است که این توپ دائما از نقطه شروع به نقطه پایان می‌رود و این کار به صورت مداوم در حال انجام است تا زمانیکه چرخش به اتمام رسد. در حلقه‌ها هم دقیقا همین امر صدق می‌کند دقیقا از یک نقطه شروع به کار می‌کنند تا زمانیکه به نقطه پایان برسند و مجددا این روند تکرار می‌شود. حال اگر تعداد تکرار در حلقه مشخص شده باشد که چه مقدار باید از نقطه شروع تا پایان، این تکرار صورت گیرد را، حلقه‌های محدود یا Finite می‌گوییم و اگر این تعداد تکرار در حلقه نامشخص باشد به این معنی که تعداد تکرار شروع و پایان  محدود نباشد را حلقه Infinite یا بی‌نهایت (نامحدود) می‌گوییم (امیدوارم که تونسته باشیم این مفهوم رو به درستی انتقال داده باشیم). خب پس از اینکه با مفهوم حلقه و دلیل استفاده از آن در برنامه را متوجه شدیم نوبت به معرفی حلقه‌ها رسیده است.

انواع حلقه‌ها در زبان برنامه‌نویسی C

  • حلقه While
  • حلقه For
  • حلقه do_while
  • حلقه‌های تودرتو (nested loops)

حلقه While

از این حلقه زمانی استفاده می‌کنیم که بخواهیم درستی یا نادرستی یک شرط را برسی کنیم که این عمل هم به صورت مقایسه‌ای با استفاده از عملگر‌ها صورت می‌گیرد. برای درک بهتر موضوع به فلوچارت دقت کنید.

فلوچارت حلقه While

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

نحوه اصولی استفاده از حلقه while در زبان برنامه‌نویسی C

همانطور که مشخص است این شرط در صورت درست بودن وارد بدنه حلقه می‌شود در غیر این صورت از حلقه خارج می‌شود.برای درک بهتر به کد زیر توجه کنید.

خروجی کد به صورت است (لطفا اول خودتون تحلیل کنید).

اگر به کد دقت کنید می‌بینید شرطی که نوشته شده است، گفته شده تا زمانیکه مقدار اولیه متغیر a کمتر از عدد 20 بود وارد بدنه حلقه شود و در غیر اینصورت از حلقه خارج گردد.

حال سوالی که ممکن است پیش بیاید این است که اگر بخواهیم این حلقه به صورت بی‌نهایت بار کار کند راه‌حل چیست؟ مسلما باید روشی یا کدی را پیدا کنیم که همیشه شرط حلقه را درست یا اصطلاحا True در نظر بگیرد. به کد زیر دقت کنید.

اگر طبق دستور بالا عمل کنید هر دستوری را که درون بدنه حلقه قرار دهید دقیقا به معنای واقعی بی‌نهایت، بی‌نهایت بار تکرار می‌شود. برای درک بهتر به کد زیر دقت کنید.

اگر دقت کنید، کدی که نوشته شده دقیقا کد قبلی است با این تفاوت که فقط از حلقه بی‌نهایت استفاده شده است.

خروجی کد را به عهده خودتان می‌گذارم فقط به عنوان راهنمایی، این حلقه بی‌نهایت بار تکرار می‌شود.

کاربرد حلقه while

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

حلقه For

از این حلقه زمانی استفاده می‌کنیم که بخواهیم تعداد گام های شمارش را در حلقه مشخص کنیم و همچنین می‌توانیم یک شرط را به همراه مقدار دهی اولیه (مثل حلقه while ) تعیین کنیم. برای درک بهتر به فلوچارت دقت کنید.

فلوچارت حلقه For

حلقه For در زبان برنامه‌نویسی C

نحوه اصولی استفاده از حلقه for در زبان برنامه‌نویسی C

اگر به فلوچارت دقت کرده باشید بر خلاف حلقه while، می‌توان پس از اینکه درستی یا نادرستی شرط تعیین شد گام شمارش را مشخص کرد برای درک بهتر به برنامه زیر دقت کنید.

اگر به کد دقت کنید می‌بینید که پس از اینکه در حلقه مقدار دهی اولیه به همراه شرط تعیین شده است مقدار گام شمارش هم مشخص شده است.

سوالی که ممکن است برای شما پیش آید این است که گام شمارش چیست؟ 

اجازه دهید برای درک بهتر، حلقه For درون برنامه را با یک دیگر برسی کنیم. ابتدا درون حلقه یک متغیر با مقدار اولیه 10 تعریف شده است. و در مرحله بعد شرط a<20 تعیین شده است. همچنین در مرحله بعد گفته شده است که اگر دو مرحله قبلی که توضیح داده شد، درست اعمال شده باشد آنگاه یک واحد به مقدار a اضافه شود (این همان بخشی است که این حلقه را از while متمایز کرده است) و در صورتیکه شرط درست نباشد از حلقه خارج شود. پس با توضیحاتی که دادیم خروجی باید قاعدتا اعدادی از 10 تا 19 را نمایش دهد. دقت کنید گام شمارش کاملا دلخواه است و طبق نیاز برنامه‌نویس انعطاف‌پذیر خواهد بود.

خروجی کد به صورت زیر است.

سوال دیگری که ممکن است برای شما پیش آید این است که آیا این حلقه را هم می‌توان مانند حلقه while به صورت بی‌نهایت تعریف کرد؟

برای پاسخ به این سوال به برنامه زیر دقت کنید.

همانطور که در خط بالا می‌بینید اگر برنامه‌ای را درون بدنه این حلقه For بنویسیم دقیقا بی‌نهایت بار تکرار خواهد شد. برای درک بهتر به برنامه زیر دقت کنید.

نکته طلایی : برای زبان برنامه‌نویسی C چندین استاندارد وجود دارد که آخرین استاندارد زبان برنامه‌نویسی C معروف به استاندارد C11 است که در این نوع استاندارد اگر حلقه for در برنامه استفاده می‌کنید باید به این نکته توجه کنید که نوع متغیر را باید خارج از حلقه for تعیین کنید. در غیر اینصورت، خطایی با مضمون اینکه این ساختار در استاندارد C11 وجود ندارد روبه رو خواهید شد. نکته جالب اینجا است که میکروبلیز هم از این استاندارد پیروی می‌کند (راه‌حل های دیگه از جمله تنظیمات خود کامپایلر وجود داره که مسله رو حل کرد که در اینجا اصلا مورد بحث ما نیست به دلیل اینکه هر کدوم از کامپایلر‌ها روند خاص خودشون رو دارند پس بهترین روش اینکه اصولی بریم جلو). برای درک موضوع توصیه می‌کنیم که مجددا به مثالی که زده شد این بار با دقت بیشتری توجه کنید.

اگر دقت کنید دقیقا کد قبلی است که با ساختار جدیدی که معرفی کردیم نوشته شده است (خروجی کد با خودتون).

کاربرد حلقه For

از این حلقه بیشتر در مواردی که نیاز باشد گام‌های شمارش را مشخص کنیم استفاده می‌کنیم.

حلقه do_while

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

فلوچارت حلقه do_while

استفاده از دستور do-while در زبان C

همانطور که در فلوچارت مشاهده می‌کنید ابتدا وارد بدنه حلقه یا اصطلاحا (do) می‌شود و سپس درستی یا نادرستی شرط را بررسی می‌کند که اگر درست باشد مجددا روند موردنظر تکرار و اگر درست نباشد از حلقه خارج می‌شود. برای درک بهتر، به برنامه زیر دقت کنید.

خروجی برنامه به صورت زیر است (لطفا اول خودتون طبق توضیحاتی که دادیم خروجی رو تحلیل کنید.)

کاربرد حلقه do_while

معمولا در زمان‌هایی که حداقل بخواهیم یک بار، یک دستور در برنامه به همراه بررسی شرط درستی یا نادرستی اجرا و بررسی شود. از این دستور استفاده می‌کنیم.

توجه : این حلقه دقیقا مشابه دستور while است پس تمامی صحبت هایی که برای دستور while گفته‌ایم در اینجا هم صدق می‌کند. 

حلقه‌های تودرتو (Nested Loops)

این نوع از حلقه‌ها دقیقا از ترکیب چندین حلقه با یک دیگر به وجود می‌آیند که هر کدام در جای خودشان بسیار می‌توانند کاربردی باشند. به طور مثال بدست آوردن سطر و ستون یک ماتریس و یا بدست آوردن پیکسل‌های تصویر یا کشیدن پیکسل‌ها روی یک LCD گرافیکی و … که در واقع تمام مثال‌هایی که زده شد در واقع از ساختار ماتریسی گرفته شده‌اند.(لطفا مباحث ماتریس بلاخص بدست آوردن سطر، ستون، مقادیر ویژه و … رو حتما جدی بگیرید). برای درک بهتر اجازه دهید که ابتدا ساختار هر یک از دستورات را بررسی کنیم.

حلقه تودرتو while

 

حلقه تودرتو for

 

حلقه تودرتو do_while

برای درک بهتر موضوع به برنامه زیر دقت کنید.

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

خروجی برنامه به صورت زیر است (لطفا قبلش خودتون هم یک بار تحلیلش کنید).

نکته : دقت کنید حلقه ها را هم می‌توانید با یک دیگرترکیب کنید یعنی اینکه حلقه for را می‌توانید با حلقه while و یا do_while و … ترکیب کنید کاملا این عمل بستگی به نیاز شما دارد.

کاربرد حلقه‌های تودرتو

کاربردی نمی‌توان به صورت دقیق برای این نوع از حلقه‌ها بیان کرد به دلیل اینکه بسته به نیاز کاربر می‌تواند از این روش‌ها استفاده کند یا اینکه استفاده نکند.

به عبارت کلی‌تر کاربرد این نوع از حلقه‌ها کاملا وابسته به کاربر می‌باشد.

 

حالت‌های کنترل حلقه

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

دستور continue

این دستور برخلاف اسمی که دارد در واقع کاری که درحلقه انجام می‌دهد این است که از روند تکرار خطی و یا عبارتی در حلقه جلوگیری می‌کند به عبارت دیگر اگر در برنامه خطی یا عبارتی را خواستیم متوقف کنیم کافی است که از دستور countinue استفاده کنیم. برای درک بهتر موضوع به فلوچارتی که در ادامه قرار می‌دهیم دقت کنید.

فلوچارت continue

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

اگر به فلوچارت دقت کنید کاملا مشخص شده است، هنگامی که cpu در حال اجرای خط به خط برنامه است، قادریم خطوطی را که نمی‌خواهیم cpu آن‌ها را اجرا کند در برنامه متوقف کنیم برای این‌کار کافی است کافیکه از این دستور continue استفاده کنیم. برای درک بهتر به کدی که در ادامه قرار می‌دهیم دقت کنید.

اگر به برنامه دقت کنید درون حلقه do_while یک شرط نوشته شده است و درون شرط دستور continue. به عبارت دیگر زمانیکه شرط برقرار شود چه اتفاقی خواهد افتاد به نظرتان؟ طبق صحبتی که با هم کردیم مسلما باید دستوری که درون شرط قرار دارد اجرا نشود به عبارت ساده‌تر در خروجی نباید عدد 15 را مشاهده کنیم. و اعدادی بین 10 تا 19 را البته بدون عدد 15 را باید مشاهده کنیم. اجازه دهید خروجی را ببینیم(لطفا قبلش خودتون هم تحلیل کنید).

خروجی کد

کاربرد دستور continue

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

دستور break

این دستور دقیقا مطابق اسمی که دارد عمل می‌کند یا به عبارتی اگر هر زمانی خواستیم که عملکرد بخشی از برنامه را طبق شرایطی متوقف کنیم از این دستور استفاده می‌کنیم. برای درک بهتر موضوع به فلوچارت دقت کنید.

 

فلوچارت break

 

استفاده از دستور break در زبان C

همانطور که از فلوچارت مشخص است این دستور بر خلاف دستور continue، کل شرط و یا دستوراتی( دقت کنید نگفتیم صرفا یک خط رو می‌تونیم کاری کنیم که در برنامه یه خط رو متوقف کنه یا چندین خط رو) که بعد از آن‌ها دستور Break قرار گرفته است را متوقف می‌کند برای درک بهتر به برنامه زیر توجه کنید.

اگر به برنامه دقت کنید، یک شرط نوشته‌ شده است که درون شرط از دستور Break استفاده شده است به نظر شما چه اتفاقی خواهد افتاد؟

همانطوری که گفتیم زمانیکه شرط صدق کند تمامی دستوراتی که درون شرط نوشته شده‌اند متوقف می‌شوند و این بخش از برنامه درصورتیکه که مجددا فراخوانی نشود تکرار نخواهد شد. به عبارت دیگر در خروجی باید اعداد 10 تا 15 را مشاهده کنیم.

خروجی کد

کاربرد دستور break

زمانیکه بخواهیم بخشی یا کل برنامه را پس از انجام یک کار خاص متوقف کنیم و در جای دیگری از برنامه بخواهیم استفاده کنیم، از این دستور استفاده می‌کنیم.( یکی از مثال‌های کاربردیش استفاده از ساختار Switch_Case که در ادامه به این دستور هم خواهیم پرداخت ان شالله )

دستور goto

این دستور در بین برنامه‌نویسان به دستور پرش معروف است که البته با اسم آن هم بی‌ربط نیست. دلیل اینکه به این دستور، دستور پرش کردن می‌گویند این است که شما را قادر می‌سازد از هر خطی از برنامه به خط دیگر بروید (پرش کنید).

نکته طلایی: این دستور در صورتیکه ندانید چطور از آن استفاده کنید به حدی خطرناک است که عملا می‌تواند پروژه شما را با خاک یکسان کند.

برای استفاده از این دستور باید یک شرط اساسی را به خاطر داشته باشید ” حتما و حتما و باید از این دستور به صورت پرش رو به جلو استفاده کنید به هیچ وجه از پرش رو به عقب استفاده نکنید.” یعنی اینکه اگر در برنامه خواستید از این دستور استفاده کنید سعی کنید از خط 2 به خط 5 بروید نه اینکه از خط 5 به خط 2 بروید. در صورتیکه بیشتر علاقمند به درک این موضوع هستید توصیه می‌کنیم حتما استاندارد MISRA_C را مطالعه کنید. (من خودم شخصا از این دستور توی برنامه‌هام استفاده نمی‌کنم یکی از بزرگترین دلیل‌هاشم خالی شدن Pipline نه اون چیزی که اکثریت تصور میکنن، ولی گفتم که اگر در صورتی هم که خواستید استفاده کنید با شرطی که گفته شد مشکلی نداره).
برای درک بهتر موضوع به فلوچارت این دستور دقت کنید.

 

فلوچارت goto

استفاده از دستور goto در زبان C

 

 

همانطوری که در فلوچارت هم نشان داده شده است می‌توان توسط این دستور در بین خطوط، پرش انجام داد که به نوعی هم خطرناک و هم خوب است که واقعا باید بدانید که چطور از این دستور استفاده کنید. برای درک بهتر به برنامه‌ای که در ادامه قرار می‌دهیم دقت کنید.

به عنوان یک تمرین: برنامه بالا را تحلیل کنید.

خروجی کد

کاربرد دستور goto

زمانیکه بخواهیم در برنامه از خطی به خط دیگر پرش انجام دهیم البته به شرطی که گفته شد می‌توان از این دستور استفاده کرد البته دستورات دیگری هم مثل Long jump و روش های دیگری هم وجود دارند که در اینجا مورد بحث ما نیست.

حلقه یا شمشیر دو لبه

حلقه را می‌توان به یک شمشیر دو لبه تشبیه کرد. سوالی که هست چرا شمشیر دولبه؟ فرض کنید یک شمشیر دو لبه را در دست خود گرفته‌اید در صورتیکه راه و روش استفاده از این شمشیر را ندانید اتفاقی که خواهد افتاد این است که اول از همه به خودتان آسیب می‌زنید. و در صورتیکه راه و روش استفاده از آن را بلد باشید. بدون اینکه به خودتان ضربه بزنید به راحتی می‌توانید از خودتان دفاع کنید(خب چه ربطی به حلقه داشت). حال در زبان برنامه ‌نویسی C اصلی ترین عضو برنامه شما، حلقه شما است، چه می‌خواهد از سیستم‌عامل استفاده شود و یا امثال آن و الی … بحثی که بسیار اهمیت دارد این است که چطور از این حلقه‌ها در برنامه‌ها استفاده کنیم. یکی از راه‌کار‌هایی که برای مدیرت تمامی حلقه‌ها در برنامه می‌توانیم داشته باشیم، بحثی به نام مدیرت زمان در حلقه‌ها است. این‌کار به روش های مختلف مانند استفاده از پریفرال‌های جانبی( تایمر و سگ نگهبان(watch dog) و … ) و RTOS (اولویت بندی کردن دستورات) و … صورت می‌گیرد.
اجازه دهید برای درک بهتر موضوع یک مثال بزنیم. فرض کنید برنامه‌ای را درون میکروبلیز نوشته‌اید که باید زمانیکه حتما دیتا را دریافت کرد آنگاه ادامه دستورات را اجرا کند؟ آیا این طرز برنامه‌نویسی درست است؟

پاسخ

بزرگترین مشکلی که این برنامه دارد این است که هر وقتی که دیتا آمد برنامه ادامه کار خود را انجام می‌دهد(یعنی فاجعه). خب فرض را بر این بگیریم که دیتایی را اصلا دریافت نکردیم. آیا عاقلانه است که بقیه دستورات را هم به خاطر آن از کار بندازیم. مسلما کاری عاقلانه نیست. راه‌حل چیست؟ راه‌حل استفاده از یک زمان‌بندی است که به طور مثال بگوییم اگر تا یک ثاینه هیچ دیتایی دریافت نشد ادامه دستورات را اجرا کن (البته روش‌های دیگری هم وجود دارند که بتوان حلقه ها را کنترل کرد و هدف از توضیح این بخش، این بود که شما مخاطب عزیز بدونید که با چه دستور مهمی در برنامه هاتون مواجه هستید).

امیدواریم که توانسته باشیم اهمیت مبحث حلقه‌ها را به شما مخاطبین عزیز انتقال داده باشیم.

 

امیدواریم که این آموزش هم برای شما مخاطبین عزیز مفید واقع شده باشد.


انتشار مطالب با ذکر نام و آدرس وب سایت سیسوگ، بلامانع است.

شما نیز میتوانید یکی از نویسندگان سیسوگ باشید.  همکاری با سیسوگ

 
BLO OM

درباره BLO OM

«السَّلَامُ عَلَیْکَ یَا أَبَا عَبْدِ اللَّهِ، السَّلَامُ عَلَیْکَ وَ رَحْمَهُ اللَّهِ وَ بَرَکَاتُهُ».

نوشته های مشابه

پاسخی بگذارید

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