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

#1 2018-08-08 00:47:12

Arcush
Moderator
ثبت شده: 2015-09-15
ارسال ها: 1,449

C اَت را قورت بده.

درود.

درسته که هرگونه جنگی بر سر زبان ها به نتیجهٔ ویژه ای نمیرسه و سر انجام به این منتهی میشه که هر زبانی کاربردهای خودش را داره و انتخاب و استفاده از زبان میتونه چند نقطه از یک طیف را مورد هدف قرار بده (از قبیل پروتوتایپ، تجاری بودن، کاربرد، تفاوت سطح، سلیقه و هدف برنامه نویس و ووو). ولی شاید همه یکدل باشیم که اگر قراره تمام زبان های دنیا را از بین ببریم و یکی باقی بمونه ممکنه C همونی باشه که به باقی موندنش رای میدیم. بهرصورت، برمبنای پیشنهاد Ritchie@ گرامی تصمیم گرفتیم که تاپیکی را ایجاد کنیم و در اون تاپیک آموزش های پایه ای تا کاربردیِ C را قرار بدیم و این تاپیک بصورت مباحثه ای پیش بره. احتمالن Ritchie@  روی گیتهاب هم آموزش ها را قرار میده ولی خود آموزش ها را همواره در ارسال پسین آپدیت می کنه. امیدوارم این تاپیک بتونه نقطهٔ عطفی در چرخش جامعهٔ انجمن های لینوکس در کشورمون باشه و همچنین امیدوارم با مشارکت (پرسش، پاسخ، پیشنهاد، انتقاد، آموزش، نکته، تجربه و ووو) دوستان بتونه به انباره ای درخور از آموزش ها و مباحثه های علمی در C تبدیل بشه. بنابراین، در ارسال ها بسیار راحت خواهیم بود و آموزش ها توسط Ritchie@ گرامی در یک ارسالْ هماره پیراسته خواهند شد.

ویرایش: یکی از دوستانِ نوجوانِ تیزهوشِ انجمن با نام تاپیک مشکل کوچیکی داشتن که درست شد. lol

آخرین ویرایش توسط Arcush (2018-08-19 00:22:54)

آفلاین

#2 2018-08-08 02:27:58

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

سلام.
در تایید سخنان دوست خوبم arcush هدف ما از ایجاد این تاپیک ایجاد آمورشی ماندگار, جمعی و کامله. ما در ازای این کار هیچ پولی دریافت نمیکنیم و فقط با عشق و علاقه خودجوش این تصمیم رو گرفتیم. پس هدفمون سیاه کردن صفحه و کار اجباری نیست. چیزی رو مینویسیم که فهمیده بشه و کاربردی باشه. پس الان طبیعیه اگر بگم یه موضوع شاید چندیدن صفحه حجمش باشه. اما بنظر شخصی من اصلا مهم نیست. شور و اشتیاق به خوندن یک کتاب قشنگ بسیار بیشتر از خوندن یک پاراگراف نامفهومه. ما سعی میکنیم از تمام اونچه که میدونیم و خوندیم و کار کردیم استفاده کنیم تا این تاپیک بصورت یک گنجینه در بیاد. در خلال این آموزش مشارکتی به انواع منابع معتبر مراجعه میکنیم, مطلب رو میخونیم و به زبانی شیوا و رسا بازگو میکنیم. سعی میکنیم بهترین استفاده رو از مستندات کامپایلرهای گنو, مستندات کتابخانه های استاندارد C, و مستندات POSIX داشته باشیم. این تاپیک به امید خدا بسیار بزرگ خواهد شد. چون این تاپیک دارای کامنت هم هست سعی میکنیم یک صفحه هم در Github براش ایجاد کنیم که کسانی که میخوان بصورت سرراست مطلب رو بخونن بتونن بی وقفه جلو برن.

آفلاین

#3 2018-08-08 03:56:36

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

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

  • برنامه و اسکریپت

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

برنامه و اسکریپت
یه چیزی که همه مون میدونیم ولی شرح تفاوتش برامون گاهی سخته. چون گاهی اسکریپت رو با سورس برنامه اشتباه میگیریم. اسکریپت به مجموعه دستورالعمل هایی میگن که برای اجرا شدن باید در برنامه دیگری ترجمه و اجرا بشن. مثال خوبش جاوا اسکریپته. دستورات جاوا اسکریپت در دل کدهای html قرار میگیرن و مرورگر اجراشون میکنه. توانایی اجرا رو از خودشون ندارن. اما برنامه ها اینگونه نیستن. برنامه ها یکبار کامپایل شدن و توانایی اجرا شدن ذاتی دارن. تفاوت بعدیشون اینه که برنامه ها به زبان ماشین ترجمه شدن اونم یکبار برای همیشه. اما اسکریپتها هربار باید ترجمه بشن. زبان ماشین زبان صفر و یکه. پردازنده زبان اون برنامه رو میفهمه و سریع اجراش میکنه چون دیگه لازم نیست ترجمه بشه و بعد به پردازنده داده بشه. تفاوت دیگرشون اینه که شما میتونید اسکریپت رو با ادیتورهای متنی مثل gedit یا notepad باز کنید و ببینید و ویرایش کنید. اما یک برنامه رو نمیتونید با ادیتور متنی باز کنید و ازش چیز قابل فهمی استباط کنید و ویرایش کنید. تفاوت دیگرشون اینه که در برنامه ها، در زمان نوشتن سورس کد، شما برای اجرا برنامه و اجزای داخلش مقدار حافظه تعیین میکنید. مثلا میگید برای اعداد صحیح ۳۲ بیت جا میخواد برنامه م. زیرا برنامه ای که اجرا میشه در رم یا حافظه اصلی مستقر میشه تا بعد از پردازش شدن، و باید براش مشخص کرده باشید که سیستم عامل چقد فضا بده به این برنامه تون. اما اسکریپتها تخصیص حافظه ندارن. بلکه برنامه ای که اجراشون میکنه به سیستم عامل میگه که چقدر فضا میخواد. سخن آخر اینکه هردوشون خوبن و نمیتونن جای همدیگه رو پر کنن. یه جاهایی اسکریپت چنان کاربردی داره که معقول نیست ازش چشم پوشید. یه جاهایی فقط اسکریپت به کار میاد. پس به چشم یه چیز بیکار نگاش نکنید. C زبان برنامه نویسیه. یعنی بعد از نوشتن سورس کد و کامپایل کردن ( در مورد کامپایل در قسمتهای آینده مفصل توضیح میدم) برنامه اجرایی ساخته میشه به زبان دودویی یا Binary. این برنامه از همین الان قابلیت اجرا رو داره.

آخرین ویرایش توسط Ritchie (2018-08-29 15:59:45)

آفلاین

#4 2018-08-16 09:24:46

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

دوستان ببخشید این مدت یه کم کار داشتم نتونستم سریع ادامه مبحث قبل رو برم. چند روز پیش اومدم کلی نوشتم بعد هنگام ارسال لاگ آوت شدم و هرچی رشته بودم در یک آن پنبه شد. امروز به کمک خدا ادامه شو میریم.

آفلاین

#5 2018-08-18 19:13:45

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

میخوام الان درباره دلایل انتخاب زبان C از دید خودم و اکثر برنامه نویسان براتون بنویسم و بعد معایبش.

  • طراحی

  • بهینگی

  • قابلیت حمل

  • قدرت و انعطاف پذیری

  • آزادی

طراحی
زبان C از بنیان ترکیب علم و عمل بوده است. زبانی است که از بنیان برای کارکرد قابل اطمینان و مستحکم ساخته شده است. زبانی است که به منظور ساخت سیستم عامل ساخته شده است. بعضی زبانها اینگونه نیستند. مثلا زبان پاسکال برای کارهای ریاضی و زبان BASIC برای دانشجویانی که به زبان انگلیسی آشنایی دارند ساخته شد. زبانی که برای پیاده سازی سیستم عامل مورد استفاده قرار میگیرد باید بسیار دقیق، پایدار و بهینه باشد. ویژگی های طراحی زبان C بطور خلاصه به این شرحه:

۱- ساختار بالا به پایین: به این صورت که مثل اکثر برنامه ها برنامه از ابتدا به انتها اجرا میشه. برنامه نویسان امروزی بشدت از استفاده از پرش goto پرهیز میکنند تا خوانایی و عیب یابی برنامه دشوار نشه. در این ساختار با دنبال کردن برنامه میتوانیم بفهمیم که برنامه قراره چه کاری انجام بده و کجاها باید اصلاحات انجام بدیم.
۲- بهینگی: C زبان بهینه ایست. به این معنی که در طراحی آن سعی شده تا از تمام توان و قابلیتهای سیستمهای فعلی استفاده بشه. C یه زبان کوچک و سریعه. در حقیقت در C از پتانسیل زبان اسمبلی در کنار راحتی زبان سطح بالا استفاده شده است تا برنامه نویس در صورت لزوم به حداکثر بهره از سیستم و حداقل فاصله از قدرت سخت افزار برسه. این هنر و دانش برنامه نویسه که از یه راه دیگه به مسئله نزدیک بشه و بتونه با حداکثر سرعت و بهینگی برنامه هاشو بنویسه.
۳- قابلیت حمل و جابجایی: منظور ما از قابلیت حمل اینه که برنامه ای رو که در یک سیستم خاص نوشتید بتونید بی دردسر در سیستمهای دیگه اجرا کنید. سی زبان قابل حمل یا پورتابلیه. به این معنی که برنامه ای رو که روی یک سیستم ویندوزی نوشتید میتونید به اسانی بر روی اکثر سخت افزارها بدون تغییر یا با تغییرات بسیار جزئی در حد تغییر فایل سرآیند، اجرا کنید. قابلیت حمل به این معنا نیست که فایل اجرایی یک اکوسیستم مثل مایکروسافت رو در اکوسیستمی مثل unix اجرا کنید. بلکه منظور پورت کردن سورس کد بدون تغییر یا با تغییرات اندک است. به گونه ای که بتوان برنامه را در سیستم مقصد به راحتی کامپایل و اجرا کرد. کامپایلرهای C برای بازه بسیار وسیعی از سخت افزارها ساخته نوشته شده اند. بطوری که میتوانید یه برنامه C رو در بازه وسیعی از سخت افزارها، از یه گوشی تلفن همراه گرفته تا یک ابرکامپیوتر اجرا کنید.
۴- قدرت و انعطاف پذیری: C یک زبان قدرتمند و انعطاف پذیره. سیستم عامل یونیکس(و مشتقات یونیکس) گواهی بر این مدعاست. بسیاری از کامپایلرها و مترجمها(اینترپرِتِر) مانند FORTRAN, Perl, Python, LISP, Logo و BASIC با زبان C نوشته شده اند. در نتیجه اگر شما در سیستم یونیکسی خود مشغول نوشتن یک برنامه به زبان FORTRAN هستید، این C است که در نهایت کار را به سرانجام رسانیده و فایل اجرایی را برایتان تولید میکند.
۵- آزادی: C زبان آزادی است که دست برنامه نویس را برای انجام بسیاری از کارها نظیر دسترسی مستقیم به سخت افزار و دستکاری بیتهای موجود در حافظه را امکانپذیر میکند. همچنین انباره ای غنی از عملوندها(اپراتورها) دارد که باعث میشود برنامه نویس بدون دردسر و بصورت کوتاه و مختصر افکار خود را در برنامه پیاده کند. این آزادی و انعطاف پذیری مانند یک شمشیر دو لبه است که میتواند در کنار مزایا معایبی(اگه بشه گفت عیب) نیز داشته باشد. مثلا تصور کنید که در بیرون از خونه امکان بروز پاره ای از مخاطرات مانند تصادف رانندگی وجود داره که در خونه احتمالش صفره. آیا به صرف اینکه در بیرون از خونه خطر تصادف ما رو تهدید میکنه باید تو خونه بشینیم تا آخر عمرم و از زیبایی های بیرون چشم بپوشیم؟ طبیعتن خیر. چیزی که لازمه احتیاطه. در C هم دقیقا همینطوره. آزادی در کنار احتیاط. در خلال درسها با چگونگی احتیاط در برنامه نویسی آشنا میشیم.
یکی دیگه از ویژگی های C که ارور خیزش میکنه اینه که C از اشاره گر استفاده میکنه. یک ویژگی بسیار بسیار مفید و قدرتمند و د رعین حال مشکل خیز. مشکل خیز ازون جهت که خطاهایی که از اشاره گرها متاثر میشن رهگیریشون کار چندان آسانی نیست. پس در این مورد نیز باید محتاط بود. به عبارت دیگر، بهای آزادی، هشیاری همیشگی ست.

