سی (زبان برنامه‌نویسی)
سی یک زبان برنامه‌نویسی از نوع همه‌منظوره، کامپایل‌شونده، سطح میانی، ساخت‌یافته، دستوری و روندگرا می‌باشد که در سال ۱۹۷۲ توسط دنیس ریچی در آزمایشگاه‌های بل ساخته شد. در سال ۱۹۶۷ مارتین ریچاردز زبان BCPL را برای نوشتن نرم‌افزارهای سیستم‌عامل و کامپایلر در دانشگاه کمبریج ابداع کرد. سپس در سال ۱۹۷۰ کن تامسون زبان B را بر مبنای ویژگی‌های زبان BCPL نوشت و از آن برای ایجاد اولین نسخه‌های سیستم‌عامل یونیکس در آزمایشگاه‌های بل استفاده کرد. زبان C در سال ۱۹۷۲ توسط دنیس ریچی از روی زبان B و BCPL در آزمایشگاه بل ساخته‌شد و ویژگی‌های جدیدی همچون نظارت بر نوع داده‌ها نیز به آن اضافه شد. ریچی از این زبان برای ایجاد سیستم‌عامل یونیکس استفاده کرد اما بعدها اکثر سیستم‌عامل‌های دیگر نیز با همین زبان نوشته‌شدند. این زبان با سرعت بسیاری گسترش یافت و چاپ کتاب "The C Programming Language" در سال ۱۹۷۸ توسط برایان کرنیگان و ریچی باعث رشد روزافزون این زبان در جهان شد.
استفادهٔ گسترده این زبان در انواع رایانه‌ها و سخت‌افزارهای مختلف باعث شد که نسخه‌های مختلفی از این زبان به‌وجود آید که با یکدیگر ناسازگار بودند. در سال ۱۹۸۳ مؤسسه استانداردهای ملی آمریکا (ANSI) کمیته‌ای موسوم به X3J11 را را مأمور کرد تا یک تعریف فاقد ابهام و مستقل از ماشین را از این زبان تدوین نماید. در سال ۱۹۸۹ این استاندارد تحت عنوان ANSI C به تصویب رسید و سپس در سال ۱۹۹۰، سازمان بین‌المللی استانداردسازی (ISO) نیز این استاندارد را پذیرفت و مستندات مشترک آنها تحت عنوان ANSI/ISO C منتشر گردید.
مانند بسیاری از زبان‌های رویه‌ای در سنت الگول، سی دارای امکاناتی برای برنامه‌نویسی ساخت یافته است و دامنهٔ متغیر واژگان را امکان‌پذیر می‌سازد. سیستم نوع استاتیک آن از انجام عملیات ناخواسته جلوگیری می‌کند. در C، کلیهٔ کدهای اجرایی در زیر برنامه‌ها (که «توابع» نیز نامیده می‌شوند وجود دارد، گرچه به معنای برنامه‌نویسی کاربردی کاملاً دقیق نیست). پارامترهای عملکرد همیشه توسط مقدار منتقل می‌شوند. گذر توسط مرجع در C با عبور صریح مقادیر اشاره‌گر شبیه‌سازی می‌شود. متن منبع برنامهٔ C با فرمت آزاد است و با استفاده از دکتر کلمات به عنوان یک اصطلاح کننده بیان و بندهای فرفیژه برای گروه‌بندی جمله‌ها استفاده می‌شود.
در حالی که C ویژگی‌های خاصی را که در زبان‌های دیگر یافت می‌شود (مانند جهت‌یابی اشیاء و جمع‌آوری زباله)، این موارد را می‌توان پیاده‌سازی یا تقلید کرد، غالباً با استفاده از کتابخانه‌های خارجی (به عنوان مثال، سیستم اشیاء GLib یا جمع‌آوری زباله Boehm).
بسیاری از زبان‌های بعدی به‌طور مستقیم یا غیرمستقیم از C وام گرفته‌اند، از جمله C ++ , C #، C , Unix's C shell , D، Go , Java , JavaScript (از جمله ترانسپلرها)، Limbo , LPC , Objective-C، Perl , PHP , Python , Rust, Swift, Verilog و SystemVerilog (زبان‌های توصیف سخت‌افزار). این زبان‌ها بسیاری از ساختارهای کنترلی خود و سایر ویژگی‌های اصلی را از C ترسیم کرده‌اند. بیشتر آن‌ها (پایتون یک استثناء چشمگیر) نیز نحو کاملاً مشابهی را با C نشان می‌دهند، و آن‌ها تمایل دارند ترکیب و نحو قابل تشخیص C را با نوع زیرین ترکیب کنند. سیستم‌ها، مدل‌های داده‌ها و معنایی که می‌توانند تفاوت چشمگیری با یکدیگر داشته باشند.
منشأ C با توسعه سیستم عامل یونیکس کاملاً مرتبط است، که در ابتدا با زبان اسمبلی بر روی PDP-7 توسط دنیس ریچی و کن تامپسون پیاده‌سازی شده و چندین ایده از همکاران را دربر گرفته‌است. سرانجام، آنها تصمیم گرفتند سیستم عامل را به PDP-11 منتقل کنند. نسخه اصلی PDP-11 یونیکس نیز به زبان اسمبلی تولید شده‌است.
تامپسون یک زبان برنامه‌نویسی را برای ایجاد برنامه‌های کاربردی برای سیستم عامل جدید می‌خواست. در ابتدا، او سعی کرد تا کامپایلر Fortran بسازد، اما خیلی زود این ایده را رها کرد. در عوض، او یک نسخه برش خورده از زبان برنامه‌نویسی سیستم‌های BCPL که اخیراً توسعه یافته بود، ایجاد کرد. توضیحات رسمی BCPL در آن زمان موجود نبود و تامپسون نحو (syntax) را اصلاح و کم‌حرف‌تر و B را مشابه اما کمی ساده‌تر تولید می‌کند با این حال، کمترین ابزارها نهایتاً در B نوشته شدند زیرا خیلی کند بود و B نمی‌توانست از ویژگی‌های PDP-11 مانند آدرس پذیری بایت بهره ببرد.
در سال ۱۹۷۲، دنیس ریچی شروع به بهبود B کرد، که منجر به ایجاد زبان جدید C شد. کامپایلر C و برخی از برنامه‌های کاربردی ساخته شده با آن در نسخه ۲ یونیکس گنجانده شده‌است. در نسخه ۴ یونیکس، که در نوامبر ۱۹۷۳ منتشر شد، هسته یونیکس به‌طور گسترده‌ای در C دوباره اجرا شد. در این زمان، زبان C ویژگی‌های قدرتمندی مانند انواع ساختار را به دست آورده بود.
در سال ۱۹۷۸، برایان کرنیگان و دنیس ریچی چاپ اول کتاب زبان برنامه‌نویسی C را منتشر کردند. این کتاب که به عنوان K&R برای برنامه نویسان C شناخته شده بود، سالها به عنوان مشخصات غیررسمی زبان مورد استفاده قرار گرفت. نسخه C که توصیف می‌کند معمولاً با عنوان "K&R C" شناخته می‌شود. چاپ دوم کتاب شامل استاندارد بعدی ANSI C است که در زیر شرح داده شده‌است.
در اواخر دهه ۱۹۷۰ و ۱۹۸۰، نسخه C برای طیف گسترده‌ای از رایانه‌های اصلی، مینی رایانه و میکرو رایانه‌ها از جمله IBM PC پیاده‌سازی شد، زیرا محبوبیت آن به میزان قابل توجهی افزایش یافت.
در سال ۱۹۸۳، مؤسسه استاندارد ملی آمریکا (ANSI) کمیته ای با نام X3J11 تشکیل داد تا مشخصات استاندارد C را ایجاد کند. X3J11 براساس استاندارد C بر روی اجرای یونیکس؛ با این حال، بخش غیرقابل حمل از کتابخانه یونیکس C به گروه کاری IEEE 1003 واگذار شد تا پایه ای برای استاندارد POSIX 1988 باشد. در سال ۱۹۸۹، استاندارد C با عنوان ANSI X3.159-1989 "زبان برنامه نویسی C" تصویب شد. این نسخه از زبان اغلب به عنوان ANSI C، استاندارد C یا بعضی اوقات C89 گفته می‌شود.
در سال ۱۹۹۰، استاندارد ANSI C (با تغییرات قالب بندی) توسط سازمان بین‌المللی استانداردسازی (ISO) به عنوان ISO / IEC 9899: 1990 تصویب شد، که گاهی اوقات C90 نیز نامیده می‌شود؛ بنابراین، اصطلاحات "C89" و "C90" به همان زبان برنامه‌نویسی اشاره دارند.
استاندارد C در اواخر دهه ۱۹۹۰ بازنگری شد و منجر به انتشار ISO / IEC 9899: 1999 در ۱۹۹۹ شد، که معمولاً به آن "C99" گفته می‌شود. از آن زمان سه بار توسط غلط‌های فنی اصلاح شده‌است.
C99 چندین ویژگی جدید از جمله توابع درون خطی، چندین نوع داده جدید (از جمله int long long و یک نوع مختلط برای نشان دادن اعداد مختلط)، آرایه‌های با طول متغیر و اعضای آرایه انعطاف‌پذیر، پشتیبانی بهبود یافته از IEEE 754 نقطه شناور، پشتیبانی از ماکرو متغیر را معرفی کرد؛ و پشتیبانی از نظرات تک خطی که با // شروع می‌شود، مانند BCPL یا C ++. بسیاری از این موارد قبلاً به عنوان پسوند در چندین کامپایلر C اجرا شده بودند.
C99 در اکثر موارد با C90 سازگاری پسرو دارد، اما از بعضی جهات سخت‌تر است. به ویژه، بیانیه‌ای که فاقد یک مشخص کننده نوع است، دیگر به‌طور ضمنی فرض شده‌است. یک کلان استاندارد __STDC_VERSION__ با مقدار 199901L تعریف شده‌است تا نشان دهد که پشتیبانی C99 در دسترس است. GCC , Solaris Studio و سایر کامپایلرهای C اکنون از بسیاری از ویژگی‌های جدید C99 پشتیبانی می‌کنند. کامپایلر C در ++Microsoft Visual C، استاندارد C89 و قسمت‌هایی از C99 را که برای سازگاری با C ++ 11 لازم است، پیاده‌سازی می‌کند.
در سال ۲۰۰۷، کار بر روی تجدید نظر در مورد استاندارد C، به‌طور غیررسمی به نام "C1X" تا انتشار رسمی آن در تاریخ ۲۰۱۱-۱۲-۰۸ آغاز شد. کمیته استاندارد C دستورالعمل‌هایی را برای محدود کردن استفاده از ویژگی‌های جدید که توسط آزمایش‌های موجود آزمایش نشده‌اند، اتخاذ کرده‌است.
استاندارد C11 چندین ویژگی جدید به C اضافه می‌کند و کتابخانه، از جمله ماکرو نوع عمومی، ساختارهای ناشناس، پشتیبانی بهبود یافته یونیکد، عملیات اتمی، چند رشته‌ای و عملکردهای محدود شده را بررسی می‌کند. همچنین برخی از بخش‌های موجود در کتابخانه C99 را به اختیاری تبدیل کرده و سازگاری با ++C را بهبود می‌بخشد. کلان استاندارد __STDC_VERSION__ به عنوان 201112L تعریف شده‌است تا نشان دهد که پشتیبانی C11 در دسترس است.
C18 که در ژوئن سال ۲۰۱۸ منتشر شده استاندارد فعلی زبان برنامه‌نویسی C است. این معرفی هیچ ویژگی جدید زبان نداشت، فقط اصلاحات فنی و شفاف‌سازی در مورد نقص C11 را ارائه می‌دهد. کلان استاندارد __STDC_VERSION__ با عنوان 201710L تعریف شده‌است.
یکی از مهم‌ترین قابلیت‌های زبان C، امکان استفاده از اشاره‌گرهاست. اشاره‌گرها کارایی، قدرت و انعطاف‌پذیری برنامه را بیشتر می‌نمایند. علاوه بر فراهم آوردن امکان نوشتن کدهای برنامهٔ کوتاه‌تر، غنی‌تر و کاراتر، گاهی مواردی پیش می‌آید که انجام محاسبات مورد نیاز برنامه تنها توسط اشاره گرها امکان‌پذیر می‌باشد. به همین دلیل، از این توانایی در برنامه‌های C زیاد استفاده می‌گردد. اگر چه در ظاهر کار با اشاره‌گرها مشکل است و درک برنامه‌ای که از آنها استفاده شده‌است ساده نیست، اما در حقیقت اگر از آنها به درستی استفاده گردد، وضوح و سادگی برنامه افزایش می‌یابد.
روش مستقیم دسترسی به حافظه برای ذخیره‌سازی مقداری در آن، یا بازیابی محتوای ذخیره شده، استفاده از نام متغیر است. همین که متغیری معرفی شد، سیستم بر اساس نوع اعلام شده، تعداد بایت لازم را به آن اختصاص می‌دهد و آدرس متغیر، شماره اولین بایت از مجموعهٔ اختصاص یافته‌است. پس از آن به راحتی از طریق نام متغیر به محل موردنظر دسترسی یافته، محتوای آن پردازش می‌گردد. اما گاهی لازم می‌شود به جای نام، آدرس متغیر در اختیار برنامه‌نویس قرار گیرد تا از طریق آن دستیابی به محل مربوط صورت گیرد. در زبان C، به راحتی می‌توان آدرس یک متغیر را در اختیار داشت و مقدارش را در حافظه ذخیره نمود تا در زمان نیاز، توسط آن به صورت غیرمستقیم به محل موردنظر دست یافت. برای این منظور از متغیر اشاره‌گر استفاده می‌گردد. متغیر اشاره‌گر، متغیری است که محتوای آن آدرس یک متغیر دیگر است.
بسیاری از موارد پیش می‌آید که برنامه‌نویس نیاز به استفاده از تعداد زیادی متغیر پیدا می‌کند؛ مثلاً اگر بخواهیم جملات ۱ تا ۱۰۰ سری فیبوناچی را برای استفاده ذخیره کنیم، به صد متغیر نیاز داریم. تعریف این صد متغیر به صورت مستقل و با نام‌های جداگانه کاری سخت و طاقت‌فرساست و البته معقول نیست. به همین خاطر در زبان C قابلیتی پیش‌بینی شده تا بتواند تعداد دلخواهی متغیر از یک نوع را به راحتی ایجاد کرد.
به این متغیرها که در حافظه پشت سر هم قرار می‌گیرند و همگی از یک نوع هستند آرایه (Array) می‌گویند. آرایه‌ها کاربردهای بسیار زیادی دارند و همانند دنباله‌ها در ریاضی عمل می‌کنند. همان‌طور که در ریاضی برای مشخص کردن یک جمله از دنباله از اندیس استفاده می‌کنیم، در C نیز برای مشخص کردن یک متغیر خاص از اندیس استفاده می‌شود.
همان‌طور که مشاهده می‌کنید خانهٔ پنجم شمارهٔ ۴ دارد و این بدین خاطر است که خانه‌ها از شمارهٔ ۰ تا n-1 (که n تعداد خانه‌هاست) شماره‌گذاری می‌شود. پس باید به این مورد دقت کرد. مورد دیگر این که شمارهٔ خانه در [] قرار می‌گیرد. درون علامت آکلاد می‌توان عبارت نیز قرار داد.
همان‌طور که گفته شد در حافظهٔ رایانه خانه‌های آرایه پشت سر هم قرار می‌گیرند. اندازهٔ هر خانه به اندازهٔ نوع تعریف شده‌است؛ مثلاً در مثال قبل اگر int دو بایت اشغال کند آرایهٔ array، در کل ۲۰ بایت از حافظه اشغال خواهد کرد. این که خانه‌ها پشت سر هم قرار می‌گیرند ویژگی کارایی است که در بحث اشاره‌گرها به کار می‌آید.
یکی از مهمترین کارکردهای یک زبان برنامه‌نویسی، فراهم آوردن امکاناتی برای مدیریت حافظه و مواردی است که در حافظه ذخیره می‌شوند. C سه روش مشخص برای اختصاص حافظه برای اشیاء ارائه می‌دهد: این سه رویکرد در موقعیتهای مختلف مناسب است و دارای تبعات مختلفی است. به عنوان مثال، تخصیص حافظه استاتیک اختصاص کمی به سربار دارد، تخصیص خودکار ممکن است کمی بیشتر از سربار باشد و تخصیص حافظه پویا به‌طور بالقوه می‌تواند مقدار زیادی از سربار را برای تخصیص و جابجایی داشته باشد. ماهیت پایدار اشیاء استاتیک برای حفظ اطلاعات حالت در طول فراخوانی‌های عملکردی مفید است، تخصیص خودکار به راحتی قابل استفاده است اما فضای پشته معمولاً بسیار محدودتر و گذرا از حافظه استاتیک یا فضای پشته است و تخصیص حافظه پویا امکان تخصیص مناسب اشیاء را می‌دهد که اندازه فقط در زمان اجرا شناخته شده‌است. بیشتر برنامه‌های C از هر سه مورد استفاده گسترده‌ای می‌کنند.
در صورت امکان، تخصیص اتوماتیک یا استاتیک معمولاً ساده‌ترین است زیرا ذخیره‌سازی توسط کامپایلر اداره می‌شود، و برنامه‌نویس را از روی خطای بالقوه خطا در اختصاص و آزاد سازی فضای ذخیره‌سازی آزاد می‌کند. با این وجود بسیاری از ساختارهای داده می‌توانند در زمان اجرا تغییر کنند و از آنجا که تخصیص استاتیک (و تخصیص خودکار قبل از C99) باید در زمان کامپایل اندازه ثابت داشته باشد، موقعیت‌های بسیاری وجود دارد که تخصیص پویا لازم است. قبل از استاندارد C99، آرایه‌های اندازه متغیر نمونه متداول این امر بودند. (به عنوان مثال از آرایه‌های اختصاص داده شده پویا به مقاله در مورد malloc مراجعه کنید) برخلاف تخصیص خودکار، که می‌تواند در زمان اجرا با عواقب کنترل نشده از کار بیفتد، عملکردهای تخصیص پویا هنگام ذخیره‌سازی مورد نیاز، نشانه (به صورت مقدار اشاره گر تهی) را برمی‌گردانند. نمی‌توان اختصاص داد (قبل از اینکه برنامه حتی بتواند اجرای آن را شروع کند، معمولاً توسط لینک دهنده یا لودر تشخیص داده می‌شود)
مگر در مواردی که مشخص شده باشد، اشیاء استاتیک حاوی مقادیر نشانگر صفر یا تهی هنگام شروع برنامه هستند. اشیاء اختصاص داده شده به صورت خودکار و پویا فقط درصورتی تنظیم می‌شوند که مقدار اولیه صریحاً مشخص شود. در غیر این صورت آنها در ابتدا مقادیر مشخص نشده‌ای دارند (به‌طور معمول، هر الگوی بیتی که در آن ذخیره می‌شود، حتی ممکن است یک مقدار معتبر برای آن نوع نداشته باشد). اگر برنامه سعی کند به یک مقدار ناشناخته دسترسی پیدا کند، نتایج مشخص نیست. بسیاری از کامپایلرهای مدرن سعی در کشف و هشدار دربارهٔ این مشکل دارند، اما هم مثبت‌های کاذب و هم منفی کاذب می‌تواند رخ دهد.
مسئله دیگر این است که تخصیص حافظه پشته باید با کاربرد واقعی آن در هر برنامه همگام سازی شود تا در استفاده مجدد از آن تا حد امکان استفاده شود. به عنوان مثال، اگر تنها اشاره گر برای تخصیص حافظه پنهان از محدوده خارج شود یا مقدار آن را قبل از بازنویسی بازنویسی کرده باشد () فراخوانی شود، پس از آن حافظه برای استفاده مجدد بعدی قابل بازیابی نیست و در اصل برای برنامه از بین می‌رود، پدیده ای معروف به a نشت حافظه در مقابل، امکان آزادسازی حافظه وجود دارد اما همچنان به آن مراجعه می‌شود و منجر به نتایج غیرقابل پیش‌بینی می‌شود. به‌طور معمول، علائم در بخشی از برنامه به دور از خطای واقعی ظاهر می‌شوند، و پیگیری مشکل را دشوار می‌کند. (چنین مواردی در زبانهایی که جمع‌آوری زباله‌های اتوماتیک دارند بهبود یافته‌است)
C دارای توابعی است که از قبل نوشته شده‌اند، و توابع کتابخانه‌ای نامیده می‌شوند. در واقع فرایندهایی که پر کاربرد هستند و در اغلب برنامه‌ها مورد استفاده قرار می‌گیرند به صورت توابع مستقل قبلاً نوشته شده‌اند؛ که به آنها هدر نیز می‌گویند.
زبان برنامه‌نویسی C از کتابخانه‌ها به عنوان روش اصلی توسعه آن استفاده می‌کند. در C، یک کتابخانه مجموعه ای از توابع موجود در یک پرونده «بایگانی» است. هر کتابخانه به‌طور معمول دارای یک فایل هدر است، که شامل نمونه‌های اولیه توابع موجود در کتابخانه است که ممکن است توسط یک برنامه مورد استفاده قرار گیرد، و اظهارات انواع داده‌های خاص و نمادهای کلان مورد استفاده با این توابع. برای اینکه یک برنامه از کتابخانه استفاده کند، باید پرونده سرصفحه کتابخانه را شامل شود، و کتابخانه باید با برنامه در ارتباط باشد، که در بسیاری موارد به پرچم‌های کامپایلر احتیاج دارد.
رایج‌ترین کتابخانه C، کتابخانه استاندارد C است که توسط استانداردهای ISO و ANSI C مشخص شده‌است و همراه با اجرای هر C (اجرای‌هایی که محیط‌های محدود مانند سیستم‌های جاسازی شده را هدف قرار می‌دهند، تنها می‌تواند زیر مجموعه ای از کتابخانه استاندارد را ارائه دهد). این کتابخانه از ورودی و خروجی جریان، تخصیص حافظه، ریاضیات، رشته‌های کاراکتر و مقادیر زمانی پشتیبانی می‌کند. چندین هدر استاندارد جداگانه (به عنوان مثال stdio.h) رابط‌های این و سایر امکانات کتابخانه استاندارد را مشخص می‌کند.
مجموعه رایج دیگری از توابع کتابخانه C مواردی است که توسط برنامه‌هایی که مخصوص سیستم‌های یونیکس و شبه یونیکس هستند، به ویژه توابعی که رابط کاربری هسته را هدف قرار می‌دهند مورد استفاده قرار می‌گیرد. این عملکردها در استانداردهای مختلفی از جمله POSIX و مشخصات UNIX تک به تفصیل شرح داده شده‌است.
از آنجا که بسیاری از برنامه‌ها به زبان C نوشته شده‌اند، انواع مختلفی از کتابخانه‌های دیگر در دسترس هستند. کتابخانه‌ها غالباً به زبان C نوشته می‌شوند، زیرا کامپایلرهای C کد شیئی کارآمد را تولید می‌کنند. برنامه نویسان سپس رابط‌هایی را برای کتابخانه ایجاد می‌کنند تا روال‌ها از زبان‌های سطح بالاتر مانند جاوا، پرل و پایتون استفاده شوند.
در سال‌های بعد و با ظهور روش‌های برنامه‌نویسی شئ‌گرا نسخه جدیدی از زبان C بنام ++C توسط بی‌یارنه استراس‌تروپ در اوایل ۱۹۸۰ در آزمایشگاه‌های بل توسعه یافت. در ++C علاوه بر امکانات جدید، خاصیت شئ‌گرایی نیز به C اضافه شده‌است.
با گسترش شبکه و اینترنت، نیاز به زبانی احساس شد که برنامه‌های آن بتوانند بر روی هر ماشین و هر سیستم‌عامل دلخواهی اجرا گردد. شرکت سان مایکروسیستمز در سال ۱۹۹۵ میلادی زبان جاوا را برمبنای C و ++C ایجاد کرد که هم‌اکنون از آن در سطح وسیعی استفاده می‌شود و برنامه‌های نوشته شده به آن بر روی هر کامپیوتری که از جاوا پشتیبانی کند (تقریباً تمام سیستم‌های شناخته شده) قابل اجرا می‌باشد.