Язык программирования Си был разработан в начале 1970-х годов сотрудниками лаборатории Bell Кеном Томпсоном и Денисом Ритчи для использования в создаваемой ими операционной системе Unix. Для выполнения работы по созданию Unix разработчики нуждались в таком языке программирования, который был бы кратким, а также мог бы обеспечивать эффективное управление аппаратными средствами, мог бы создавать компактные, быстро работающие программы.
Традиционно такие потребности программистов удовлетворял язык ассемблера, который тесно связан с внутренним машинным языком компьютера. Однако ассемблер — язык низкого уровня, т.е. он привязан к определенному типу процессора (или компьютера). Поэтому если программу на языке ассемблера необходимо перенести на компьютер другого типа, ее приходится переписывать заново на другом языке ассемблера. Это можно сравнить с ситуацией, когда при покупке нового автомобиля вы каждый раз обнаруживаете, что конструкторы решили изменить расположение и назначение органов управления, вынуждая вас заново переучиваться вождению.
Операционная система UNIX предназначалась для работы на компьютерах различных типов (или платформах). А это предполагало использование языка высокого уровня. Язык высокого уровня ориентирован на решение задач, а не на конкретное аппаратное обеспечение. Специальные программы, которые называются компиляторами, транслируют программу, написанную на языке высокого уровня, в команды внутреннего языка конкретного компьютера. Таким образом, используя отдельный компилятор для каждой платформы, одну и ту же программу на языке высокого уровня можно выполнять на разных платформах. Разработчики Unix нуждались в языке, который сочетал бы в себе эффективность и возможность доступа к аппаратным средствам, обеспечиваемые языками низкого уровня, с более общим характером и переносимостью, присущими языкам высокого уровня. Поэтому на основе имевшихся в то время более старых языков программирования Ритчи и Томпсоном был разработан язык С.
Рассмотрим философию языка С. В общем случае язык программирования базируется на двух основных понятиях — это данные и алгоритмы. Данные представляют собой информацию, которую программа обрабатывает. А алгоритмы — это методы, которые программа использует (для обработки данных, см. рис.). Язык С, как и болыпинство основных языков программирования того времени, является процедурным — это означает, что основной акцент в нем делается на алгоритмах. Теоретически процедурное программирование заключается в том, что сначала определяется последовательность действий, которая должна быть выполнена компьютером, а затем эти действия реализуются с помощью языка программирования. Программа содержит набор процедур, которые компьютер должен выполнить, чтобы получить требуемый результат. Такая деятельность во многом напоминает кулинарный рецепт, который предписывает последовательность действий (процедур), необходимых для выпечки пирога. При использовании первых процедурных языков, таких как FORTRAN и BASIC, по мере увеличения объема программ пришлось столкнуться с проблемами организационного плана. Например, в программах часто используются операторы ветвления, которые в зависимости от результатов некоторой проверки направляют ход выполнения программы на тот или иной набор операторов. Во многих старых программах алгоритм настолько запутан, что его крайне сложно понять при чтении текста, а модификация такой программы чревата осложнениями. Чтобы решить эту проблему, компьютерщики разработали более упорядоченный стиль программирования, называемый структурным программированием. Язык С включает ряд элементов, облегчающих применение структурного программирования. Например, структурное программирование ограничивает возможности ветвления (выбора следующего выполняемого оператора) небольшим набором хорошо функционирующих конструкций. Эти конструкции (циклы for, while, do while и оператор if else) входят в словарь языка С.
Еще одним из новых принципов программирования было проектирование программ сверху вниз.
Идея заключается в разбиении большой программы на более мелкие, легче решаемые задачи. Если одна из этих задач по-прежнему остается слишком обширной, ее также следует разделить на более мелкие задачи. Этот процесс продолжается до тех пор, пока программа не будет разделена на маленькие, легко программируемые модули. (Рассмотрим пример. Есть просьба: наведите порядок в своем кабинете. Ой! Хорошо, наведите порядок в письменном столе, на столе и на своих книжных полках. Ох! Хорошо, начните с письменного стола и наведите порядок в каждом выдвижном ящике, начиная со среднего. Гм, с этой задачей я, пожалуй, могу справиться.) Язык С упрощает такой подход, поскольку "поощряет" программистов разрабатывать программные единицы (элементы), называемые функциями, которые представляют собой модули отдельных задач. Как можно было заметить, методика структурного программирования отражает процедурный подход, при котором программа рассматривается с точки зрения выполняемых ею действий.