آخرین ویرایش توسط Ritchie (2018-08-18 19:21:15)

آفلاین

#6 2018-08-29 12:27:00

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

زبانهای سطح بالا و زبانهای سطح پایین

منظور از سطح زبان نزدیک بودن قواعد نگارشی آن به زبان آدمیست. مثل زبان C، پایتون و بسیاری از زبانهای سطح بالای آشنا. در مقابل زبانهای سطح پایین وجود دارند. زبانهایی که قواعد نگارشیشون به زبان ماشن نزدیک تر است.
یک نمونه براتون مثال میزنم. چاپ Hello World در خروجی به سه زبان C و اسمبلی و ماشین.
در زبان C:

printf("Hello world");

در زبان اسمبلی:

    global  _main
    extern  _printf

    section .text
_main:
    push    message
    call    _printf
    add     esp, 4
    ret
message:
    db  'Hello, World', 10, 0

و در زبان ماشین:

b8    21 0a 00 00   
a3    0c 10 00 06   
b8    6f 72 6c 64   
a3    08 10 00 06   
b8    6f 2c 20 57   
a3    04 10 00 06   
b8    48 65 6c 6c   
a3    00 10 00 06   
b9    00 10 00 06   
ba    10 00 00 00   
bb    01 00 00 00   
b8    04 00 00 00   
cd    80            
b8    01 00 00 00   
cd    80            

همونطور که میبینید نوشتن برنامه در این زبانها قدری سخت تر و زمانگیرتره. زبانهای سطح بالا نیز در آخر کار باید به چنین شکلی در بیان تا برای ماشین(پردازنده) قابل فهم و اجرا باشن. این کار رو کامپایلر انجام میده. کامپایلر در حقیقت یک مفسره که کدهای ما رو برای ماشین تفسیر میکنه. اما در حقیقت کامپایلرهای امروزی فراتر از یک مفسر هستند. چرا که علاوه بر تفسیر کدهای منبع، کار لینک کردن(توضیح خواهیم داد) و عیب یابی را نیز انجام میدهند. پس کامپایلر برنامه ایست که کدهای منبع مارا در زبانهای سطح بالایی چون C به زبانی قابل فهم برای ماشین تفسیر میکند و ازون یه خروجی ماشینی قابل اجرا میسازد. یک مسئله ای که بسیاری از ما با اون مشکل داریم تفاوت زبانهای کامپایلی و مفسریه . بعضی زبانها مفسر دارند و بصورت real-time ترجمه میشن. یکبار برای همیشه اینجا عرضتون میکنم. زبانهایی که مفسر دارن مانند پایتون، برای هربار اجرا باید مفسر از قبل بر روی سیستمشون نصب شده باشه. مفسر بصورت خط به خط از بالا به پایین کار میکنه. یعنی اگر شما یه برنامه پایتون داشته باشید که در اون باید از کاربر ورودی بگیره تا اون ورودی رو نگیره خط بعد ترجمه نمیشه و مفسر همونجا باقی خواهد ماند. پس میتونیم بفهمیم که اگر برنامه تا خط اخر درست نوشته شده باشه ولی خط اخر نادرست باشه برنامه تا اون خط بی مشکل پیش میره اما در خط آخر به شما خطا خواهد داد. اما در کامپایلر قضیه فرق میکنه. اولا برنامه ای که کامپایل میشه باید تمام و کمال درست نوشته شده باشه (از لحاظ دستور زبان یا syntax اون زبان). ثانیا برنامه ای که کامپایل شد، برای اجر نیازی به کامپایلر نخواهد داشت. مورد بعدی اینه که زبانهایی که کامپایلر دارند وابسته به سیستم عامل هستند. مثال بارزش اینکه شما نمیتونید فایل با پسوند exe رو از ویندوز بیارید و در گنو/لینوکس یا هر اکوسیستم غیر مایکروسافتی اجرا کنید. به همین دلیله که برای طیف وسیعی از اکوسیستم ها کامپایلرهای زبان C نوشته شده است. و اینم مجددا عرض کنم که پورتابل بودن زبان به معنی پورتابل بودن سورس برنامه است نه فایل ماشینی.
کامپایلرهای زیادی برای زبان C وجود دارن که از معروفترین آنها میتوان به Clang و GCC اشاره کرد. ما در این تاپیک از GCC استفاده میکنیم. در استفاده از کامپایلرها هیچ اجباری به نوع خاصی از کامپایلر نیست. کامپایلر باید دو ویژگی داشته باشه. اول اینکه مطابق با آخرین استانداردها باشه و دومی مستندات خوبی رو ارائه بده. که مجموعه کامپایلرهای گنو چنین ویژگی رو دارند.

ادیتور
مبحث بعدی ادیتور یا ویرایشگر متن هست. جایی که ما بتونیم کدهامون رو درش بنویسیم. در استفاده از یک ادیتور هیچ اجباری نیست. اما ادیتور باید یک ویژگی داشته باشه و اون نیفزودن فراداده یا metadata به کد باشه. به چه صورت؟ به این معنی که ادیتور نباید هیچ نوع داده ای رو به کد نظیر پاراگراف، فرمت، افزونه و امثال اینها به کدهای ما اضافه کنه. سعی کنید از ادیتورهای ساده مانند TextEdit در مک، gedit، nano، vi وkate در گنو/لینوکس یا notepad در Microsoft Windows استفاده کنید. به هر صورت با جستجویی ساده در وب میتونید مناسب ترین ادیتور رو برای خودتون پیدا کنید.

IDE یا محیط توسعه مجتمع
برنامه ای که کلیه امکانات لازم برای برنامه نویسی را در یک جا جمع کرده. IDE ها از یک ادیتور، کامپایلر توکار، لینکر و عیب یاب تشکیل شده اند.  میتوان بدون IDE هم برنامه نوشت و اتفاقا ترجیح من به کسانی که تازه شروع به برنامه نویسی میکنند این است که از IDE استفاده نکنند. به این دلیل که استفاده از IDE برنامه نویس مبتندی رو تنبل بار میاره. قضیه برای برنامه نویسهای صنعتی و کهنه کار فرق میکنه. اونا مسیرشون رو رفتن و IDE برای سرعت دادن به کارهاشونه و اینگونه نیست که اگر IDE رو ازشون بگیرید فلج بشن. بلکه خیلی هم خوب به کارهاشون میرسن. شما هم روزی حرفه ای میشید و میتونید از IDE استفاده کنید. کسی که تازه شروع به برنامه نویسی میکنه خوبه که با انواع ادیتورها و کامپایلرها و خط فرمان آشنا بشه. خوبه که از قابلیت autocomplete استفاده نکنید و بیشتر با دستهاتون کد بزنید حتی کدهای بسار تکراری. ازین جهت که اولا همین اول باید یاد بگیرید که برنامه نویسی ادم پر حوصله ای میخواد که نباید غز بزنه. مورد بعد اینکه دستهاتون عادت کنه به تند نویسی و دقیق نویسی. یاد بگیرید چگونه در محیط خط فرمان از کامپایلر و عیب یاب استفاده کنید. سویچ ها و فلگهای کامپایلرتون رو بشناسید. از خطاهای املایی نترسید. حرفه ای ترین برنامه نویس های دنیا هم دچار اشتباهات تایپی میشن.
ولی به هرحال اگر چنانچه توصیه های من رو نپذیرفتید تعدادی از IDE ها رو خدمتتون عرض میکنم
Xcode
Visual Studio
geany
Code::Blocks
CLion
NetBeans
Eclipse
CodeLite
KDevelop
و هرچیزی که شما میشناسید و من نمیشناسم.
ما در این تاپیک از ادیتور و مجموعه کامپایلرهای گنو بعلاوه ترمینال در سیستم عامل گنو/لینوکس استفاده میکنیم.
برنامه های که کاربران گنو/لینوکس باید نصب کنند:
یک ادیتور که باهاش راحتید.
یک کامپایلر ترجیحا GCC.
دیباگر که با نصب GCC بسته GDB هم کنارش نصب میشه. اگر نصب نشده بود نصبش کنید.
و یک شبیه ساز ترمینال (Konsole, gnome-terminal, xfce4-terminal, Terminator, Tilda, Xterm یا هرچی که مناسبتونه).
شیوه کار با gcc در ترمینال بدین صورته:

gcc filename.c -o filename

با این دستور، gcc فایل برنامه رو که به زبان C است از شما گرفته و در همان پوشه/دایرکتوری یک فایل اجرایی(ماشینی) با همون نام براتون میسازه.
اگر gcc را به این شکل به کار ببرید:

gcc filename.c

یک فایل اجرایی با نام a.out برای شما میسازه. حالا چرا a.out ؟
این یک بحث تاریخیه. در اون زمان که سیستم عامل یونیکس رو در آزمایشگاه های Bell متعلق به شرکت AT&T میساختن، کن تامسون ازین نام و فرمت خروجی که مخفف assembler output بود استفاده کرد. چون کد منبع به زبان اسمبلی ترجمه میشد و assembler نیز همین کد اسمبلی را به کد ماشینی ترجمه میکرد. در نظر داشته باشید که زبان اسمبلی با زبان ماشین تفاوت دارد. زبان ماشین فقط 0 و 1 است. بعدها همین مخفف در سیستمهای یونیکسی و BSD ها دست نخورده و تا امروز باقی ماند.
به هر حال شما باید قادر باشید فایلی رو که بعنوان خروجی گرفتید اجرا کنید. برای اینکار دو روش پیش رو دارید:
۱- دایرکتوری یا پوشه شما در لیست مسیرهای سیستم عاملتون قرار نداره:

