Ответы пользователя по тегу C
  • Как написать модуль для Python 3 на C?

    @res2001
    Developer, ex-admin
    У Бизли в "Подробном справочнике" есть хорошая глава введения в этот процесс (это лучшее, что я видел в печатной литературе на русском). Но там, конечно, только для старта информация, все остальное берите из докуменатции.
    Ответ написан
  • Как копировать один символ строки в другую переменную?

    @res2001
    Developer, ex-admin
    Для кода нет никакой разницы английский символ в строке, русский или китайский.
    Но когда вы читаете текстовый файл глазами, чтобы символы правильно отображались вы должны выбрать правильную кодировку. Си никак не меняет кодировку символов, то что есть в строке то и пишется в файл.

    Вообще у вас как-то усложнена запись в файл. Зачем вы копируете этот единственный символ, да еще и выделяете для этих 2ух байт динамическую память (которую надо еще и освободить после использования).
    Си строка - это просто массив байт. С ним можно обращаться как с массивом (symb[i]). Для записи в файл одного символа используйте fputc(), для записи нескольких байт используйте fwrite().
    Ответ написан
  • С чего начять новичку в СИ?

    @res2001
    Developer, ex-admin
    1.Си достаточно не большой и простой язык программирования. Возьмите любой учебник для начинающих. Изучите язык, порешайте задачи оттуда.
    Поймите все про Си строки. Все достаточно просто, но почему то у многих с этим проблемы в начале.
    Поймите тонкие моменты языка (это важно для системного программиста и для "железячника", да и просто для хорошего программиста): указатели, арифметика указателей, динамическое выделение памяти.

    2. Потом надо погрузиться в программирование для той ОС, которую планируете использовать. Обычно это линукс. Учитывая ваши интересы (системное программирование, железо), то тут можно порекомендовать следующие книги:
    - https://www.ozon.ru/product/linux-api-ischerpyvayu... - это для user space. Эта книга больше справочник по Linux API. Если у вас хорошо с английским то эту книгу может заменить встроенная справка линукс (man).
    - https://www.ozon.ru/product/yadro-linux-opisanie-p... - это kernel space (драйвера)

    3. Параллельно с первыми двумя пунктами есть смысл читать что-нибудь по алгоритмам. Например Кормена: https://www.ozon.ru/product/algoritmy-postroenie-i...

    4. После того как будете уверены в своих знаниях Си и Linux, можете выбирать платформу с которой вы хотите работать (железку) и начинать реализовывать свои задачи. По ходу дела возникнет куча вопросов. Большая часть из них может быть решена с помощью чтения TRM (Technical Reference Manual, предоставляется производителем железа/процессора). TRMы обычно оочень большие просто так их читать без конкретной цели смысла нет.
    Ответ написан
  • Почему некорректно находит произведение чисел?

    @res2001
    Developer, ex-admin
    Почему вы в функции с переменным количеством аргументов не используете стандартный механизм для работы с аргументами в подобных функциях (#include <cstdarg>)?

    Поставьте отладочный вывод в цикл, где выведите значение count, а заодно и *ptr и comp. То же самое можно быстро посмотреть в отладчике затратив минуты 3 на все. Выводите значение floatов с большим количество знаков после запятой (10-15).
    Вы будете удивлены тому, что во float 3.0 это не обязательно равно 3, ну и т.д. То же самое относится к любым типам с плавающей точкой.
    Передавайте первым аргументом uint32_t, вторым и следующим float. Тогда все будет нормально. Код, конечно, придется немного переделать.
    Ответ написан
  • Как реализовать обмен сообщениями между программами, где текст сообщения берется из txt-документа?

    @res2001
    Developer, ex-admin
    Если одна из программ потомок другой - используйте неименованные каналы.
    Если обе программы работают не зависимо друг от друга (не предок и потомок) используйте именованные каналы или unix socket (если платформа никсы).
    Если программы должны работать на разных компах (могут работать и на одном при этом) используйте сокеты.

    Вообще самым быстрым средством межпроцессного взаимодействия является shared memory. Но у нее недостаток в том, что должен быть дополнительный механизм с помощью которого второму процессу можно будет сообщить, что данные обновлены (либо второй процесс должен в цикле постоянно мониторить состояние памяти, а это часто не приемлемо). shared memory есть смысл использовать, когда надо передать большой объем информации и в паре с ним использовать каналы или сигналы (unix).
    Ответ написан
  • Как отсортировать повторяющиеся строки на языке СИ?

    @res2001
    Developer, ex-admin
    Проходите по списку и выводе все строки где дата равна указанной. Все.
    Зачем тут сортировка?

    В плане сортировки и учитывая, что тема Базы данных, то если смотреть на любую реляционную СУБД, то там сортировка данных достигается за счет создания индексов. Индексы это отдельные (от данных) сущности, т.е. физически порядок данных не меняется, но существует отдельный отсортированный список "указателей на данные".
    Справедливости ради стоит сказать, что в СУБД существуют и "кластерные индексы" - это такой индекс, который определяет физическую сортировку данных, т.е. данные физически располагаются в хранилище в порядке указанном в кластерном индексе. Но такой индекс может быть только один для одного набора данных (таблицы), а обычных индексов может быть сколько угодно.

    Исходя из вышеописанного вы можете создать индекс по дате поступления. Индекс может представлять собой отсортированный массив указателей на данные, двусвязный список указателей или бинарное дерево указателей или что-то еще. При этом сам список данных останется прежним.
    Самый простой вариант массив указателей. Сортировать его можно с помощью стандартного qsort(), поиск производить с помощью бинарного поиска bsearch(). При добавлении или удалении элемента в данные, придется либо полностью перестраивать индекс, либо вручную добавлять/удалять элемент из индекса. В любом случае это будет достаточно затратной операцией.
    В двусвязном списке и бинарном дереве со вставкой и удалением все проще и гораздо быстрее. В этом случае проще всего генерировать индекс сразу по мере добавления данных, тогда индекс будет строится вместе со списком данных. Но это соответственно скажется на скорости этих операций. Бинарное дерево лучше реализовывать сразу сбалансированное. Работа с подобными структурами сильно усложнит ваш проект и возможно не совсем вписывается в рамки курсового проекта. Это уже вам решать.
    Ответ написан
  • Где здесь путаница?

    @res2001
    Developer, ex-admin
    Зачем это
    r[j] = '\0';
    в цикле? Вынесите из цикла.
    Путаницу в куче я вижу только в том смысле, что памяти выделяется больше, чем нужно. Можно этот момент подрихтовать.
    Сам цикл я бы реализовал немного по другому - так чтобы в одной итерации цикла добавлялись сразу 2 символа из строки и один symbol. В этом случае нужно будет еще обработать оставшийся хвост, если количество символов не четное.

    Добавлено: Проглядел отсутствие освобождения памяти. Оно необходимо, конечно.
    Ответ написан
  • С: Объясните, что не так?

    @res2001
    Developer, ex-admin
    Возможно он хочет увидеть что-то типа этого:
    puts(sort_string(word));
    Но это блаж какая-то.
    Кроме того в sort_string возможна ошибка выделения памяти (которую вы не обрабатываете) и передавать так, без обработки ошибок ... плохо.
    Ответ написан
  • Как правильно получить ввод строки от пользователя в Cи?

    @res2001
    Developer, ex-admin
    В scanf_s при задании ввода строки, нужно указывать, кроме адреса буфера еще и реальный размер буфера в параметрах. Смотрите пример использования тут: https://en.cppreference.com/w/c/io/fscanf
    Обычный scanf считается не безопасным, и не без оснований, конечно. Поэтому его использование не рекомендуется, о чем в сообщении и пишут. Но это можно обойти, как именно, написано в том же сообщении. Правда задание _CRT_SECURE_NO_WARNINGS влияет не только на использование scanf, но и на пачку других функций.
    Определять #define _CRT_SECURE_NO_WARNINGS нужно до включения любых заголовков стандартной библиотеки. Что бы это определение на них подействовало. Проще всего это сделать в параметрах командной строки компилятора с помощью опции -D_CRT_SECURE_NO_WARNINGS
    Ответ написан
  • Указатель на функцию или атрибут weak?

    @res2001
    Developer, ex-admin
    Указатель на функцию:
    плюсы: явный механизм (требует явных действий пользователя - вызова функции регистрации нового callback), понятней и проще (реализован стандартными средствами языка), универсальней (будет работать на всех платформах и компиляторах), для подключения пользовательского функционала не требуется пересборка библиотеки.
    минусы: динамическое связывание - если функция будет активно вызываться, то это может привести к дополнительным накладным расходам.

    weak:
    плюсы: статическое связывание (отсутствие накладных расходов на вызов)
    минусы: требуется не стандартная поддержка компилятора (может не работать при использовании другого компилятора, например у компилятора микрософт другой синтаксис для этого), связывание происходит не явно (компилятор сам выбирает какую функцию использовать из подходящих вариантов), для подключения пользовательского функционала требуется пересборка библиотеки

    Условная компиляция:
    плюсы: статическое связывание (отсутствие накладных расходов на вызов), универсальность, явный механизм
    минусы: возможно немного сложней в реализации, чем weak, для подключения пользовательского функционала требуется пересборка библиотеки

    Выводы:
    Если требуется статическое связывание, то выбор - условная компиляция. При грамотной реализации тут можно минимизировать действия пользователя по подключению своей реализации функции в сборку библиотеки. Если библиотеку не планируется выпускать в открытый доступ и не смущает не стандартность - можно использовать weak из-за простоты реализации.
    В остальных случаях - указатель на функцию.
    Ответ написан
  • Как организовать работу двух динамических массивов используя malloc?

    @res2001
    Developer, ex-admin
    Добавлю ко всему выше написанному: подобное использование двумерных массивов убивает производительность, т.к. вместо одного чтения памяти происходит 2, а кроме того весь массив разбит на много маленьких кусков, которые лежат в разных местах памяти - кэш процессора используется не эффективно. В нагруженных приложениях это будет сказываться.
    Правильнее использовать двумерный массив выделенный одним куском и пересчитывать индексы в ручную:
    int *a = malloc(sizeof(int) * n * m);
    for(int i=0; i < n; ++i)
      for(int j=0; j < m; ++j)
        *(a + i * m + j) = 0;

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

    Что бы избежать пересчета индексов (например когда массивы трехмерные или больше) можно использовать промежуточный "указатель на массив переменной длины" (правда это будет работать только на gcc/clang и в С++ работать не будет, только С99+). Подробно расписывать не буду, т.к. тут важно понимание. Если будет интересно в интернете информацию по VLA найдете.
    Ответ написан
  • Как ввести целое число и определить, верно ли, что все его цифры четные (язык Си)?

    @res2001
    Developer, ex-admin
    В цикле надо устанавливать флаг четности/нечетности, а сам вывод делать после цикла в зависимости от установленного флага. При этом можно проверять только на не четность. Например значение флага по умолчанию 1 (т.е. все числа четные), если хоть одно число не четное, то присваиваем флагу 0 и завершаем цикл (break), после цикла анализируем флаг и выводим YES или NO в зависимости от его значения.
    Ответ написан
  • Как добавить файл конфигурации к библиотеке?

    @res2001
    Developer, ex-admin
    Обычно подобные вещи делаются не так.
    Для этого в cmake предусмотрена функция configure_file
    Смысл в том, что вы создаете шаблонный файл, содержащий ссылки на переменные cmake. configure_file обрабатывает этот шаблон, заменяет все ссылки значениями переменных и создает из них новый файл. Этот новый файл вы и используете в проекте. Т.е. реального файла (в вашем случае conf.h) в проекте не существует, он появляется только во время компиляции.
    Изменять значения переменных cmake пользователь может через параметры командной строки cmake с помощью ключа -D, например: cmake ... -DMY_VAL="New value".
    Подобную переменную внутри cmakelists.txt обычно декларируют через option, там же можно указать и описание переменной и значение по умолчанию.
    Примеры использования можете найти в любом более менее крупном проекте cmake на github.
    Ответ написан
  • Неправильный вывод?

    @res2001
    Developer, ex-admin
    Вы не правильно инициализируете указатель ptr: int *ptr = s[0];
    Обращение s[0] просто возвращает первый элемент массива (в вашем случае 1). Это не указатель.
    Правильная запись была бы:
    int *ptr = &s[0];
    или
    int *ptr = s;


    Если бы вы поставили максимальный уровень сообщений компилятора, то в этом месте он бы вам ругнулся.
    В целом рекомендую в своих проектах всегда выставлять максимальный уровень сообщений и исправлять ошибки, на которые указывает компилятор. В большинстве случаев компилятор выдает абсолютно правильные рекомендации. Конечно бывают и исключения.
    Ответ написан
  • Безопасно использовать типы atomic из Си в динамических структурах?

    @res2001
    Developer, ex-admin
    Атомарные переменные - это такие же переменные как и остальные. Инициализировать их вы можете сколько угодно раз. Это относится только к встроенным типам. Атомарные классы - это сказка.
    Но на них накладываются некоторые ограничения:
    1. выравнивание переменной - переменная должна находится по адресу обычно кратному размеру переменной. Если не будет правильного выравнивания, то intelовские процы могут сделать 2 операции чтения, что уже не будет атомарной операцией. Другие процы могут сгенерировать какое-нибудь исключение.
    2. атомарная переменная всегда volatile - т.е. компилятор не может ее кэшировать в регистре, всегда идет обращение к памяти.
    Не все атомарные переменные в std действительно атомарны. Это проверяется с помощью atomic_is_lock_free(). Атомарность зависит от платформы. Например на x86 int64 - не атомарна из-за ограничений процессора. Тогда как на 32 битных АРМах она вполне атомарна.
    При обычном чтении/записи атомарных переменных (с упорядочиванием памяти memory_order_seq_cst) происходит синхронизация кэшей ядер - из-за чего атомарные операции "дороже" не атомарных. Но этот процесс на разных архитектурах стоит по разному. Для синхронизации кэшей есть отдельные ассемблерные инструкции.

    В целом все undefined behavior для атомарных переменных в std связаны с:
    1. возможностью объявить атомарным любой класс
    2. не для всех встроенных типов на конкретной платформе гарантируется реальная атомарность (atomic_is_lock_free).
    3. если вы не будете соблюдать ограничения, то же ничего гарантировать нельзя.
    Так что особо пугаться undefined behavior не стоит. Просто соблюдайте ограничения, не используйте атомарные классы и удостоверьтесь, что встроенные типы на вашей платформе действительно атомарны.
    Ответ написан
  • Указатель или Индекс элемента?

    @res2001
    Developer, ex-admin
    имею ввиду, зачем делают так *p+1 для доступа к следующиму элементу, а не p[1]?

    Вообще то ничего общего между приведенными операциями нет (смотрите приоритет операций):
    *p+1 == (*p) + 1
    p[1] == *(p+1)


    Но вопрос в целом понятен, не взирая на ошибку в примере.
    Надо смотреть на контекст. Часто бывает, что код не ограничивается одноразовым применением p[1], а например есть целая серия обращений к p[1], в этом случае будет экономия на операциях, если вы сначала вычислите адрес p[1], а в дальнейшем будете использовать простое разыменование этого адреса. Будет ли реально выигрыш во времени исполнения зависит от компилятора, в целом думаю, современные компиляторы в состоянии сами сделать подобную оптимизацию.
    Ответ написан
  • Как в языке СИ посчитать количество согласных букв, окруженных цифрами?

    @res2001
    Developer, ex-admin
    И на деле так же как на словах.
    как-то с помощью цикла каждому символу присвоить какое-то значение

    Уже все присвоено давно, ничего не нужно придумывать. Называется ASCII Table, погуглите.

    Но на самом деле в стандартной библиотеке Си есть функции, который проверяют символ и возвращают буква эта, цифра или что-то другое. Начать можете от сюда: https://en.cppreference.com/w/c/string/byte/isalpha
    Внизу есть табличка со сравнение всех подобных функций.
    Вам останется только правильно выставить локализацию перед использованием этих функций, т.к. с неправильной локалью могут быть проблемы с опознаванием русских букв.
    Ответ написан
  • Как перевернуть массив в си?

    @res2001
    Developer, ex-admin
    В цикле до половины массива, в цикле 2 счетчика: счетчик с начала массива увеличивающийся и счетчик с конца уменьшающийся. На каждой итерации меняешь местами элементы массива индексируемые счетчиками.
    В случае не четного количества элементов, центральный элемент остается на месте.
    Ответ написан
  • Как сортировать массив с рандомными значениями?

    @res2001
    Developer, ex-admin
    До сортировки дело не доходит.
    1. тут:
    int i, a, n, j, b, d;
    int x[i];

    Как вы думаете, какой размерности будет массив х после этого объявления?
    2. в цикле генерации рандомного массива:
    for(d=0; d < n; d++)
      x[i] = rand();

    Какому элементу массива вы присваиваете значение?
    3. printf("%d", x[i]);
    Какой элемент выводится? Сколько элементом выведется?

    А это вообще праздник какой-то:
    system("chcp 1251");
      system("cls");
      system("title Pr101");
      system("Color F0");

    Но ошибки тут нет :)
    Ответ написан
  • Какие есть альтернативы getch() в си?

    @res2001
    Developer, ex-admin
    Под какую ОС разрабатываете?
    Если винда, то там не надо никакой библиотеки - функция входит в стандартную библиотеку.
    Вам нужно лишь в код подключить заголовок conio.h и использовать не getch(), а _getch(). getch() объявлена микрософтом устаревшей.
    https://docs.microsoft.com/ru-ru/cpp/c-runtime-lib...
    https://docs.microsoft.com/ru-ru/cpp/c-runtime-lib...
    getch() использует вызов WinAPI для низкоуровнего чтения из консоли: ReadConsole(). Вы можете его использовать в своей программе то же вместо getch().
    https://docs.microsoft.com/ru-ru/windows/console/r...
    Если вы программируете на С/С++ под винду полюбите документацию MSDN - это очень хороший ресурс, к тому же от производителя.
    Ответ написан