Почему стоит начать изучение программирования с языка C +26


AliExpress RU&CIS

Краткое содержание: автор статьи объясняет, почему С хорош именно на этапе обучения и прокачки мозгов будущего программиста. А через некоторое время, или даже параллельно, можно выучить более современный язык и заняться, например, Enterprise- или Web-разработкой.


Фото: Liam Briese on Unsplash

Языков программирования становится всё больше. Сейчас их около 700. Однако в основном разработчики используют 20 из них. Здесь, как и во многих других сферах, существуют рейтинги, тренды и даже мода.

Назовём навскидку несколько популярных языков. Для Enterprise-разработки активно используют Java (скоро там закрепится и Kotlin), C#, для Web-разработки — JavaScript, Go, Python и PHP, для мобильной разработки — Swift, Java/Kotlin, ну и осмелюсь назвать JavaScript (потому что может, потому что React Native). Разработчики игр часто пользуются C# и С++. Все они востребованы по нескольким причинам:

  • упрощённый синтаксис (в большинстве своём) и ясная семантика — на фоне языка C;
  • полнофункциональный набор стандартных API;
  • активная поддержка сообщества;
  • растущая экосистема фреймворков и библиотек.

Язык С применяют при разработке программно-аппаратных решений. На С также можно частично реализовать функциональность программных продуктов, требовательных к производительности. Хотя далеко не каждый программист хочет и может работать на подобных проектах. Но вернёмся к этапу обучения.

Обычно будущие разработчики начинают программировать в школе, университете или на курсах по смене профессии. Последний вариант, к слову, сейчас сильно набрал популярность.

Рано или поздно они задаются вопросом: какой язык программирования лучше учить первым? В школе и университете на этот вопрос могут ответить за вас: чаще всего обучение там начинают с языка С/С++ (именно вот так, через «/»). Но на альтернативных обучающих площадках вряд ли вам тоже кто-то предложит просто поизучать С для расширения кругозора или прокачки мозгов. Всем хочется побыстрее, что называется, войти в ИТ. Так что, как видите, тут и там вам придётся проявить волю и самостоятельность, если решите начать изучение с языка С.  

В этой статье речь всё-таки пойдёт про этап обучения и становления будущего специалиста. Поэтому, позвольте, сейчас я изложу свои аргументы, а потом вы можете изложить свои.

C заставляет глубоко прорабатывать решение проблемы


Более современные языки предлагают сразу несколько встроенных абстракций (или абстракций из стандартных библиотек) на все распространённые случаи жизни. Это в первую очередь относится к стандартным алгоритмическим задачам. Например, если вам нужно скопировать определённые элементы из первого массива во второй, вы можете использовать встроенный метод filter() в JavaScript. Если пишете на Java, в вашем распоряжении метод filter() из пакета java.util.stream. 

JavaScript: Array.filter()

const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
// если длина слова больше 6, добавляем его в результирующий массив
const result = words.filter(word => word.length > 6);  
console.log(result);
// получится вот такой результат: Array ["exuberant", "destruction", "present"]

Java: stream().filter()

List<String> lines = Arrays.asList("spray", "limit", "elite");

// преобразуем List в Stream
List<String> result = lines.stream()              
// хотим исключить elite  
       .filter(line -> !"elite".equals(line))     

// сформируем коллекцию и преобразуем в List
       .collect(Collectors.toList());   

//получится вот такой результат:  spray, limit
        result.forEach(System.out::println);   

На языке С, особенно в учебных целях, можно предложить такую реализацию (чтобы не усложнять пример, я поменял строки на числа и изменил условие «фильтрации»):

#include <stdio.h>
#define SIZE 5

void copy_aka_filter_arr(double trg[], double src[], int n);

int main(void){
    int i;
    double source[SIZE] = {1.1, 2.2, 3.3, 4.4, 5.5};
    double target[SIZE];
   
 printf("Source:  ");
    for (i = 0; i < SIZE; i++){
        printf("%5.1f ", source[i]);
    }
    putchar('\n');
    copy_arr(target, source, SIZE);   
    return 0;
}

void copy_aka_filter_arr(double trg[], double src[], int n){
// копирует i-й элемент из исходного массива в новый, если он больше 3.3. 
// иначе записывает в i-й элемент нового массива 0.0 
    int i;
    for (i = 0; i < n; i++){
            if (trg[i]) > 3.3){     
                trg[i] = src[i];
            }
            else{
                trg[i] = 0.0;
            }
    }       
    printf("Target: ");
    for (i = 0; i < SIZE; i++){
        printf("%5.1f ", trg[i]);
    }
    putchar('\n');
}


Пытаясь реализовать такие функции руками, вы столкнётесь с фундаментальными принципами и нюансами, в которых нужно будет глубоко разобраться. В частности, самостоятельная реализация алгоритмов обработки структур данных на языке С — отличный способ научиться решать проблемы, а не искать готовые решения. 

На каком бы классном и продвинутом языке вы не писали, время от времени появляются сложные задачи, которые нельзя решить с использованием стандартных библиотек и встроенных абстракций. В этих случаях такой навык просто необходим.

Кстати, разработчики, участвующие в соревновательных хакатонах, часто тренируют этот скил, решая нестандартные задачи как раз на C.

C позволяет прикоснуться к «низкоуровневому» программированию