./filename

یا

./a.out

۲- دایرکتوری محتوی فایل اجرایی در لیست مسیرهای تعریف شده قرار دارد:

filename

یا

a.out

آخرین ویرایش توسط Ritchie (2018-08-29 16:10:50)

آفلاین

#7 2018-08-29 14:02:53

Arcush
Moderator
ثبت شده: 2015-09-15
ارسال ها: 1,449

پاسخ: C اَت را قورت بده.

درود بر سعید گرامی. کم کم داریم نزدیک میشیم به الگوریتم و کُد. نوشته هات بسیار زیبا هستند و امیدوارم این راه پیوسته باشه. به قول رضا براهنی: بِدَف.

پاسکال و لایبنیتز (که بر خلاف پاسکال در دو سده زندگی کرد) روی ساختن ماشین های محاسباتی کار کردند. دو سده دیرید تا در ۱۹۴۰ تورینگ نظریهٔ ماشین تورینگ را بنا نهاد ( گفتگوی بیشتر در این فتاد در گسترهٔ این درآخت/تاپیک نیست، ولی بسیار خوشاینده). در ۱۹۵۰ جان.فون.نویمان یک ریانهٔ دیجیتالی ساخت که سه بخش داشت: "حافظه" برای نگهداری داده ها و برنامه ها،  "پردازشگر" برای اجرای برنامه ها و "ابزارهای I/O*" برای گرفتن داده ها و دادن پاسخ (تخته کلید، موشی، چاپگر و نمایشگر). آشکار هست که توان هریک ازین قسمت ها بر توان کلِی رایانه تاثیر میگذاره. گرچه زیاد هم نباید خوش بین بود و مساله های زیادی وجود دارند که خودشون، پیاده سازیِ الگوریتم های حلشون و بهینه کردن الگوریتمشون هنوز هم که هنوزه از جستارهای بازِ دانش کامپیوتر هستند. آشکار هست که ما در اینجا با این زمینه ها سر و کار نخواهیم داشت. )) ولی در ادامه نمونه هایی خواهیم آورد که می تونیم پیاده سازیِ الگوریتم های مختلف برای حل یک مساله را در اونها بررسی کرده و دستِ کم زمان حلِ اون مساله را در هریک ازین حالت ها بسنجیم. اگر بهتر بودن را بمعنایِ رسیدن رایانه به پاسخ در زمان کمتر معنی کنیم، می تونیم نوشتن کد بهتر را در مسابقه بگذاریم (هر کس با خودش) و همواره به این بیندیشیم که: اگر ارزشش را داشته باشه،  آیا می تونم کُدم را بهتر کنم؟





---------------------------
* Input/Output

آخرین ویرایش توسط Arcush (2018-08-29 14:04:58)

آفلاین

#8 2018-08-29 14:05:46

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

استانداردها
حالا میرسیم به بحث خوش استانداردها
اصولا استانداردها برای چی هستند؟ فکر کنید هرکس هرجوری خواست یه برنامه بنویسه. هر کس به میل خود به روش خودش متغیر تعریف کنه. یکی پرانتز بزاره یکی اکولاد. یکی این کارو بکنه یکی اون کار. خب سنگ رو سنگ بند نمیشه. برای داشتن یک برنامه که بشه در کل دنیا ازش بهره برد باید استانداردی داشت که در کل دنیا تعریف شده باشه و مورد استفاده قرار بگیره.
اولین نیمچه استانداردی(چون واقعا استاندارد نبود بلکه پیروی از روش بود) که در مورد C اتخاذ شد استاندارد K&R مخفف کارنیگان و ریچی بود. این استاندارد دقیقا پیروی از شیوه برنامه نویسی این دو والا مقام در کتابشون بود به نام  The C Programming Language که در سال ۱۹۷۸ منتشر شد. همچنین یک فصل به نام C Reference Manual به این کتاب ضمیمه شد که راهنمایی برای نحوه پیاده سازی کامپایلر بود برای کسانی که میخواستند کامپایلر بنویسن برای C. به هر حال هرچه زمان پیش میرفت و برنامه نویسان و شرکت های بیشتری به سمت C می آمدند نیاز به یک استاندارد کامل و جامع و به روز بیشتر حس میشد. تا اینکه موسسه استاندردهای ملی امریکا کمیته ای را به نام X3J11 ایجاد کرد تا استاندارد جدیدی را برای زبان C تعریف کنند که استانداردشان را رسما در سال ۱۹۸۹ تصویب و منتشرکردند. در این استاندارد که به نام ANSI C شناخته میشد هم استانداردهای زبان C و هم استانداردهای کتابخانه های C بیان شده بود. در سال ۱۹۹۰ سازمان بین المللی استانداردسازی نیز استانداردی را تحت عنوان ISO C تعریف کرد. استادارد ISO C در واقع تفاوتی با استاندارد ANSI C نداشت. اسم استاندارد ANSI C را C89 و اسم استاندارد ISO C را C90 گذاشتند(سالهایی که رسمی تعریف شدند). در کتابهای برنامه نویسی ممکن است به عبارت ANSI/ISO C89/90 برخورد بکنید که خود گواهی بر این است که این دو استاندارد تفاوتی ندارند و صرفا استاندارد دوم، استاندارد اول را جهان شمول عنوان کرده است.
اهدافی که در این دو استاندارد عنوان شده بود به این قرار بود:

  • به برنامه نویس اعتماد کنید

  • از قرار دادن هر آنچه که برنامه نویس را محدود میکند بپرهیزید

  • زبان C را تا حد ممکن ساده و کوچک نگاه دارید

  • فقط یک راه برای انجام یک عملیات فراهم کنید(زبان را کلاف سر در گم نکنید)

  • برنامه ها را بگونه ای بنویسید که بالاترین سرعت را داشته باشند. حتی اگر با این کار از پورتابل بودن برنامه کاسته شود(کاری که در درایورها انجام میشود. زیرا سرعت پاسخگویی یک درایور بسیار بسیار مهمتر از قابلیت حمل آن است)

منظور کمیته از مورد آخر این است که برنامه ها برای سیستم هدف کاملا بهینه و سریع نوشته شوند. در طول این تاپیک ما به چنین مواردی به کرات برخورد میکنیم.

استاندارد C99
در سال ۱۹۹۴ دو کمیته ANSI و ISO با هم تلفیق شدند و کمیته ای را تحت عنوان کمیته C9X شکل دادند. این کمیته جدید شروع به ویرایش و بهبود استاندارد قبلی کرد. در  این استاندارد هیچ یک از گزینه های استاندارد قبلی پاک نشد و مورد جدیدی نیز افزوده نشد و فقط پاره ای از بهبودها نظیر:

  • پشتیبانی از کارکترهای بین المللی و محلی کشورها

  • کدها و اعلان های متصل. اعلان متغیر دیگر وابسته به محدوده فایل نباشد

  • چند نوع داده جدید از جمله نوع داده بولی, complex و long long int

  • افزودن کامنتهای یک خطی //

  • افزودن فایلهای سرآیند جدید

و ... افزوده شدند.

استاندارد C11
استانداردسازی یک امر دائمیست. نه به این دلیل که استانداردهای قبلی ناقص و ضعیف باشند. بلکه به این دلیل که به مرور زمان مفاهیم و تکنولوژی هایی زاده میشوند که در گذشته نبوده اند، مانند برنامه نویسی همزمان یا concurrent programming که در آن از چندین پردازنده برای برنامه نویسی استفاده میشود. به همین دلیل کمیته استانداردسازی زبان C در سال ۲۰۰۷ استاندارد دیگری را تحت عنوان C1X پدید آورد. لازم به ذکر است که استانداردها با همدیگر سازش دارند. بگونه ای میتوان اکثر برنامه های قدیدمی را در کامپایلرهای مبتنی بر استانداردهای جدید کامپایل کرد، اما نه بالعکس. اما توصیه میشود همیشه طبق اخرین استاندارهای روز که در مستندات هر کامپایلر ذکر شده است برنامه بنویسید. باری، اولین نسخه ازین استاندارد که منتشر شد استاندارد C11 بود که به روز ترین استاندارد حال حاضر نیز هست.
همیشه سعی کنید از استانداردهای روز پیروی کنید تا به مشکل نخورید. یک تمرین خوب این است که در مخازن و کتابها برنامه های قدیمی C را بیابید و با استاندارد C11 بازنویسی کنید.

آخرین ویرایش توسط Ritchie (2018-08-29 16:17:20)

آفلاین

#9 2018-08-29 15:42:43

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

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

۱- تعریف اهداف برنامه
گویا و واضح. بررسی و کنکاش ایده ای که در ذهنتونه. برای چی دارم برنامه مینویسم؟ قراره چه کاری برام انجام بده؟ چه ورودی هایی باید بگیره برنامه م؟ چه خروجی بهم میده؟ در این مرحله نباید در جزئیات وارد شد. فقط باید به شمای کلی و اهداف بصورت دید از بالا نگاه کرد، مفهومی.

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

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

۱- یک پیغام از کاربر میخواهد دو عدد را با یک فاصله وارد کند:
۲- یک تابع دو عدد ورودی را از کاربر میگیرد و در دو متغیر قرار میدهد
۳- حاصل جمع این دو عدد در متغیر سومی قرار میگیرد
۴- مقدار موجود در متغیر سوم را چاپ میکنیم.

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

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

#include<stdio.h>

int main(void)
{
int number1, number2;	

printf("Enter two integer: ");
scanf("%d %d",&number1,&number2);
int sum;
sum = number1 + number2;
printf("sum of %d + %d is %d.\n", number1, number2, sum);

return 0;
}

یه چیز بسیار بسیار مهم که در برنامه نویسی باید بهش عادت کنید مستندسازی و نوشتن توضیحاته که من عمدا ننوشتم. به این دلیل که اولا هنوز راجع بهش صحبتی نکردیم. دوما بعدا بدونید برنامه بدون مستندات تا چه حد میتونه بد باشه.
حالا که ما هدف برنامه مونو تعیین کردیم. طرحشو تو ذهنمون کشیدیم. شبه کدش رو نوشتیم و تبدیلش کردیم به یک برنامه درست در زبان C باید برنامه رو کامپایل کنیم.
فرض کنید اسم برنامه ما calculator.c باشه

کامپایل کردن برنامه
همچنان که قبلا توضیح دادیم کامپایل کردن برنامه در ترمینال سیستمهای nix (گنو/لینوکس-BSDها و حتما macOS) به این صورته:

gcc calculator.c -o calculator

