Ответы пользователя по тегу C
  • С: Объясните, что не так?

    @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
    Ответ написан
    1 комментарий
  • Указатель на функцию или атрибут 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 найдете.
    Ответ написан
    1 комментарий
  • Как ввести целое число и определить, верно ли, что все его цифры четные (язык Си)?

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

    @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 не стоит. Просто соблюдайте ограничения, не используйте атомарные классы и удостоверьтесь, что встроенные типы на вашей платформе действительно атомарны.
    Ответ написан
    1 комментарий
  • Указатель или Индекс элемента?

    @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 - это очень хороший ресурс, к тому же от производителя.
    Ответ написан
    2 комментария
  • Почему первый цикл запускается повторно?

    @res2001
    Developer, ex-admin
    Если удалить эту часть, то программа работает исправно, за исключением повторного исполнения первого цикла do while.

    Вы же сами повторно вызываете start_int() в предложении while, отсюда и повторный вызов.
    Вам нужно передать в end_int() сохраненный результат выполнения start_int. И в while сравнивать с ним, не вызывая start_int повторно.
    Ответ написан
    3 комментария
  • Как обработать код С/С++ внутри Python(с живым примером в виде кода)?

    @res2001
    Developer, ex-admin
    Введение в тему применения Python C API не плохо описано у Бизли в его подробном справочнике. Остальное придется осваивать из документации по ссылке выше.
    Но это не единственный вариант использования Си библиотек в питоне. Тема достаточно обширна.
    Ответ написан
    Комментировать
  • Как отсортировать массив, чтобы он работал (язык СИ)?

    @res2001
    Developer, ex-admin
    Было бы лучше, если бы вы указали в вопросе, какие конкретно проблемы, что выводит и т.п.
    На вскидку: в этой строке выход за границы массива дважды:
    if (a[i] == a[i-1] && (i+1== N || a[i+1] != a[i]))
    Первый раз при i=0 в a[i-1], второй раз при i = N - 1: a[i+1].
    Видимо вам нужно первый и последний элемент массива обрабатывать отдельно (не в общем цикле).
    Да и в целом, как мне кажется, вы не правильно решаете задачу.
    Ответ написан
  • Как задать матрицу X[5][7] на С?

    @res2001
    Developer, ex-admin
    int X[5][7];
    Ответ написан
    Комментировать
  • Почему в массив размером N можно положить больше чем N элементов?

    @res2001
    Developer, ex-admin
    В malloc при передаче в качестве аргумента нуля возвращаемое значение не определено (implementation-defined). Так что фиг знает что там вам вернул маллок. Но раз программа не падает, то, возможно, он вернул какой-то указатель на стек, а в стеке у вас есть ~8МБ - развлекайтесь.
    В общем не нужно так делать. На другом компиляторе (или на том же, но другой версии) поведение может быть совсем другим.
    Ответ написан
    Комментировать
  • Как кидать исключения при работе с try catch?

    @res2001
    Developer, ex-admin
    Сишные функции не вызывают исключений. В Си их просто нет. Поэтому помещать их в try/catch нет смысла - проверяйте возвращаемые значения по старинке. Если хотите, можете написать обертки для стандартных функций, генерирующие исключения в случае ошибки. А еще лучше использовать std::fstream - вы же пишите на С++, так и пользуйтесь плюсовой стандартной библиотекой, а не Сишной.
    void foo() {
        int *smth;
        try {
            smth = new int[100];
            if (5 < 4) {
                std::runtime_error("Беда");
            }
        } catch (std::runtime_error &e) {
            e.what();
        }
        delete[] smth;
    }

    new генерирует std::bad_alloc, если произойдет исключение - память не выделилась и ничего удалять не надо.
    Ответ написан
    2 комментария
  • Как удалить элемент массива?

    @res2001
    Developer, ex-admin
    Прежде всего я не понимаю, как выбить этот элемент из массива

    В вопросе уже есть ответ на вашу непонятку:
    для чего выполнить сдвиг влево.

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