На современных высокоуровневых языках (Python, C#, Java или какой-то ещё на ваш вкус) удобно писать. Однако эти языки очень ограничивают взаимодействие с аппаратной частью. Другими словами, вы не получите полноценного опыта взаимодействия с «железом», пока не начнёте программировать на C. Современные языки программирования скрывают аппаратно-зависимые детали реализации и вместо этого эмулируют некую абстракцию. В большинстве случаев она создаётся с помощью виртуальной машины.

К сожалению, начинающие специалисты совсем не имеют представления об  управлении памятью, об обработке файлов и оптимизации кода, потому что они никогда не видели даже примеров «низкоуровневого» программирования на языке C. С этой точки зрения современные языки программирования автоматизируют и скрывают слишком много. Язык С заставляет делать многое руками и писать высокооптимизированный код.

Как по мне, такое должен попробовать каждый профессиональный разработчик. Ну, как минимум, бэкендер.

C учит свободе и ответственности


Когда язык программирования предлагает набор удобных для человека абстракций, он становится менее гибким. Каждый встроенный или библиотечный метод действует как жёстко запрограммированный чёрный ящик. Другими словами, современные языки программирования скрывают подробности реализации и предлагают разработчику просто обращаться к набору интерфейсов. Ручное управление распределением динамической памяти в современных языках программирования в большинстве случаев невозможно. Между тем, C даёт вам настоящую свободу, позволяя выбирать способ реализации на более низком уровне.

Компиляторы C при должной оптимизации создают невероятно быстрый ассемблерный код. Правда, кроме того, чтобы выставлять нужные флажки оптимизации для компиляции, нужно и самому писать высокопроизводительный исходный код. В C мы должны аккуратно объявлять переменные, выделять и вовремя очищать память, обращаться к ресурсам и не забывать освобождать их. Если C был вашим первым языком, вы привыкнете рационально использовать память и ресурсы, привыкнете выбирать оптимальные структуры данных. Эта привычка сохранится, когда вы начнёте писать и на других языках.

C мотивирует к написанию чистого кода


В отличие от современных языков программирования, для реализации тех же задач на C вам придётся писать в разы больше кода. Это связано с тем, что на C многое приходится реализовывать на более низком уровне, а не использовать встроенные обёртки и абстракции из стандартных библиотек, скрывающих подробности реализации. Когда количество строк в коде увеличивается, сложность кода также растёт. Чтобы компенсировать этот эффект и поддерживать порядок в проекте, нужно стараться писать чистый и понятный код.

Написание чистого кода — это навык, который особенно востребован при работе в крупных коммерческих проектах. Если вы научитесь писать чистый код на С, то вам будет легче сделать это на другом, более простом языке.

Пока не убедил?


С активным развитием C++  язык C многие перестали воспринимать как самостоятельный. Он как будто превратился в подмножество языка C++. Понятно, что фактически это не так. C++ — действительно современный язык программирования с полнофункциональным набором стандартных библиотек. На мой взгляд, C++ не должен быть первым языком, который стоит изучить. Правда, тут есть одна оговорка: если вы в дальнейшем хотите специализироваться именно на нём, то вперёд. В этом случае эти два языка можно учить параллельно, но они в какой-то момент «пересекутся» — и переход от С к С++ будет органичным и почти мгновенным. 

Практически все современные языки программирования конкурируют друг с другом, вводя новый синтаксис, семантику и расширяя стандартные библиотеки и фреймворки. Как говорится, всё для людей. Это и подкупает. Но если будущие разработчики с нуля начнут изучать эти языки, они упустят ценные возможности, которые даёт C. В какой-то момент они просто не смогут сделать новый шаг в своём развитии, не зная, как работает код на более низком уровне, не зная даже, как внутри реализованы их любимые фреймворки и библиотеки.

Поэтому выберите C в качестве первого языка программирования. Его изучение займёт больше времени, но в дальнейшем поможет вам очень быстро стать экспертом в более современных языках.



Облачные серверы от Маклауд отлично подходят для разработки на С и других языках программирования.

Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!




Комментарии (60):

  1. unsignedchar
    /#22993826 / +2

    На любом языке можно писать как на С. ;)

    • Sultansoy
      /#22993940 / -1

      Возьму за пример джаву. Там конечно есть unsafe, например, для работы с памятью, но нигде еще не встречал, чтобы про него рассказывали на курсах, редко в какой книге о нем пишут.
      К тому же, не уверен, что стандартная hotspot jvm дает прям настолько полный контакт с железом, без надстроек и jni, конечно же

      • pin2t
        /#22996266

        На Java как раз таки пишут очень много кода "в стиле С". И дело тут не в unsafe.
        Любое использование null — это код на С
        Любое использование статических функций — это код на С
        Любые классы с именами заканчивающимися на -er или -or — это на самом деле не классы а функции на С
        И такого вот очень много в Java-мире, и пишут это все люди, которые ранее писали на С, но после перехода на Java не стали изучать как писать на Java а изучили только синтаксис.

        • nirom
          /#22997274

          любые классы с именами заканчивающимися на -er или -or

          Это что за классы такие особенные?

    • staticmain
      /#22994208

      Вот так?
      /*! \brief Отвечает на вопрос, является ли интерфейс физическим
       * \param[in] name Имя
       * \return boolean, истина, если интерфейс физический */
      function dd24_interface_isphysical(name) {
          return !name.includes(":");
      }
      
      /*! \brief Возвращает имя выбранного интерфейса
       * \param[in] root Объект: DOM-интерфейс
       * \return string, имя интерфейса */
      function dd24_interface_name(interface) {
          return dd24_element_find(interface, "h6.json-value-name").textContent;
      }
      
      /*! \brief Возвращает тип выбранного JSON-элемента
       * \param[in] elem Выбранный элемент для подстановки JSON-данных
       * \return string, тип JSON-поля */
      function dd24_element_type(elem) {
          var sclass = elem.className;
          var cpos = sclass.search("json-type-");
          return sclass.substring(cpos).split(' ')[0].split('-')[2];
      }
      
      /*! \brief Устанавливает префиксы полям формы выбранного интерфейса
       * \param[in] type Тип DOM-элемента (input, select, div, etc...)
       * \param[in] interface Корневой объект DOM-интерфейс
       * \param[in] index Порядковый номер интерфейса
       * \param[in] name Имя поля JSON-объекта */
      function dd24_interface_prefix(type, interface, index, name) {
          var ename = dd24_element_find(interface, type + ".json-value-" + name);
          var jtype = dd24_element_type(ename);
          var avalue = "interfaces[" + index + "](" + jtype + ")." + name;
          ename.setAttribute("name", avalue);
      }
      
      /*! \brief Показывает нужную кнопку (удалить\добавить) исходя из типа интерфейса */
      function dd24_interface_controls() {
          var interfaces = dd24_interfaces_list();
          for (var i = 0; i < interfaces.length; i++) {
              var name = dd24_interface_name(interfaces[i]);
              var badd = dd24_element_find(interfaces[i], ".interface-add");
              var brem = dd24_element_find(interfaces[i], ".interface-rem");
      
              if (dd24_interface_isphysical(name)) {
                  dd24_element_show(badd);
                  dd24_element_hide(brem);
              } else {
                  dd24_element_hide(badd);
                  dd24_element_show(brem);
              }
          }
      }

  2. Sultansoy
    /#22993850

    Не смог перейти к оригиналу, возможно глюк мобильной версии. Предоставьте, пожалуйста, ссылку.

  3. ffriend
    /#22993884 / +8

    C заставляет глубоко прорабатывать решение проблемы

    А в чём глубина приведённого решения на C? Больше кода вижу, отсутствие фукнций высшего порядка (которые как раз полезно изучать) вижу, решение не совсем той задачи, что на других языках, вижу. А вот глубины проработки — не вижу. Да и сама задача на особую глубину не претендует вроде как.


    Язык С заставляет делать многое руками и писать высокооптимизированный код. [...] Как по мне, такое должен попробовать каждый профессиональный разработчик. Ну, как минимум, бэкендер.

    Оптимизировать нужно то, что рабтоает медленно. В бекенде чаще всего медленно работает база данных (при этом нужно уметь оптимизировать запросы), ввод-вывод (часто помогает асинхронщина), HTTP запросы (можно оптимизировать пулы соединений, например). Опять же, причём тут C?


    Если вы научитесь писать чистый код на С, то вам будет легче сделать это на другом, более простом языке.

    Или наоборот.

    • nick758
      /#22993950 / +2

      Если вы научитесь писать чистый код на С, то вам будет легче сделать это на другом, более простом языке.

      Или наоборот.

      Та статья как раз про тех, кто не научился писать чистый код.

      • ffriend
        /#22994054

        Из второго абзаца той статьи:


        Есть основания полагать, что ранний опыт использования MCS51/AVR/PIC оказывается настолько психически травмирующим, что многие страдальцы затем продолжают считать байты на протяжении всей карьеры, даже когда объективных причин для этого не осталось.

        Понятно, что с чего бы человек не начал изучение программирования, у него есть шанс в будущем научиться делать что-то другое хорошо. Но автор этой ^ статьи достаточно категорично заявляет о необходимости изучения C, а автор статьи по ссылке наоборот предупреждает о возможной опасности низкоуровневого программирования в начале карьеры.




        Вообще непонятно, на каком основании автор этой делает заявления о чистоте кода. Чистый код на C значительно отличается от чистого кода на Java, Python или JavaScript. Более того, понятие о чистоте кода сильно варьируется в зависимости от области применения — математический код будет выглядеть ужасно для веб-программиста и наоборот. Да даже в двух соседних проектах одной команды из одной области структура и стиль кода может быть совершенно разный (пример — Scala как улучшенная Java и Scala как Haskell на JVM).


        Тем более непонятно заявление о глубине знаний (или, о гспд, глубине проработки проблемы). У меня есть пара знакомых без технического образования (как раз из тех, кто хочет "войти в IT"), которые сейчас изучают Java и Python. Первый недавно потратил вечер на изучение дополнительного кода для представления негативных целых чисел, другой незадолго до этого спрашивал про линии кеша процессора. Они знают про инструкции процессора, стратегии работы с памятью, относительную скорость операций и т.д. Но при этом они в жизни не видели C, потому что для достижения цели он им не нужен.

  4. mapron
    /#22993908

    Поправьте ссылку на оригинал (у вас битая) —
    betterprogramming.pub/why-every-developer-should-start-programming-with-c-39b3a87392bf
    (не пишу в личку т.к. в корпортивных блогах исправления делают по 2-3 недели — если делают вообще. а читателям переходить к ориниалу нужно уже сейчас).

    • owlofmacloud
      /#22995398

      спасибо!
      я делаю исправления сразу, не стесняйтесь писать мне в личку

      • mapron
        /#22995434

        Я обычно так и делаю. Опечатки, и прочее. Тут особый случай был. Ну и про «сразу». Это вообще про все корп блоги, но я и вам отвечу. Вот вы ответили спустя 8 часов. За 8 часов у статьи 7 тысяч просмотров. Допустим даже 1% пользователей ходит по ссылке для перевода, это значит не меньше 70 юзеров получили битую ссылку.
        У статьи недельной давности — habr.com/ru/company/macloud/blog/554650 около 6 тысяч. Не надо быть супер аналитиком чтобы понять, что большая часть просмотров и комментариев к статье в первые 4-8 часов после публикации.

        Тем не менее у большинства авторов корп блогов на хабре стратегия — выложить статью и забить на фидбек на день, два, неделю или даже три. Да, некоторые отвечают на замечания в личку спустя три недели «спасибо, исправили!».

        То что это мягко говоря «уже и нахрен не надо», думаю очевидно.

  5. mapron
    /#22993930 / +4

    C заставляет глубоко прорабатывать решение проблемы

    C мотивирует к написанию чистого кода


    При этом вот код автора из его проекта:
    github.com/neutralinojs/neutralinojs/blob/master/core-windows/src/server/requestparser.cpp
    (т.к. neutralinojs указан им самим как его основная деятельность в личной информации, не думаю что это какой-то наколеночный проект которому он не уделял внимания)

    void RequestParser::processChunk(const char *buf, size_t size) {
        char c;
        size_t i = 0;
        c = buf[i];
        for(; i < size; ++i, c = buf[i]) {
            if(c == '\r') {
                half_end_of_line = true;
                goto next_iter;
            } else if(half_end_of_line && c == '\n') {
                if(end_of_line) {
                    headers_available = true;
                } else {
                    if(!first_line) {
                        headers[tmp_header_name] = tmp_header_value;
                        tmp_header_name = "";
                        tmp_header_value = "";
                    }
                    end_of_line = true;
                    first_line = false;
                    goto next_iter;
                }
            }
            if(first_line) {
                static int field = 0;
                if(beginning || end_of_line) {
                    field = 0;
                }
    
                if(c == ' ') {
                    field++;
                } else {
                    switch(field) {
                    case 0:
                        method += c;
                        break;
    
                    case 1:
                        path += c;
                        break;
    
                    case 2:
                        proto_ver += c;
                        break;
                    }
                }
            } else {
                static int field = 0;
                if(end_of_line) {
                    field = 0;
                }
    
                switch(field) {
                case 0:
                    if(c == ' ' && previous_char == ':') {
                        tmp_header_name.pop_back();
                        field++;
                    } else {
                        tmp_header_name += c;
                    }
                    break;
    
                case 1:
                    tmp_header_value += c;
                    break;
                }
            }
            half_end_of_line = false;
            end_of_line = false;
    next_iter:
            previous_char = c;
            beginning = false;
    
            /* --- begin extended code for body parser --- */
    
            if(c == '\n' && prev_char == '\r') {
                if(i+2 < size) {
                    if( buf[i+1] == '\r' && buf[i+2] == '\n' ) {
                        beginbody = true;
                    }
                }
            }
    
            if(charcount == -1) {
                auto size_it = headers.find("Content-Length");
                if(size_it != headers.end()) {
                    charcount = stoi(size_it->second);
                }
            }
            if(headers_available && method == "GET") { // GET request
                parsingDone = true;
            }
    
            if(beginbody) {
                body += buf[i];
                if(charcount == body.size()) {
                    parsingDone = true;
                }
            }
    
            prev_char = c;
    
            /* --- / end extended code for body parser --- */
        }
    
    
    }
    


    Чет лично я не вижу никакой чистоты кода
    (да, это синтаксически С++, но лично я не вижу тут именно идиоматически «плюсов», думаю вполне подходящий пример).
    К сожалению проектов на C у автора не нашел :)

    • longclaps
      /#22994418 / +1

      Давненько я не видел goto, а тут бац — и парочка. Красота!

      • AnthonyMikh
        /#22995372

        Меня ещё радует наличие парочки статиков, причём с одинаковыми именами

    • zkutch
      /#22995564

      Мне одному кажется, что приведенный в статье пример кода копирования с фильтрацией не совсем удачно содержит выпечатку масива?

  6. voidptr0
    /#22994064 / +1

    В отличие от современных языков программирования, для реализации тех же задач на C вам придётся писать в разы больше кода.

    Чем старше становишься — тем ленивее все писать заново. С наличием языкового сахара и хороших библиотек концентрируешься уже больше на сути «написуемой» программы.

  7. Tsimur_S
    /#22994256 / +1

    Нужно разделять обучение разработчика переходящего в 30+ лет из другой сферы, или вообще из ниоткуда («свитчера»), и разработчика получающего образование в юном возрасте(«студента»). Ключевым фактором их отличающим это наличие времени обусловленное наличием/отсутствием обязательств. В первом случае необходим быстрый результат, пусть даже ценой будущих перспектив, а во втором случае важнее планомерное, системное развитие, с охватом максимального количества дисциплин программирования, с учетом того что он возможно захочет поменять направление.
    Смешивать эти две категории и советовать какие-то общие вещи — несусветная глупость.
    Для «студента» не зазорно обучение начать не то что бы с С а даже с Паскаля и с ассемблера, у «свитчера» же такой роскоши нету.

  8. alexander_lamdan
    /#22994394

    Шикарная статья.

    Я вовсе начинал программировать на JavaScript, потом когда уже более менее стал сильным в веб разработке, то в сторонке стал изучать язык С, и на многие вещи я стал смотреть иначе.

  9. gvg2000
    /#22994396

    Когда в 2018 изучал Java на онлайн-курсах, в программу обучения входил курс по алгоритмам, который читался на C, соответственно перед этим курсом надо было еще дополнительно пройти небольшой курс по основам C.
    По итогу так и не понял, в чем был плюс такого варианта (предполагаю, что единственная причина — не делать отдельный курс на Java), тогда основ С из курса хватило, чтобы понять, о чем речь в курсе по алгоритмам, но в итоге и С забылся, и алгоритмы пришлось вспоминать заново, уже с решениями на Java.
    Предполагаю, что опытному разработчику при необходимости изучить дополнительный язык будет значительно проще, чем новичку сначала учить С, а потом уже учить тот язык, который он хочет использовать в работе.

  10. valeramikhaylovsky
    /#22994398 / +1

    C мотивирует к написанию чистого кода

    Это не так, проект написанный на Си, код которого можно назвать чистым — очень большая редкость.

    C заставляет глубоко прорабатывать решение проблемы

    Тут скорее борьба с самим языком, чем проработка решения.

    Если вы научитесь писать чистый код на С, то вам будет легче сделать это на другом, более простом языке.

    Если вы в принципе научитесь писать чистый код вне зависимости от языка, то будете это делать на любом языке.

    Язык С заставляет делать многое руками и писать высокооптимизированный код.

    Не многое, а всё нужно делать руками, обобщённое программирование там просто ужасно, макросы в макросах и не дай бог где-то ошибёшься, искать ошибку будешь вечность и отлаживаться не получиться. А вот высокооптимизированный код писать получится только спустя не один год практики, потому-что оптимизация начинается с архитектуры.

  11. Emelian
    /#22994400

    Почему стоит начать изучение программирования с языка C

    А почему не с ассемблера? Хотя бы на уровне erfaren.narod.ru. Кстати, «народный» дизассемблер IdaPro, Ильфака Гильфанова, позволяет переводить ассемблерный бинарный код, типа dll и exe-файлов, в Си код.

    Тем не менее, я лично предпочитаю С++, поскольку на этом языке можно проще и удобней организовать модульность. Для примера возьмем опенсорсный консольный видеопроигрыватель FFPlay.c и пробуем его внедрить в собственное оконное приложение. Я, лично, пока не перевел этот код в классы, не мог решить подобную проблему.

    С другой стороны, Си-код SQLite ни в какие классы переводить не нужно. Оно и понятно, это не оконное приложение, а консольное, поэтом просто внедряем его в свой С++ проект и все прекрасно работает без «напильника».

    Короче говоря, для общего развития, ассемблер и Си нужны, но не более. Для серьезной работы хорош С++. А для разовой подготовки (обработки) данных очень эффективен Питон и другие скриптовые языки. Однако краеугольным камнем программирования я считаю С++.

  12. gshep
    /#22994432

    потому, что не стоит

  13. cepera_ang
    /#22994526 / +2

    Нужно учить не С, а архитектуре компьютера (обычно второй или третий курс наряду с основами программирования и алгоритмами и структурами данных), особенно с учётом того, насколько абстрактная Си-машина далека от того, что реально происходит в железе. А сам С будет автоматически вытекать из рассказаного материала — это просто запись человеко-понятным языком, того что делает машина изученная только что.


    А потом оказывается, что нужны и выше абстракции и это вовсе не какой-нибудь питон, а операционные системы, сети, базы данных и распределённые системы. Всё учить надо, с такой базом потом будет легко в любой области разработки разбираться.

  14. wolfy_str
    /#22994612

    C не стоит учить… по крайней мере не олимпиадникам. Его стоило учить в начале ну максимум под конец нулевых годов. А ещё лучше в 90-е. Сейчас уже поздно. Кто знает тот знает, вундеркинды путь учат, остальные пусть мимо проходят. Я помню как изучал этот язык лет 10 назад даже больше, 12. Так вот кроме того, что это преподавалось не так что бы понятно, всё что я запомнил — это циклы, условия, какие то общие концепции не более. Вместо классов были структуры. И да намучились мы тогда, все кто учил с указателями и бинарными деревьями. Потом я узнал, что 90% ошибок в С и С++ это ошибки связанные с утечкой памяти. И забросил на долгие годы, жаль только что более современные языки, такие как Java и Python не начал учить раньше. Вообщем если хотите писать драйвера, что то низкоуровневое — велкам, но учтите, что это сделать будет не так просто сейчас.

  15. saboteur_kiev
    /#22994730

    IMHO вообще не важно с какого языка ты начал.
    Важно, чтобы ты попробовал писать на нескольких разных языках и понял их преимущества и недостатки.

  16. inferrna
    /#22994790 / +1

    Автор путает причину и следствие: чтобы хорошо и успешно писать на C нужно быть Торвальдсом или Кармаком. Это вовсе не значит, что кем-то из них можно стать, если долго-долго биться головой о стену практиковаться в C.

    • Автор путает причину и следствие: чтобы хорошо и успешно писать на C нужно быть Торвальдсом или Кармаком.

      Автор желает, чтобы в IT были только Торвальдсы и Кармаки, а всех прочих желает отсечь при помощи C.

  17. yeputons
    /#22994848

    Категорически не согласен почти со всей статьёй.


    Не надо учить Си первым языком, если есть выбор! Первый императивный язык нужен для того, чтобы научиться работать с переменными, массивами, абстракциям (функции, объекты) и прочая, прочая, прочая. Чтобы было интересно этим заниматься, лучше, если проблемы будут возникать где-то в районе "как формализовать вот этот кусок предметной области?", а не "откуда взялся очередной UB?".


    Как научились — можно либо лезть вниз (в том числе в Си), либо вверх (к какой-нибудь предметной области).


    C заставляет глубоко прорабатывать решение проблемы

    Нет, он заставляет детально расписать происходящее поближе к железу (а точнее — к виртуальной машине Си, привет от модели памяти), причём покороче, чтобы посвящённым меньше символов набирать. Это не то же самое, что "проработать решение проблемы".


    Посмотрите на некоторые куски стандартной библиотеки: заточено под UNIX (сигналы?) и null-terminated строки в однобайтовой кодировке (причём даже с кодами 0-127, привет от знакового char и падающего на отрицательных числах isdigit). Это ещё о локалях не говорим. Это активно создаёт видимость, что мы решили проблему, воспользовавшись стандартной atof (и огребя от локалей), strstr (и огребя от ненормализованного юникода), tolower (и огребя от неоднобайтовых символов).


    Никаких требований "подумать о проблеме" язык не выдвигает — что хочешь, то и пиши. Не угадал, что написать — получил поддых. В отличие от, например, Rust, где даже по строчке проитерироваться нельзя, не сказав явно, что именно надо — байты, code units, grapheme clusters. Вот это я бы назвал "заставляет глубоко прорабатывать".


    Кстати, разработчики, участвующие в соревновательных хакатонах, часто тренируют этот скил, решая нестандартные задачи как раз на C.

    Полагаю, что автор подразумевает всякие олимпиады по программированию. Тогда я считаю, что у меня есть некоторый опыт, чтобы ответственно заявить: фигня полная, на соревнованиях пишут на C++ и Java. Никто не пишет самостоятельно динамический массив или словарь, берут std::vector<> и std::map<>. А вот где встроенных абстракций не хватает — там пишем свои. Благо, таких задач хватает, и свой вектор там — скучнейшая часть.


    C позволяет прикоснуться к «низкоуровневому» программированию

    Автор сам пишет: "Как по мне, такое должен попробовать каждый профессиональный разработчик.". Согласен, должен попробовать. Но не первым языком, а дальше, когда уже не путаешься в отличиях цикла от условного оператора.


    Компиляторы C при должной оптимизации создают невероятно быстрый ассемблерный код.

    Придирка: если только вы не пишете интерпретатор.


    C мотивирует к написанию чистого кода

    Каким именно образом? Больно бьёт палкой за некоторые виды ошибок, иногда через полтора часа после запуска программы, а за некоторые не бьёт (утечки памяти)? Так себе методический приём. Нет чтобы линтеры запустить (есть для любого языка) или на этапе компиляции какие-то ошибки управления памятью ловить.


    и переход от С к С++ будет органичным и почти мгновенным.

    Это два принципиально разных языка с разными стилям написания кода и библиотек! Не будет никакого мгновенного перехода, будет сишный код в файле с расширением .cpp.

    • unsignedchar
      /#22995278

      Не надо учить Си первым языком, если есть выбор!


      Если выбор между С и Pascal — лучше C :)
      Во первых, С-подобный синтаксис встречается чаще чем паскале-подобный. Во вторых, научиться не стрелять в ногу с помощью С — это полезное умение.

      • yeputons
        /#22995378

        Если б оно ещё и стреляло стабильно… Но debug-режим, sanitizer'ы и Valgrind тут, конечно, сильно помогают.

      • sshikov
        /#22995384

        >Если выбор между С и Pascal — лучше C :)
        А как может такое получиться, что выбор только из них? В смысле, в нормальных условиях (не будем брать условную школу, где есть проблемы с преподавателями информатики, которые сами толком ни одного языка не знают)?

      • AnthonyMikh
        /#22995390

        Во вторых, научиться не стрелять в ногу с помощью С — это полезное умение.

        И чем именно полезно? Это же совершенно непереносимый навык.

        • yeputons
          /#22995530

          Умение отлаживать систему, которая умеет либо полностью работать, либо иногда необъяснимо падать с вероятность 1% в непонятном месте вполне переносимо с сишного UB на многопоточные приложения, распределённые системы и области с большими данными. Например, какие-нибудь сложные алгоритмы могут упасть после недели работы. Или если у вас десяток тысяч серверов и какая-нибудь коллизия хэшей с вероятностью 0.001% (а из-за масштабов каждый час что-нибудь да падает).


          Скорее даже не умение отлаживать, а умение такое писать: чётко следовать заданной модели, не применять "очевидные рассуждения" на самом деле выходящие за рамки модели (вроде "очевидной" sequential consistency) и, когда всё-таки случилась беда, не пугаться происходящего безумия.

        • Antervis
          /#22995828

          И чем именно полезно? Это же совершенно непереносимый навык.
          си как раз замечательно переносимый, не просто так его «переносимым ассемблером» окрестили. Просто не все умеют писать на переносимых сях переносимый код.

          • AnthonyMikh
            /#23008012

            Я не про это. Я про то, что навык "не стрелять в ногу в C" не переносится на другие области и другие ЯП.

    • Antervis
      /#22995838

      Не надо учить Си первым языком, если есть выбор! Первый императивный язык нужен для того, чтобы научиться работать с переменными, массивами, абстракциям (функции, объекты) и прочая, прочая, прочая.
      честно говоря, тоже не согласен. Выучить высокоуровневый язык начав с си довольно-таки просто. Ну, только иногда будет пригорать от динамической типизации. А вот всякие питоны/жсы ну никак не помогут выучить работу с памятью. В итоге получится разработчик, который не понимает почему написанный им код тормозит, и которому будет в разы сложнее переквалифицироваться.

      Единственный нюанс — начинать изучать программирование с работы с памятью… скучно. Поэтому на мой взгляд идеальным вариантом будет начать курсом условного питона (базовая алгоритмика), потом продолжить си (работа с памятью, алгоритмы и структуры данных), а уже потом джава/шарп (для изучения паттернов проектирования). Жаль только на нормальную проработку такого варианта у большинства вузов нет ни часов ни квалификации преподавателей.

  18. GarretThief
    /#22995366 / +2

    Инструктор рассказывает вам, что такое автомобиль, что такое дорожные знаки, где газ, где тормоз, что будет, если нажать эту кнопочку, что будет, если этот рычажок. Затем постепенно вы ездите вдвоём по городу, учитесь правильно поворачивать, а затем вам рассказывают, как вести себя при аварии и в аварийно опасном моменте.

    Вас садят в гоночный автомобиль и говорят проехать трассуя менее, чем за две минуты. За вопросы, что это за стрелочка, вас бьют по голове и отправляют учить матчасть, а в случае столкновения вы можете погибнуть.

    Когда-то давно я начинал учить Си и Питон примерно в одно время. И это мои эмоции от каждого из них (угадайте, где кто). Когда ты пытаешься понять, что такое функции, то тебе совершенно не до того, что звёздочка означает указатель, а тот факт, что передать двумерный массив[m][n] можно как можно как одномерный массив[m*n] (и это проще сделать, чем передавать его в двумерной виде), ломает тебе мозг и желание программировать. А замена простого array.length выражением типа sizeof(array_of_int) / sizeof(int) радости этому всему не добавляет. Есть кривая обучения, и если для питона она пологая, то для Си тебе нужно одновременно изучать Си, компьютер, алгоритмы, работу с памятью, дебаг и трассировку.


    Несколько лет изучая питон, я понял и внутреннее устройство компьютера, и работу компиляторов/интерпретаторов, и научился гуглить проблемы и догадываться об их причинах, но когда я только начинал, то всего этого я не знал. Заставьте выйти из вима того, кто про линукс не слышал. А вот саблайм он закроет без проблем.

  19. sshikov
    /#22995374 / +1

    Вот как так получается — большинство комментаторов считают статью в лучшем случае неверной, или категорически не согласны. А плюсы тогда откуда? Ну ведь правда же, аргументы автора оставляют желать лучшего. Нужно ли было это переводить — тоже вопрос без очевидного ответа. Есть ли среди читающих вообще хоть кто-то, кто скорее согласен с текстом? Ну или видит в нем какую-то иную пользу?

    • mapron
      /#22995440

      Ну не все ставят минус статье когда с ней не согласны. Тут например, перевод, для начала, я поставил плюс, т.к. хочу больше подобного контента на Хабре (спорного, провоцирующего дискуссии, но хотя бы технического)

      • sshikov
        /#22997392

        Ну, я не предлагаю сразу ставить минус. Я наоборот, пытаюсь выяснить, что именно в данном случае кому-то понравилось? Спорный и провоцирующий дискуссии? Да вот как-то не тянет оно на такое…

  20. Daddy_Cool
    /#22995652

    "… и переход от С к С++ будет органичным и почти мгновенным."
    Нет. Всё что можно написать на С++ можно написать на Си — он же низкоуровневый… Зачем мне классы если есть структуры? Да и без структур можно. В результате нет стимула двигаться вверх, а там много полезного/экономящего время.

  21. alexeiz
    /#22995770

    Cи мотивирует к написанию чистого кода

    Такое может сказать только человек, который сам на Си ничего не написал. Это по автору, кстати, видно. Куча пустых, ни на чём не основанных уверждений. Но вернёмся к чистому коду. В реальности код на Си — это хак на хаке и хаком погоняет. В Си простые вещи делать достаточно непросто. В следствие этого, рано или поздно программиста задалбывают сложности, и он начинает искать кратчайшие пути к достижению цели. Вот один пример из моей практики: я работал с человеком, который написал небольшой фреймвок для логирования событий на Си. События ассоциировались с неким контекстом, собиралась статистика, и прочее. На нормальном языке программирования, например, Питоне, вы бы сделали with EventContext() as ctx: .... Но это Си. В нём подобная конструкция разворачивается в выделение памяти, явное по-элементное инициализирование структуры, указатель на которую надо где-то хранить и передовать в каждую функцию, где будет совершаться логирование, а в конце память нужно будет освободить. Как вот этот человек решил, хрен со всем этим — я сделаю контекст статической переменной! По сути, он пришёл к анти-паттерну синглтона, потому что нормальная организация работы с объектами в Си — это много кропотливой работы. И вы думаете, это единственный пример. Такого полным-полно практически в любом коде на Си.

  22. Antervis
    /#22995822

    В этом случае эти два языка можно учить параллельно, но они в какой-то момент «пересекутся» — и переход от С к С++ будет органичным и почти мгновенным.
    нет, нет, нет, и нет! Худшее, что можно сделать с будущим разработчиком — пытаться учить его одновременно с и с++. В итоге он не может ни писать на плюсах (потому что «си с классами» очень не приветствуются в адекватных кодобазах), ни на си (потому что уже привык опираться на некоторые плюсовые фичи).

  23. atomic1989
    /#22995970

    Совершенно не согласен с автором. Обучать новичка сразу с сложного не получится. Новичка необходимо вводить в мир программирования с простого. По мере усвоения материала, обретения соответствующих навыков, углублять знания. На каждом этапе обучения очень важно видеть результат и важность своих знаний. Поэтому начинать путь с высокоуровневых абстракций, библиотек, фреймворков даст толчок, мотивацию к развитию с самого начала. Да и бизнесу нужны специалисты, которые дадут результат здесь и сейчас. Большинство задач решаются набором простых и готовых абстракций. Для примера: как часто приходится применять решения олимпиадных задач в бизнесе, если и часто, то какой процент разработчиков это затрагивает?

    • Antervis
      /#22996080

      Для примера: как часто приходится применять решения олимпиадных задач в бизнесе, если и часто, то какой процент разработчиков это затрагивает?
      будет обидно, если нетривиальная задачка таки возникнет, и никто в вашей команде не сможет её решить?

      • JustDont
        /#22999722

        А если ваш стартапчик с рокстарами разорится — обидно не будет, я так понимаю? Будет очередное "мы пилили очередной мегапродукт, делающий всем хорошо, вот только несправедливый жестокий мир его подкосил"?

        • Antervis
          /#22999856

          во-первых, вы смешиваете в кучу «студентов-олимпиадников», «рокстаров» и специалистов с навыками низкоуровневого программирования. Во-вторых, забываете, что владение молотком не обязывает забивать им шурупы. В третьих, если «начинать путь с высокоуровневых абстракций, библиотек, фреймворков», всегда есть шанс что навыки деактуализируются веяниями моды или банальной сменой места работы. А вот база никуда не денется.

          • JustDont
            /#22999978 / +1

            Да нет, это вы смешиваете. У вас выше — нерешаемая "нетривиальная задачка", а тут вдруг попёрла куча других интересных людей совсем не по этой части. "Нетривиальные задачки" в бизнесе бывают нетривиальны самыми разными путями, и совсем даже не все из них решатся, если вдруг у кого-то есть "база" и он может чё-то там накодить на С. Люди, которые (обычно) успешно решают нетривиальные задачки бизнеса, связанные с кодом — это именно "звездные программисты", а не люди, у которых могучая база знаний основ С.


            А вот база никуда не денется.

            … и точно так же может быть почти совсем невостребованной после "банальной смены места работы". Ну впрочем можно зато проходить собеседования в конторы, которые упарываются по алгоритмам, это да.

            • Antervis
              /#22999998 / -1

              под «нетривиальными» я имел в виду задачи, тривиальные решения которых не проходят по требованиям, например CPU/RAM. И уже в зависимости от требований вам может понадобиться как разработчик с пониманием основ, так и рокстар. Я конечно понимаю, что в том же вебе как правило по барабану — железо ведь на стороне пользователя, но даже там поисковики снижают рейтинг тормозных сайтов, а пользователи их не уважают.

              … и точно так же может быть почти совсем невостребованной после «банальной смены места работы»
              вы наверно сможете привести пример, когда при смене работы базовые знания теряют актуальность?

              • JustDont
                /#23000110

                Ну понятненько, "если будет такая задача, которую будет сложно впихнуть в железо, то вот тут-то всё и пригодится!". Действительно, если проблема в гвоздях, а у вас чисто случайно в руках молоток — то всё складывается просто отлично. Кто бы сомневался.


                вы наверно сможете привести пример, когда при смене работы базовые знания теряют актуальность?

                Вы понимаете, в чем разница между "не востребовано" и "потеряло актуальность"?

                • Antervis
                  /#23000136 / -1

                  легко наверно пытаться обесценивать навыки, которых у вас нет...

                  Ну понятненько, «если будет такая задача, которую будет сложно впихнуть в железо, то вот тут-то всё и пригодится!»
                  самый простой пример — бекенд на AWS или подобных. Чем больше CPU/RAM/диска жрет ваш сервис, тем больше вы платите за это железо. Пока у вас единицы мелких контейнеров, проще закидать проблему железом. А когда сотни/тысячи, оптимизация внезапно становится чертовски выгодной.
                  Вы понимаете, в чем разница между «не востребовано» и «потеряло актуальность»?
                  это не имеет значения если у вас нет примера.

    • unsignedchar
      /#22996970

      Новичка необходимо вводить в мир программирования с простого.


      Переменные, циклы, условия, да? Совсем как в С ;) На простых уровнях С очень простой язык.

      начинать путь с высокоуровневых абстракций, библиотек, фреймворков


      Лучше бы с алгоритмов. Библиотеки с фреймворками — в одних языках одни, в других — другие, за время изучения что-то устареет, что-то выпустят новое…

      • yeputons
        /#22997230

        Переменные, циклы, условия, да? Совсем как в С ;)

        Следующий обязательный шаг и популярная абстракция — массивы и строки — уже убьёт всех начинающих программистов на Си из-за а) неопределённого поведения при выходе за границу; б) необходимости руками возиться с памятью.

      • Лучше бы с алгоритмов. Библиотеки с фреймворками — в одних языках одни, в других — другие, за время изучения что-то устареет, что-то выпустят новое…
        Верно подмечено про устаревание!

      • JustDont
        /#22999748

        Переменные, циклы, условия, да? Совсем как в С ;)

        Про типы данных вы случайно забыли, да? Что вы там накодите простого и интересного, не приближаясь к строкам и спискам? Числа Фибоначчи посчитаете?

        • unsignedchar
          /#23000780

          Что вы там накодите простого и интересного, не приближаясь к строкам и спискам?


          Всякие матрицы-шматрицы, уравнения, физика, численные методы разные, преобразования Фурье… Есть очень много задач, не требующих операций со строками.

          Числа Фибоначчи посчитаете?


          И их тоже ;)
          ЗЫ: и FizzBuzz :)

  24. Revertis
    /#22997534

    Надо начинать изучать программирование с Бейсика! :)

    А по статье — так ведь Rust все эти пункты выполняет намного лучше!