با این دستور به کامپایلر gcc میگیم که فایل calculator.c رو که حاوی کدهای ماست بگیره و یک فایل خروجیِ ماشینیِ قابل اجرا به نام calculator بهمون بده. اگر در نوشتن برنامه مرتکب خطایی شده باشیم(مخصوصا خطای دستوری) کامپایلر gcc با استفاده از عیب یاب یا دیباگر gdb بهمون اعلام میکنه که خطایی در برنامه مون هست و باید درستش کنیم. همینجا باید یه عذرخواهی بکنم از کاربران ویندوزی. متاسفانه من هیچگونه اطلاعاتی در مورد ویندوز و نحوه کامپایل برنامه در خط فرمان ویندوز ندارم. امیدوارم دوستانی که میدونن تشریف بیارن و توضیح بدن.

اجرای برنامه
قدم بعدی اجرای برنامه هست. قبلا در همین تاپیک شیوه اجرای برنامه رو تحت ترمینال خدمتتون عرض کردم. دوستانی هم که از IDE استفاده میکنن گزینه run در اختیارشون قرار داده شده توسط IDE.
خب حالا برنامه مون رو اجرا میکنیم:

$ ./calculator

سپس کلید Enter یا Execute رو میزنم. خروجی به این شکل خواهد بود:

Enter two integers: 

در این قسمت برنامه منتظر میماند تا کاربر دو عدد صحیح را با فاصله وارد کند. مانند ۱۲  ۱۳

Enter two integers: 12 13

بعد از فشردن Enter خروجی بدین شکل خواهد بود.

sum of 12 + 13 is 25.

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

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

آخرین ویرایش توسط Ritchie (2018-08-29 15:56:32)

آفلاین

#10 2018-08-30 03:13:14

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

شروع برنامه نویسی واقعی

به نام یزدان پاک
تصمیم گرفتیم هر مبحث رو با یک برنامه شروع کنیم و در طی اون مبحث اجزای اون برنامه رو حلاجی کنیم.
پس بزن بریم.
first.c

/*  firts.c
 * our firs C program*/

#include<stdio.h>       // include an external library in program
int main(void)              /* main function */
{
    int num;    // define a variable called num
    num = 1;    // assign a value to num
    
    
    printf("I am a simple ");    // use the printf() function
    printf("program.\n");
    printf("My favorite number is %d because it is first.\n", num);
    
    return 0;
}

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

I am a simple program.
My favorite number is 1 because it is first.

توضیح: چنانچه برنامه رو در IDE نوشتید و پس از اجرا برنامه فورا بسته میشود در یک خط قبل از return عبارت

getchar();

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

شرح برنامه

کامنت یا توضیحات
قسمتهایی از برنامه که بین دو علامت /* و */ محسور شده و یا پس از // قرار گرفته اند کامنت نامیده میشوند. در کامنتهای تک خطی از // استفاده میشود. برای ایجاد کامنتهای چند خطی میتوان از /* و */  استفاده کرد:

//this is one line comment
/*
this is 
multi line
comment*/

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

فایل سرآیند یا هدر
فایل سرآیند فایلی است که در بالای برنامه قرار میگیرد و کتابخانه ای را در برنامه کپی میکند. این فایل در برنامه ما stdio.h است که در برنامه وارد شده است. کمی عمیق تر به این موضوع نگاه کنیم و ببینیم اصلا چی هست و به چه دردی میخوره.
در یونیکس( و طبعا C و لینوکس) مفهومی بنام کتابخانه های استاندارد اشتراکی وجود دارد. این کتابخونه ها چی هستند و چه کاری انجام میدهند؟ با یک مثال قضیه رو بشکافیم. فرض کنیم شما یه خونه یا ساختمون ساختید و باید گاز طبیعی رو به خونه تون بکشید. چیکار میکنید؟ آیا میرید یه لوله از دمِ درِ خونه تون میکشید تا پارس جنوبی در خلیج فارس؟ آیا این کار منطقیه؟ آیا اگر هر خونه ای اینکار رو بکنه نظم جامعه مختل نمیشه؟ قطعا شما همچین کاری رو نمیکنید. یک شرکت متولی میاد با شاه لوله های بزرگ گاز رو به هر استان و شهری میرسونه. و با تقسیمات و انشعابات، لوله گاز رو تا دمِ درِ خونه تون میاره. این دقیقا مفهوم کتابخونه های اشتراکیه. عده ای برنامه نویس خبره نشستن و کتابخونه هایی رو نوشتن تا هر برنامه نویسی مجبور نباشه برای کارهای روتین، خیل عظیمی از کدها رو به تنهایی بنویسه. این کار چندین مزیت بزرگ داره. اول اینکه در وقت برنامه نویس صرفه جویی میشه. دوم اینکه برنامه کوچک و کم حجم خواهند شد. دلیل دارم برای حرفم. این لینک رو نگاه کنید: stdio.h.
۱۶۰ خط کد! شما میتونستید اون خطی رو که حاوی

#include<stdio.h>

بود رو پاک کنید و این ۱۶۰ خط رو قرار بدید یا خودتون ساز و کاری برای گرفتن ورودی و دادن خروجی مینوشتید. اما آیا منطقیه؟ کدومش راحت تره؟ در واقع شما با نوشتن اون یک خط کل محتوای فایل stdio.h رو در برنامه خودتون کپی کردید. به همین دلیل است که حجم برنامه های یونیکسی از برنامه های ویندوزی کمتر است. مثلا برنامه VirtualBox رو در نظر بگیرید. در هنگام نگارش این مطلب، حجم نسخه لینوکسیش ۶۵ مگابایت و حجم نسخه ویندوزیش ۱۰۹ مگابایته. این به این دلیل که در ویندوز هر برنامه باید کتابخانه های خودشو، رو دوشش اینور اونور بکشه. مزیت سوم امنیتشه. این کتابخانه رو افراد با تجربه و خبره مینویسند و به صورت اوپن سورس در معرض دید همگان قرار دادن. نمیتونن توش کدهای مخرب کار بزارن. چون میلیونها چشم و چشمان خود شما مراقبشه. در حالی که اگر هر برنامه نویس خودش بخواد این توابع رو برای خودش بنویسه میتونه هر کد دلخواه مخربی رو درش قرار بده. مزیت چهارمش پایداری و بهینه بودنشه. زیرا این کدها کار افراد خبره ست و چون بصورت اوپن سورس روی وب قرار گرفته هر بنی بشری میتونه بهتر و پایدارترش کنه. برای دیدن کتابخانه های استاندارد موجود در سیستم خودتون میتونید به این مسیرها سر بزنید:

/usr/include/
/usr/lib/gcc/include/

دلیل اینکه به این کتابخونه ها استاندارد میگن اینه که سازمان استانداردسازی زبان C تمام سازندگانی رو که کامپایلر میسازن مجبور کرده این کتابخونه ها رو داشته باشن. در غیر اینصورت قادر به دریافت استاندارد نخواهند بود. بعلاوه این کتابخانه های استاندارد، هر کامپایلری میتونه بنابر احساس نیازی که در جامعه کاربرانش میبینه کتابخانه های دیگری رو هم قرار بده. همچنین اگر شما بر روی پروژه ای کار میکنید و به کتابخانه های بخصوصی نیاز دارید که باید در چند برنامه مورد استفاده قرار بگیرند ولی بصورت استاندارد موجود نیستند، میتوانید کتابخانه های شخصی مخصوص خودتون را بسازید. در این باره در آینده بیشتر و مفصل تر بحث خواهیم کرد.
این کتابخانه بخصوص ما به اسم stdio.h مخصوص برنامه هایی است که در اون برنامه قراره ورودی از/خروجی به کاربر داشته باشه. اسمش مخفف standard input output است و پسوند h مخفف header یا سرآیند است. در واقع بدون وجود این برنامه مجاز به استفاده از تابع printf نمیبودیم.
سوالی که ممکن است برای شما پیش بیاید این است که چرا باید برای هر برنامه ای این کتابخونه رو وارد کدمون بکنیم؟ مگر نه اینکه ورودی/خروجی یکی از پرکاربردترین المانهای مورد استفاده در هر برنامه است؟ سوال شما بجاست. اما اگر مبحث استانداردها رو مطالعه کرده باشید، در اون استانداردها به وضوح قید شده که زبان C باید در کوچکترین حالت ممکن باشه و چیز اضافه ای درش نباشه. بعلاوه، خیلی از برنامه هایی که برای سیستم های توکار نوشته میشوند، نیازی به گرفتن ورودی از کاربر و دادن خروجی به او ندارند. بعنوان مثال برنامه ای که در خودروها مقدار سوخت موجود در باک را نمایش میدهد، نیازی به دخالت کاربر ندارد. ورودی خود را از برنامه ای دیگر تحت عنوان آرگومان میگیرد و خروجیش را نیز به برنامه دیگری برگشت میدهد.
این نوع از دستورات رو در زبان C به اسم دستورات پیش پردازنده میشناسیم و علامت # معرف این نوع از دستورات هستند. اما چرا پیش پردازنده؟ یادتونه در بحث کامپایلر از چیزی به نام لینکر اسم بردم؟ اینجا لینکر یا ارتباط دهنده کارش مشخص میشه. در واقع این دستورات پیش پردازنده هستند، چون قبل از اینکه چیزی در برنامه پردازش بشه، این فایلها هستند که لینک میشن به برنامه. این کار رو لینکر انجام میده که قسمتی از کامپایلرهای امروزیه.

تابع main
تابع main چنانچه از اسمش پیداست در واقع مهمترین و اصلی ترین تابع همه(بجز تعدادی معدود که میتوانید اکنون نادیده بگیرید) برنامه هاست. شرح و چیستی تابع رو هم به دوست عزیزمون arcush واگذار میکنم. وجود تابع main در برنامه الزامی است. زیرا C از تابع main شروع به اجرای برنامه میکند.
یکبار دیگه با هم این خط رو مرور کنیم:

int main(void)

تابع main رو که شرح دادیم. پرانتز جلوی main نمایانگر اینه که main یک تابع است. دو مورد باقی میمونه. اول int که قبل از main اومده و دوم void داخل پرانتز.
با یک مثال بامزه شروع کنیم. من دوستم رو به اسم محمد صدا میزنم. محمد اینجا یک تابعه. میگم محمد اون برنجها رو وزن کن ببین چقدره. این دستوری که من به محمد دادم آرگومانه. محمد بعد از وزن کردن برنجها بهم میگه که ۵ کیلو بود. این ۵ کیلو مقدار بازگشتیِ تابعیه به نام محمد. پس داده ای رو به محمد دادم و محمد بعد از پردازش به من خروجی داد. حالا بریم سراغ بحث فنی.
ببنید در واقع هر تابعی دو مشخصه داره. مشخصه اول آرگومانها یا پارامترهاییه که میگیره. و مشخصا دوم مقداری که پس از پردازش برمیگردونه. به چه صورت؟ فرض کنید یک تابع دارید که کارش جمع زدن دو عدد و برگردوندن حاصل جمعه. این تابع دوتا آرگومان داخل پرانتز میگیره و یک نتیجه ای رو بعد از پردازش پس میده. اینکه اینجا ما داخل پرانتز کلمه void به معنی خالی یا empty رو نوشتیم اینو میرسونه که ما نمیخوایم به این تابع چیزی بدیم. استاندارهای C90 و ماقبلش کلمه void رو داخل پرانتز قبول نمیکنه و این قانون در استاندارد C99 به بعد وارد C شد. ممکنه کامپایلر شما پرانتز خالی رو بپذیره. اما اگر میخواید که برنامه تون، روی هر سیستمی قابل اجرا باشه و بعدها به مشکل نخورید، شما هم از آخرین استانداردها پیروی کنید و از آرگومان void استفاده کنید.
حالا میرسیم به int که قبل از تابع main اومده. گفتیم که هر تابع مقادیری رو تحت عنوان آرگومان یا پارامتر میپذیره و مقادیری رو بعد از پردازش به برنامه ای که اون تابع رو صدا زده پس میده. همینجا عرض کنم که صدا زدن یا فراخواندن تابع دقیقا مثل مفهومیه که ما آدمها بکار ببریم. وقتی ما بخوایم کسی رو صدا کنیم اسمشو میبریم. مثل مثال محمد. ما اینجا تابع محمد رو صدا زدیم. اما کی صداش کرده؟ هیچ تابعی قبل از محمد وجود نداره. پس کار کی میتونه باشه؟ اگه درست حدث زدید برای خودتون اسپند دود کنید. درسته. سیستم عامل تابع main رو صدا زده. در واقع برای همینه که مهمترین تابعه. چون ازون خفنهای روزگاریه که سیستم عامل خودش مستقیم صداش میزنه. پس int چی بود؟ کلا int و void انواعی از داده ها هستن که در باره شون مفصل حرف خواهیم زد. int مخفف integer به معنی عدد صحیح یا عدد غیر اعشاری ست. خب اینجا از تابع main خواسته شده که یک عدد صحیح رو به سیستم عامل برگردونه. اما کو عدد؟ کو صحیح؟ یه بار دیگه سورس برنامه رو نگاه کنید؟ این int جلوی تابع main با اون return 0 موذی کاملا در ارتباطه. صفر یک عدد صحیحه و دستور return به معنی برگشت دادنه. برگشت دادن به کسی که صداش زده. که در اینجا سیستم عامله.
اما چرا صفر؟ قحطیه عدده؟ این یک بیشتر جنبه تاریخی داره تا قانون. در یونیکس، که C هم برای توسعه یونیکس خلق شد چنین در نظر گرفته شد که اگر برنامه ای پس از بسته شدن کد صفر رو به سیستم عامل پس داد، به این معنیه که برنامه به درستی اجرا شده. باور نمیکنید؟ بزارید تست کنیم. در ترمینال سیستم عاملتون دستور

ls -a

رو وارد کنید. در کمترین حالت یک نقطه و یه دو نقطه رو میبینید. حالا دستور

echo $?

رو اجرا کنید. یه صفر باحال میبیند. این کد رو بهش میگن exit status code. یعنی چی؟ هر برنامه ای که در سیستم عاملهای یونیکسی(تا جایی که میدونم) بسته میشه یک کد حالت خروج رو میفرسته به سیستم عامل تا سیستم عامل بفهمه چجوری بسته شده. صفر یعنی عالی و بی مشکل بسته شده. اگر برنامه ناموفق اجرا بشه کدی غیر از صفر رو برمیگردونه و هر کد مشخص کننده یک نوع خطاست. بیاید امتحانش کنیم و یه دستور من دراوردی بنویسیم(نرید براش alias بسازید:)

saeed

دستور رو اینتر کنید. با پیغامی مبنی بر اینکه دستور یافت نشد مواجه میشید. حالا بیاد آخرین exit status code رو بررسی کنیم:

echo $?

عددی غیر صفر(۱۲۷) به شما نشون داده میشه. اینجاست که میتونید بفهمید اون return چرا جلوش صفره. سیستم عامل از برنامه خواسته که یک مقدار صحیح رو بهش برگردونه. اگر برنامه تا آخرین خط به درستی اجرا بشه خب این خط نیز اجرا خواهد شد:

return 0;

پس خیلی منطقیه. میگیم اگر تا اخرین دستور (return 0) درست پیش رفتی صفر رو بعنوان exit status code به سیستم عامل برگردون. در حقیقت بازگردوندن صفر = اعلام اجرای موفقیت آمیز برنامه. پس اگر برنامه به هر شکل نتونه به این خط برسه یعنی نتونسته با موفقیت اجرا بشه و صفر هم دیگه برنمیگرده. چون اصلا به این خط نرسیده متوقف شده. اگر هم این خط رو ننویسید باز هم ممکنه برنامه به درستی اجرا بشه. اما خوبه که طبق قوانین مندرج در آخرین استانداردها پیش بریم و اون خط رو همیشه بنویسیم. بعضی کامپایلرها این شکل از تابع main  رو میپذیرن:

void main()

اما هیچ استانداردی ازین کاربرد اسم نبرده. پس بهتره برای دوری از انواع مشکلاتی که ممکنه پیش بیاد ازین نوع نوشتن حذر کنید و مطابق استانداردها پیش برید.

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

اعلان متغیر
متغیر اصلا چی هست؟ اعلان متغیر چیه؟
در سیستم های کامپیوتری دو نوع کلی حافظه وجود داره. حافظه فرار یا volatile و حافظه غیرفرار یا non-volatile. همونطور که از اسمشون پیداست در حافظه های فرار اطلاعات موندگار نیستند. در این نوع از حافظه ها، اطلاعات پس از قطع برق، از حافظه پاک میشوند. انواع مختلفی از حافظه های فرار وجود دارند که به ترتیب زیر هستند. در نظر داشته باشید قیمت و سرعت رابطه بسیار مستقیمی با هم دارند و هرچقدر سریعتر باشند گرانتر هستند و گنجایش کمتری دارند:
۱- ثبات یا رجیستر
۲- کش
۳- رم یا حافظه اصلی
حافظه های غیر فرار مانند ssd ها و هاردیسک و دیسک نوری برای ذخیره دائمی اطلاعات مورد استفاده قرار میگیرند.
متغیرها همونطور که از اسمشون مشخصه متغیرن و مقدارشون در طی اجرای برنامه میتونه تغییر کنه. ما برای متغیرها اسم تعیین میکنیم. مانند num در برنامه ای که نوشتیم. در واقع متغیر اسمیه که برای قسمتی از حافظه تعیین میکنیم که مقدار مورد نظر ما در اون مستقر میشه. متغیرها انواع گوناگونی دارند. مثل int که گفتیم نشان دهنده عدد صحیحه. اما چرا نوع؟ یه توضیحی بدم بعد بریم سراغ دلیل تعیین نوع.
گفتیم پردازنده سرعت بسیار بسیار زیادی داره. مثلا یک پردازنده با سرعت 4 گیگاهرتز میتونه ۴ میلیارد عملیات را در یک ثانیه انجام دهد. این واقعا عدد بزرگیه. اگر پردازنده بخواد با چنین سرعتی اطلاعات و دستور العملها رو از هارد دیسک و امثال اون بخونه کارها بسیار کند میشه چون سرعتی بسیار بسیار کمتر دارند و وقت عظیمی از پردازنده هدر میره. برای رفع این مشکل اومدن حافظه های سریعتر با حجم کمتری ساختن که در اون فقط اطلاعاتی قرار بگیره که نیاز به پردازش دارند. انواع گوناگونی از حافظه معرفی شد. یکیشون همین رم بود. قطعا سرعت رم نیز در برابر سرعت پردازنده کند است اما نسبت به هر نوع حافظه غیر فراری بسیار بیستر است. برای رسیدن به بهینه ترین حالت پردازنده، حافظه های دیگری مثل کش و ثبات معرفی شدند. در واقع داده هایی که در رم منتظر پردازش هستند بصورت نوبتی در آرایه هایی به کش و ازونجا به ثباتها برای پردازش فرستاده میشن و بعد از پردازش به رم بر میگردن. در حینی که پردازنده مشغول محاسبات است این نقل و انتقالات پیوسته انجام میشود و پردازنده بسیار کمتر بیکار و منتظر میماند. در یک سیستم کامپیوتری منابع سخت افزاری از اهمیت زیادی برخوردار هستند و چون محدود نیز هست هر پروسه و برنامه ای نباید به میل خود به هر مقدار و خودسرانه به منابع دست پیدا کنه. اینجاست که سیستم عامل وارد میدان میشه. در واقع سیستم عامل برنامه ایه که در لایه پایین سیستم(روی سخت افزار لخت) میشینه و میشه مسئول تخصیص منابع سخت افزاری. هر برنامه ای که احتیاج به رم یا پردازنده یا ورودی/خروجی داشته باشه باید با سیستم عامل حرف بزنه. و این سیستم عامله که مسئول تخصیص منابع به برنامه ها میشه. وقتی برنامه ما هم اجرا میشه به کرنل یا هسته سیستم عامل میگه که من احتیاج به منابع سخت افزاری دارم. حالا این برنامه ما باید به کرنل بگه که چه مقدار رم و به چه شکلی میخواد.کرنل هم پس از بررسی های دقیق و کامل بهش اوکی میده و برنامه رو برای اجرا وارد رم میکنه.  این مقدار و شکل رو نوع متغیر تعیین میکنه. چرا اصلا باید اینجوری باشه؟ گفتیم که زبان C زبان بسیار بهینه شده ایه. تصور کنید C به نوع داده ای ۶۴ بیت جا میداد. اونوقت یک عدد ساده مثل یک ۶۴ بیت از حافظه رو میگرفت، در صورتی که با یک بیت نیز میتوان عدد ۱ رو در رم نگه داشت. اینجاست که انواع مختلف داده ها پا به عرصه وجود میزارن. درباره انواع مختلف متغیرها و ویژگی ها و مکانیسم های هر متغیر در ادامه تاپیک به طور کامل صحبت خواهیم کرد. در اینجا فقط در همین حد باید بدونید که با نوشتن کلمه کلیدی int، به برنامه میگیم که متغیر ما از نوع عدد صحیح است(چون مقدار رمی که برای عدد صحیح در نظر گفته میشود با انواع داده های دیگر مثل عدد اعشاری فرق دارد) پس به اندازه یک عدد صحیح(فارغ از مقداری که ما میدهیم) برای آن در رم جا در نظر بگیر.
و حالا =
مساوی رو در ریاضی خوندیم و همه مون آشنایی داریم باهاش. اما در برنامه نویسی تفاوت داره معناش با ریاضی. در ریاضی عبارت

5+1=6

رو اینگونه مخونیم که ۵ بعلاوه یک مساویست با ۶. اما در برنامه نویسی اینگونه نیست. در برنامه نویسی یک مقدار عددی هیچگاه نمیتواند در سمت چپ مساوی قرار بگیرد. دلیلشو الان خدمتتون عرض میکنم. دلیلش اینه که این علامت = در برنامه نویسی اصلا مساوی خونده نمیشه بلکه انتساب خونده میشه. به چه صورت؟
برگردیم به برنامه خودمون num = 1. در ریاضی بدین گونه خونده میشه num مساویست با ۱. اما در برنامه نویسی به این صورت خوانده میشه: عدد ۱ رو در متغیر num قرار بده. عدد ۱ رو به num نسبت بده. در C برنامه از بالا به پایین و از چپ به راست خونده میشه توسط کامپایلر. یکی از معدود مواردی که کامپایلر از راست به چپ میخونه همین علامت انتصابه، پس حالا میفهمیم چرا عدد نمیتونه در سمت چپ انتساب قرار بگیره. چون نمیتونیم بگیم متغیر num رو در ۱ قرار بده. چون ۱ یه عدده و ثابته و هیچ عددی جایی برای ذخیره چیزی نداره بلکه این متغیرها هستند که جا برای ذخیره سازی دارند.
پس دوباره و بطور خلاصه مرور میکنیم:

int num = 1;

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

نامگذاری متغیر
در نامگذاری متغیرها باید به چند نکته دقت کرد.
اول اینکه اینکه نام متغیر گویای چیزی باشه که هست. مثلا فرض کنید دوتا متغیر به اسم قد و وزن داریم. سعی کنیم از خودِ کلمات قد و وزن استفاده کنیم.

int height;
int weight;

همین رو میتونستیم با x و y  هم تعریف کنیم. اما برای خواننده برنامه بسیار بی معنیه. حتی بعد از گذشتن مدتی، شاید خودمونم نفهمیم این x و y چکارن. پس توصیه میشه از نامهای با معنی استفاده کنید.
در صورتی که به هر دلیل نتونستید از نام بامعنی برای متغیرهاتون استفاده کنید، حتما کامنت یا توضیحات براشون بگذارید:

float r;    // Circle Radius

اینجا ما از نام با معنی برای متغیرمون استفاده نکردیم. اما در توضیحات نوشته ایم که این متغیر شعاع دایره میباشد.

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

تابع ()printf
از کلمه print متوجه میشویم که وظیفه این تابع چاپ اطلاعاتی در خروجی است. این اطلاعات، همان مقادیری است که در داخل پرانتز آمده است. حرف f مخفف formatted یا قالب بندی شده است. زیرا تابع ()printf خروجی را پیراسته و قالب دهی میکند. عملکرد و نحوه کار این تابع در فایل stdio.h مشخص شده است. علامتهای دابل کوتیشن " در ابتدای و انتهای رشته های کاراکتری الزامی است. در مورد رشته های کاراکتری در آینده بحث خواهیم کرد. هرآنچه که بین پرانتزها قرار میگیرد، آرگومان خوانده میشود. این آرگومانها را تابع ()main به تابع ()printf ارسال کرده است(پاس داده است). بیاید یه لحظه عمیقتر به سیستم برنامه نگاه کنیم. برنامه ما با تابع ()main شروع شده. تمام دستورات از بالا به پایین اجرا میشوند و هنوز کنترل در اختیار ()main است. در لحظه ای که به تابع ()printf میرسیم کنترل برنامه از دست ()main خارج شده و کنترل به ()printf میرسد. این تابع بعد از اتمام کار، کنترل برنامه رو به ()main میده مجدد. یه لحظه به بحث قبلمون برگردیم. یادتون هست گفتیم تابع ()main صحت اجرای هر تابع رو چک میکنه و خودِ سیستم عامل هم مستقیم صحت اجرای تابع ()main رو کنترل میکنه؟ خب خب. الان تابع ()main باید چجوری بفهمه که تابع ()printf درست کار کرده؟ اینو موکول میکنیم به بحث ساختارهای تصمیم. فقط خواستم در نظر داشته باشید که تابع ()printf یک مقدار عددی رو به تابعی که صداش زده برمیگردونه.
مورد بعدی در این برنامه ما که در تابع ()printf دیده میشه بک اسلش یا backslash است. همینجا یه توضیحی بدم:

/    slash or forward slash
\    backslash

بک اسلش در C و بسیاری از زبانها معرف و نشانگرِ توالیهای فراره. توالی چیه؟ فرار از دست کی؟
توالی یعنی پشت سرم هم و ممتد. ازین جهت بهش میگن توالی چون مستقیما پشت سر این آقای بک اسلش باید کاراکتر معنا دار بیاد. کاراکتر معنا دار کاراکتریه که بطور استاندارد براش یه رفتار و وظیفه توصیف شده باشه.
فرار از دست کی؟ دشمن. فرار از دست f در ()printf. گفتیم که این تابع خروجیش رو قالب دهی میکنه. فکر کنید شما در حال نوشتن اطلاعاتی در تابع ()printf باشید که این اطلاعات برای تابعمون معنای مشخصی دارند. چجوری باید به تابع ()printf بگیم که ما منظورمون چیز دیگه ایه؟ یا مثلا میخواهید که تابع بعد از چاپ اطلاعات موجود در خودش، یک خط فاصله بده و بره خط بعدی؟ چجوری بهش میگید که یه خط رد کن؟ اینتر میزنید؟ اولا Enter کلیدیه که برای شما معنا داره نه برای اون. ثانیا بعد از اجرای برنامه، شما فقط در قسمتهایی که ورودی میخواد، قدرت زدن اینتر رو دارید. اگر برنامه ورودی نپذیره، اینتری در کار نخواهد بود. در حقیقت وقتی ما کلید اینتر رو میزنیم دستوری رو از صفحه کلید به سمت سیستم عامل میفرستیم. که محتوای اون دستور به زبان ساده اینه که یک خط رد کن. پس سیستم عامل چنین دستوری رو میفهمه. حالا ما بجای زدن اینتر بطور سخت افزاری و دستی، ازش میخواهیم خودش همچین دستوری رو بدون دخالت کاربر به سیستم عامل بده.
در مثال ما در تابع ()printf توالی فرار n\ وجود داره.
در مثال ما n\ بیانگر ایجاد یک خط جدید است. n را با newline یا خط جدید به خاطر بسپارید. توالی های فرار دیگری نیز وجود دارند که در جای خود شرع خواهیم داد.
نکته ای که حائز اهمیت است بکار بردن این توالی هاست. یکبار دیگر کد منبع برنامه این پست و نتیجه آن را نگاه کنیم:

printf("I am a simple ");    // use the printf() function
    printf("program.\n");

Output

I am a simple program.

همانطور که مشاهده کردید، صرفِ نوشتن جمله در دو خط، به معنای جدا کردن خطوط در خروجی نیست. اما خط بعد از دومین تابع ()printf بدلیل داشتن n\ در انتهای آن، خالی رد میشود.
در مورد سِمیکالُن یا نقطه ویرگول هم یک توضیح بدم. در C، حضور ; به معنای اتمام دستور میباشد. بگونه ای که حتی اگر اینتر هم نزنیم و تمام دستورات را در یک خط بنویسیم قابل پذیرش است. این دو برنامه هر دو یک کار انجام میدهند:

#include<stdio.h>
int main(void)
{
	printf("Hello world!");
	return 0;
}
#include<stdio.h>
int main(void){printf("Hello world!");return 0;}

کد نویسی به شیوه دوم باعث ناخوانا شدن برنامه میشود. خوانایی برنامه را قربانی هیچ چیز نکنید.

آخرین ویرایش توسط Ritchie (2018-09-06 17:24:34)

آفلاین

#11 2018-08-30 13:24:41

Arcush
Moderator
ثبت شده: 2015-09-15
ارسال ها: 1,449

پاسخ: C اَت را قورت بده.

تابع؛ بخش نخست

ممکنه در ریاضی اسم تابع را شنیده باشید. در اونجا دربارهٔ اینکه یک تابع ماشینی هست که ورودی می گیره و  خروجی میده صحبت می کنند. همچنین معمولن اصرار دارند که خروجیِ تابع منحصر به فرد هم باشه. مجموعهٔ ورودی های تابع ( = دامنه) و مجموعه ای که خروجی های تابع درون اون قرار دارند ( = بُرد) هم باید کاملن و بدون هیچ ابهامی مشخص باشند.
در C باید یه مقداری این تصور را بهم بریزید. درحقیقت، ممکنه که یک تابع دامنه، بُرد و یا هتا هیچ یک ازونها را نداشته باشه. یعنی ممکمنه هیچ مقداری را بعنوان ورودی نگیره و یا هیچ مقدارِ خاصی را بعنوان خروجی نده. درحالت کلی، در C یک تابع بصورت

type functionName (type_0 a_0, type_1 a_1, ..., type_n a_n) {
Do some instructions on variables.
}

مشخص میشه. در اینجا type میتونه همون بُردِ اشاره شده در بالا باشه که بهش "نوعِ تابع" هم خواهیم گفت. پس تابعی از نوع int یعنی تابعی که خروجیِ اون int هست. پارامترهای a_0 تا a_n هم را که به ترتیب از نوع های type_0 تا type_n هستند "آرگومان های پاس داده شده به تابع" می نامیم. همچنین برخی یا همهٔ  type و type_0، type_2، ...، type_n ها میتوانند یکی هم باشند. اگر type را void قرار بدیم در اینصورت تابع مقداری را برنخواهند گرداند.

نمونه۱:

int multiply (int a, int b) {
	return a * b;
}

در اینجا مشاهده می کنید که نام تابع ()multiply هست و دو تا ورودی میگیره که هردوشون از نوع int هستند. وقتی این تابع صدا زده بشه (در بدنهٔ برنامه به کار گرفته بشه) دستورالعمل هایی که داخل بدنهٔ تابع یعنی داخل {} هستند به کار گرفته میشند. تنها دستورالعمل در اینجا

return a * b;

هست. کلیدواژهٔ رزرو شدهٔ return در هر تابعی که در C به کار گرفته بشه (که بسیار هم رخ میده) باعث پایان یافتن کار تابع خواهد شد و مقداری را که برنامه نویس مشخص کرده "برمیگردونه". در این نمونه، برنامه نویس a * b را جلوی return قرار داده و بنابراین تابع با برگردوندن حاصلضرب a و b به پایان میرسه. اجرای کد

return a * b;

باعث میشه یک متغیر بدون نام از نوع int (همون نوع تابع) ساخته بشه تا a * b بعنوان خروجی تابع داخلش قرار بگیره. این متغیر temporary هست و تنها در خطی از کد که تابع صدا زده میشه ایجاد میشه و پس ازون هم از بین خواهد رفت.

در بارهٔ نام تابع، باید دقت کنید که وقتی می نویسیم  ()multiply یعنی داریم دربارهٔ تابعی به نام multiply حرف میزنیم و فراموش نکنید که نوشتن "تابع multiply" مرسوم نیست. بعبارت دیگه، هنگام حرف زدن درمورد تابع، هتمن باید دوتا پرانتز را جلوی نام تابع بنویسیم. این تفاوت در بخش structها در آینده بیشتر مشهود خواهد شد. 

توجه کنید که

return;

هیچ چیزی را برنمیگردونه  (ما در آینده ازین موضوع بعنوان یک ترفند در حلقه ها و گزاره های شرطی استفاده خواهیم کرد). درحقیقت چون return به کار تابع خاتمه میده، میشه اون را در جایی از کد قرار داد (هتا در تابع های از نوع void) که به دلایلی به دنبال خاتمهٔ کار هستیم. اگر یک تابع فاقد return باشه تمام خطوط داخل بدنهٔ تابع اجرا خواهند شد. در این حالت، آکولادی که تابع با اون بسته میشه داره کار return را انجام میده. اگر نیازی به برگردوندن خروجی نمی بینید پس نوع تابع را void قرار بدید. اگر نوع تابع را چیزی قرار ندید (یعنی از نوشتن type صرف نظر کنید) نوع پیشفرضِ int توسط C انتخاب خواهد شد.

شکل عمومیِ return statement به صورت

return my_value;

هست که my_value میتونه constant، variable، یک محاسبه (مثل a * b در مثال ما)، یک نشانگر، یک عبارت بولی و هتا صدا زدن یک تابع دیگه باشه (که در بخش مثال انواع اینها را خواهیم دید).

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



اکنون کدِ زیر را اجرا کنید.

#include <stdio.h>

int multiply(int a, int b) {
	return a * b;
	}

int main () {
	int n = multiply(3, 5);
	printf("%d\n", n);
	return 0;
	}

و خروجیِ 15 را در نمایشگر ببینید. ابتدا تابع  ()multiply را خارج از بدنهٔ main تعریف کردیم (البته این تنها راه نبوده و روش های بهتری هم هستند که بررسی اونها را در آینده در قسمت پروتوتایپ های تابع ها انجام خواهیم داد). سپس دو عدد صحیح 3 و 5 را بهش پاس دادیم. این تابع این دو عدد را در هم ضرب خواهد کرد. سپس ما این حاصلضرب را در متغیر n قرار دادیم*. این کار باعث میشه که مقدار موقتی multiply(3, 5) پس از پایان صدا زده شدنِ تابع، از بین نره. [میتونستیم در اینجا روش دیگری را هم در پیش بگیریم. یعنی بجای اینکه مقدار موقتی

multiply(3, 5)

را داخل متغیر n ذخیره کنیم، اون را  مستقیم چاپ کنیم:

int main () {
	printf("%d\n", multiply(3, 5));
	return 0;
	}

کدوم یک از این دو روش بهتر هستند؟ پاسخِ صریحی وجود نداره. درواقع، با توجه به هدف های بعدیِ برنامه نویس و شاید هدف های قبلیش این دو روش در موقعیت های مختلف جایگزین هم بشن. بهرحال، وقتی من تصمیم می گیرم که مقدار موقتیِ multiply(3, 5) را توی یه متغیر ذخیره کنم، پس هتمن میخوام در جایی ازون استفاده کنم و این استفاده احیانن بیشتر از نشون دادنِ تنها یک خروجی باید باشه. بعبارت دیگه من باید دلیلی برای این که این مقدار موقتی را ذخیره کردم ارائه بدم.]

  سپس n را چاپ کردیم**. خط بعدی یعنی

return 0;

هم بخاطر این هست که خروجیِ تابع main را int قرار دادیم و در یونیکس بیس ها، 0 را معمولن بمعنای اجرای موفقیت آمیز در نظر میگیرند***. قرار دادن این خط در کد باعث میشه بتونیم بگیم که برنامه با موفقیت اجرا شده یانه. همونطوری که سعید گفت ?$ متغیری هست که مقداری را که return در خط آخر برنامه برگردونده در اون ذخیره میشه. کد بالا را با نام try.c ذخیره کنید و به ترتیب دستورهای زیر را برای حالت های 0، 1 و 1- بزنید:

$ gcc -o try try.c
$ ./try
$ echo $?

همچنین خط

return 0;

را حذف کرده و دستورهای بالا را بزنید. در نهایت هم اسم خودتون را در جایی از کد بنویسید و دستورهای بالا را بزنید.

یک بار دیگه به تابعی که تعریف کردیم نگاه کنید. دو متغیر a و b که درون تابع استفاده شدند متغیرها (آرگومان های) موضعی نام دارند. این متغیرها بلافاصله پس ازینکه تابع پایان یافت از بین خواهند رفت.  در این مورد میتونیم این سؤال را مطرح کنیم که چرا این متغیرها بصورت موضعی ساخته شدند و اگر هم نام متغیرهای دیگه در بلوک های دیگه باشند چه اتفاقی میفته (بلوک های کد آکولادهای باز و بسته هستند که خطوط کد درون اونها قرار دارند). البته با توجه به اسم "موضعی بودن" می تونیم پاسخ را حدس بزنیم: هر بلوک متغیرهای موضعی خودش را داره و از وجود متغیرهای موضعی هم نام یا غیر هم نام با متغیرهای خودش در بلوک های دیگه بیخبره. بحث بیشتر در مورد متغیرهای موضعی و سرتاسری  (variable scope) و ارتباط اونها با حافظه هیپ و استک  را به آینده موکول می کنیم.


مقداردهیِ اولیه آرگومان های تابع:


لزوم استفاده از تابع:  کاهش دادن حجم کد همواره مطلوب هست و از اولین ایده های رسیدن به این هدف استفاده از تابع می باشد. در حقیقت، وقتی قرار هست یک کار را بیش از یک بار انجام بدید اون کار را تبدیل به یک تابع کرده و به این ترتیب از چندباره کاری جلوگیری میشه. یک تابع میتونه به تعداد دفعات دلخواه به کار گرفته بشه و به این ترتیب  با استفادهٔ چندباره ار تابع در نوشتن کد صرفه جویی شده. استفاده از تابع همچنین می تونه باعث تفهیم بهتر کد هم بشه. این یک اصل هست که هر مساله ای را چه در کامپیوتر و چه در بیرون ازون با تقسیمش به تکه های کوچکتر میشه بهتر حل کرد. تابع ها هم در توازی با این اصل قرار دارند. به عبارت دیگه، اگر من به کدی که سعید نوشته اعتماد داشته باشم، میتونم بدون توجه به بدنهٔ تابعی که نوشته (اینکه اون تابع چطوری داره کار می کنه) تنها با استفاده از اسم اون تابع کارم را راه بندازم. در اینجا پای مفهومی به نام abstraction به میان کشیده میشه. بدون اینکه درگیر چگونگی کار یه چیزی بشی، می تونی از اون استفاده کنی.   

در بخش بعد، مثال هایی از تابع ها خواهیم آورد.

-----------------------------------
* ما در آینده در بارهٔ const کردن مقدار return و اینکه چقدر لازم و مفیده که این کار را بکنیم، حرف خواهیم زد.
** آیا این n خودِ n هست؟ ما در آینده دربارهٔ نشانگرها و آدرس ها و اینکه چقدر می تونیم این کد را بهبود بدیم حرف خواهیم زد. 
*** خطاها در آینده بررسی خواهند شد.

آخرین ویرایش توسط Arcush (2018-08-30 14:49:06)

آفلاین

#12 2018-09-10 01:10:54

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

به نام خدا
ادامه مبحث قبل
مبحث قبلی در مورد تشریح عناصر موجود در برنامه ای بود که مثال زدیم. یه مورد که توضیحش برای الان موند d% بود.
گفتیم تابع ()printf تابعیه که خروجیشو قالب دهی میکنه. در باره شیوه و مکانیزم قالب دهی به مرور بیشتر آشنا میشم.
در C ما تعدادی identifier یا مشخص کننده داریم. هر نوع داده ای، مشخص کننده خاص خودش رو داره. برای نوع داده عدد صحیح یا int دو نوع مشخص کننده وجود داره: d% و i%. در استفاده از هرکدوم ازینها مختارید. ولی چیزی که مهمه اینه که بدونید برای مشخص کردن عدد صحیح در C ازین دو نوع مشخص کننده استفاده میشه. خب فرض کنیم ما در تابع ()printf از این مشخص کننده استفاده کردیم. بعد چه خواهد شد.
مثال قبلمون رو دوباره بررسی کنیم:

printf("My favorite number is %d because it is first.\n", num);

گفتیم که C یک زبان کامپایلیه. یعنی کامپایلر یک بار اون رو ترجمه و به زبان ماشین برمیگردونه و یک فایل اجرایی بهمون میده. پس همه چیز در حین کامپایل باید درست باشه.
یکبار دیگه به اون خط کد نگاه کنید. در میانه متن d% قید شده است. این به کامپایلر میگه که آقا/خانم کامپایلر اینجا قراره یه عدد صحیح چاپ بشه. کامپایلر هم میگه مشکلی نیست ولی کدوم عدد صحیح؟ تابع ()printf به کامپایلر میگه: همون عدد صحیحی که در یک متغیر قرار گرفته و نام متغیر مستقیما بعد از این رشته اومده. کامپایلر میره نگاه میکنه ببینه که چه متغیریه. در توابع علامت ویرگول یا کاما مشخص کننده جدایی است. کامپایلر میره نگاه میکنه یه ویرگول هست. میفهمه که اینجا آرگومان اول که یک رشته بوده تموم شده و به دنبال آرگومان یا پارامتر دومه.  آرگومان دوم یه متغیره به نام num. نگاه میکنه ببینه آیا همچین متغیری در برنامه تعریف شده یا نه. و میبینه که بله چند خط بالاتر این متغیر از نوع عدد صحیح یا int تعریف شده و به خوشی و سلامتی این خط رو قبول میکنه. حالا هر وقت این برنامه اجرا بشه، مقدار موجود در متغیر num در محل d% قرار میگیره و چاپ میشه. هر یک از خطوط برنامه رو اینگونه برای خودتون بشکافید میبینید که واقعا چیز سختی نیست.

آخرین ویرایش توسط Ritchie (2018-09-10 04:01:12)

آفلاین

#13 2018-09-10 03:28:09

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

برنامه های چندتابعی یا Multiple Functions

در این قسمت قصد داریم تا کاملا شیوا و ملموس با ارائه مثالی واقعا ساده نحوه کار برنامه های چند تابعی رو شرح بدیم.
شیوه ای که در استانداردهای ANSI/ISO C برای برنامه های چند تابعی ذکر شده، شیوه نمونه سازی تابع یا Function Prototyping است. از اسم قلمبه سلمبه اش نترسید. خیلی سرراست و آسونه.
فرض کنیم من بعنوان سعید پسری به نام قباد و همسایه ای به نام جمشید دارم. از پسرم میخوام که یک کاسه آش نذری برای همسایه مون ببره. میخوام این کار رو با توابع انجام بدم.پسرم رو صدا میزنم و بهش میگم کاسه آش رو برای همسایه ببره.آش رو میبره و کاسه آش رو بهشون میده. پس نام برنامه اصلی که من باشم سعید است. شروع کنیم به نوشتن شبه کد این برنامه:

۱-فراخوانی پسرم
۲-دادن مسئولیت به قباد
۳-صدا زدن همسایه توسط قباد
۴-اعلام خبر کار انجام شده به من از طریق قباد

با حاله. شروع کنیم
اول من باید دوتا تابع تعریف کنم. در اینجا برای ساده سازی برنامه و درک بهتر از هیچ آرگومان و مقدار بازگشتی استفاده نمیکنم. پس هم نوع آرگومان ارسالی و هم نوع داده بازگشتی خالی یا void خواهد بود.
برنامه رو با توضیحات کم کم بنویسیم:
saeid.c
اولین کار در نوشتن هر برنامه باید نوشتن توضیحات اون برنامه باشه:

/* saeid.c
 * This program is a simple example of using multiple functions in C
 * Feel free to change names according to your willing
 */

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

#include<stdio.h>

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

void Ghobad(void);       // ANSI/ISO C function prototyping
void Jamshid(void);

در اینجا ما به درستی توابعی رو که میخواهیم استفاده کنیم به برنامه معرفی کردیم. به ; یا نقطه ویرگول پایان هرتابع دقت کنید. در شیوه پروتوتایپ باید بعد از معرفی تابع، بلافاصله سِمی کالن در انتهای معارفه توابع نوشته شود.
حالا برنامه مون رو مثل مثال قبلی نرمال پیش میبریم. استفاده از تابع ()main:

int main(void)

حالا نوبت به نوشتن بدنه تابع میرسه. بدنه تابع با یک آکولاد باز شروع میشه و به آکولاد بسته ختم میشه:

{

خب حالا باید اول یه متن بنویسیم. تو اون متن قید کنیم که میخواهیم چیکار کنیم. این متن توضیحات نیست بلکه جزو برنامه است. مثلا من در این متن از پسرم میخوام که یک کاسه آش به همسایه مون بده:

printf("Hey Ghobad, can you please give this bowl of pottage to Jamshid?\n");

خب من در خط بالا به پسرم گفتم که برام یک کاری انجام بده. حالا چجوری به گوشش برسونم؟ با صدا زدن. بیایید قباد رو صدا بزنیم. برای صدا زدنش کافیه اسمشو ببریم. پرانتزهای جلو اسمش نمایانگر اینه که قباد یک تابعه. و چون هیچ آرگومانی بهش نمیدیم میتونیم اینجا در هنگام صدا زدن نوع داده آرگومان رو ذکر نکنیم:

Ghobad();       // we call Ghobad to do something

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

}

تا به اینجا چیزی شبیه این داریم:

/* saeid.c
 * This program is a simple example of using multiple functions in C
 * Feel free to change names according to your willing
 */
#include<stdio.h>
void Ghobad(void);       // ANSI/ISO C function prototyping
void Jamshid(void);

int main(void)
{
    printf("dad: Hey Ghobad, can you please give this bowl of pottage to Jamshid?\n");
    Ghobad();       // we call Ghobad to do something

}

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

void Ghobad(void)

دقت کنید پس از شروع به تعریف تابع دیگر از سمی کالن استفاده نمیکنیم. زیرا پس از این با یک آکولاد باز شروع میکنیم به تعریف تابعمون. در اینجا آقا قباد با دو تابع ()printf یکبار جواب پدرش رو میده و بار دوم به همسایه میگه که برای چه کاری اومده:

{
    printf("Ghobad: Hey dad, of course I can, why not?\n");
    printf("Ghobad: Hey Jamshid. My father has sent me to give you this pottage bowl. Can you take it please?\n");

پس از این گفتگوی خلاصه حالا قباد میخواد پیغامش رو به جمشید هامسایه شون برسونه. در نتیجه جمشید رو صدا میزنه:

    Jamshid();      // calling Jamshid

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

}

پله بعدی تعریف تابع جمشید است. قراره جمشید آقا جواب پسر ما رو بده و یه تشکری هم بکنه. به این صورت:

void Jamshid(void)
{
    printf("Jamshid: Hi Ghobad. Thank you for such a generous manner.\n");
}

پس ما تابع جمشید رو مثل تابع قباد تعریف کردیم. پس از اینکه کامپایلر به آکولاد بسته پایان تابع جمشید رسید، کنترل برنامه رو به تابع صدا زننده که در اینجا قباده برمیگردونه. ما میتونستیم در اینجا قبل از آکولاد پایانی، تابع ()Ghobad رو صدا بزنیم تا کنترل رو به تابع ()Ghobad برگردونه. اما یک مشکلی داشت. وقتی تابع جمشید تابع قباد رو صدا بکنه، تابع قباد از ابتدا اجرا میشه. پس دوباره جمشید رو صدا میکنه. جمشید هم در هر اجرا تابع قباد رو صدا میکرد. در این حالت به یک چرخه نامتنهای بازگشتی یا recursive گرفتار میشدیم. عین اکوی صدا در کوه اما بدون استهلاک. این دوتا هی همدیگه رو صدا میکردن و هی تعارف تکه پاره میکردن. ولی وقتی تابع جمشید بصورتی که نوشتیم، ختم بشه، کنترل برنامه خودبخود به تابع صدا زننده برمیگرده و به بعد از فراخوانی تابع جمشید برمیگرده. یعنی به بعد از اخرین دستور اجرا شده در تابع صدازننده. آخرین دستور اجرا شده در تابع قباد همین صدا زدن جمشید بوده. دلیلش هم روشنه. تابع جمشید رو یکبار صدا زده و کارشم انجام داده. حالا باید ببینیم آیا قباد کاری داره یا نه. اگر کاری داشته باشه انجام میشه وگرنه کنترل به برنامه صدا زننده قباد، یعنی پدرش برمیگرده. البته که قباد کار داره. قباد میخواد به باباش بگه که جمشید تشکر کرده. پس تا به اینجای کار ما این دو تابع رو اینگونه نوشتیم:

void Ghobad(void)
{
    printf("Ghobad: Hey, of course I can, why not?\n");
    printf("Ghobad: Hey Jamshid. My father has sent me to give you this pottage bowl. Can you take it please?\n");
    Jamshid();      // calling Jamshid

}

void Jamshid(void)
{
    printf("Jamshid: Hi Ghobad. Thank you for such a generous manner.\n");
}

حالا بریم تابع ناتمام قباد رو کامل کنیم. قراره قباد به باباش بگه که جمشید آقا تشکر کرده:

    printf("Ghobad: Hey dad, Jamshid thanked you.\n");

خب قباد آقای ما آخرین حرفش رو هم زد و کارش تمام شد. حالا کنترل به تابعی برمیگرده که قباد رو صدا زده. تابع پدر یا ()main. اول ببینیم تا اینجا چی داریم و بعد بریم و قسمتهای ناتمام اون رو هم کامل کنیم:

/* saeid.c
 * This program is a simple example of using multiple functions in C
 * Feel free to change names according to your willing
 */
#include<stdio.h>
void Ghobad(void);       // ANSI/ISO C function prototyping
void Jamshid(void);

int main(void)
{
    printf("dad: Hey Ghobad, can you please give this bowl of pottage to Jamshid?\n");
    Ghobad();

}

void Ghobad(void)
{
    printf("Ghobad: Hey, of course I can, why not?\n");
    printf("Ghobad: hey Jamshid. My father has sent me to give you this pottage bowl. Can you take it please?\n");
    Jamshid();      // calling Jamshid
    printf("Ghobad: Hey dad, Jamshid thanked you.\n");
}

void Jamshid(void)
{
    printf("Jamshid: Hi Ghobad. Thank you for such a generous manner.\n");
}

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

    printf("dad: Thank you son.\n");
    
    return 0;

و در آخر برنامه کامل شده ما به این شکل خواهد بود:

/* saeid.c
 * This program is a simple example of using multiple functions in C
 * Feel free to change names according to your willing
 */
#include<stdio.h>
void Ghobad(void);       // ANSI/ISO C function prototyping
void Jamshid(void);

int main(void)
{
    printf("dad: Hey Ghobad, can you please give this bowl of pottage to Jamshid?\n");
    Ghobad();
    printf("dad: Thank you son.\n");
    
    return 0;
}

void Ghobad(void)
{
    printf("Ghobad: Hey, of course I can, why not?\n");
    printf("Ghobad: Hey Jamshid. My father has sent me to give you this pottage bowl. Can you take it please?\n");
    Jamshid();      // calling Jamshid
    printf("Ghobad: He thanked you.\n");
}

void Jamshid(void)
{
    printf("Jamshid: Hi Ghobad. Thank you for such a generous manner.\n");
}

قبل از توضیحات تکمیلی برنامه مون رو کامپایل و اجرا کنیم:

gcc saeid.c -o saeid
./saeid

خروجی برنامه مون رو ببینیم با هم:

dad: Hey Ghobad, can you please give this bowl of pottage to Jamshid?
Ghobad: Hey, of course I can, why not?
Ghobad: Hey Jamshid. My father has sent me to give you this pottage bowl. Can you take it please?
Jamshid: Hi Ghobad. Thank you for such a generous manner.
Ghobad: He thanked you.
dad: Thank you son.

همونطور که دیدید کار بسیار خفنی نکردیم. برنامه نویسی بر ایده و منطق و اصول استوار شده. دقیقن مثل یک ساختمون. همونطور که یه بنای ساختمانی درسته از آسمون سقوط نمیکنه، یک برنامه هم درسته از آسمون سقوط نمیکنه رو زمین. درست مثل بنّایی اول یه هدف و چارچوب رو برای خودمون معین میکنیم. ایده مون رو رو کاغذ میاریم. با مصالحی که در اختیاریم داریم درست و منطقی و قدم به قدم پیش میریم و ترکیبشون میکنیم. هر آجری رو درست در جای خودش مینشانیم و در آخر به یک بنای چشم نواز میرسیم. این یک مثال ساده بود برای اینکه برنامه های چند تابعی براتون جا بیفته. مطمئن باشید اصل قضیه همینه و اگر این رو فهمیده باشید چیز زیاد دیگری باقی نمونده که راجع به اصل توابع بدونید. همین درس رو با مثالهای دیگری در ادامه این پست و در همین تاپیک بیشتر بسط خواهیم داد.

آخرین ویرایش توسط Ritchie (2018-09-10 16:31:25)

آفلاین

#14 2018-09-10 17:56:07

Ritchie
عضو
ثبت شده: 2018-08-06
ارسال ها: 16

پاسخ: C اَت را قورت بده.

کلمات کلیدی زبان C
هر زبانی تعدادی کلمه کلیدی رزرو شده مخصوص بخودش رو داره. کلمات کلیدی هر زبان، برای اون زبان معنا و مفهوم خاصی دارند. این کلمات کلیدی رو نمیتونیم به عنوان نام متغیر یا تابع و ثوابت بکار ببریم. همچنین نام توابع موجود در کتابخانه های استاندارد نیز برای ما قابل استفاده نیستند. زیرا کامپایلر C در برخورد با این نامها، توقع دارد که برنامه نویس حق کلمات رزرو شده زبان C را محترم شمرده باشد. لیست کلمات کلیدی C به شرح زیر است:
5oh2_photo_2018-09-10_17-43-31.jpg

آفلاین

پانوشت انجمن

پشتیبانی توسط تیم آرچ لینوکس ایران و نیرو گرفته با FluxBB