Ответы пользователя по тегу C
  • Почему инициализация целочисленного указателя 0 или NULL не вызывает предупреждений, хотя 0 - это целочисленная константа?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы присваиваете значения указателю. Указатель хранит адреса. Т.е. вы записываете в переменную адрес, на который она должна указывать. Поэтому обычно присвоение какого-то целого числа указателю - это ошибка, ведь вы не можете знать что там за адреса у вас в программе нужны. Если же вы какой-то адрес откуда-то взяли, то он и был бы уже типом указателя. Отсюда и предупреждение компилятора. Довольно часто присвоения указателю целого числа - это пропущенное разыменование указателя.

    Но 0 - исключение. Потому что нулем принято обозначать пустой, ни на что не указывающий указатель. Обычно для этого в C используют NULL, чтобы разделять число 0 и пустой указатель в коде. Но NULL, фактически и есть 0.

    Компилятор ничего не приводит, а просто игнорирует присвоение 0, ибо это нормальная ситуация.
    Ответ написан
    1 комментарий
  • Как замерить частоты тактов, отводимых на операцию в C?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Никак.

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

    Во-вторых, даже если вы смотрите на итоговый ассемблерный код, сколько тактов он занимает - некорректный вопрос. Операции в современных CPU разбиваются на микроперации, перемешиваются и выполняются в конвеере параллельно. А если там еще всякие обращения к памяти, то зависит от того в какой кеш оно попадет, сколько тактов процессор будет синхронизировать кеши и так далее. Даже если нет обращения к памяти, то есть переименование регистров. И нет никакой гарантии что одна и та же операция будет выполнятся одинаковое количество тактов всегда.
    Ответ написан
    Комментировать
  • Корректен ли данный код, возможна ли оптимизация?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В целом неплохо, оптимизировать тут нечего, ибо программа тривиальная и работает так быстро как это только возможно.

    По коду есть комментарии:
    1)
    if ((valVAT == 10) || (valVAT == 18) || (valVAT == 20)) {
    ...


    Тут у вас один большой мега-if в котором что-то делается. Гораздо проще для понимания и визуально читабельнее, если делать "ранний выход". Вместо if(a) { много кода } стоит писать:
    if (!a) {
      continue; // или return; если это в функции.
    }
    // много кода.


    У вас стоит сначала проверить, что valVAT == 0 и выйти из цикла через break в этом случае. Потом проверить, что valVat != 10 && valVAT != 18 && valVAT != 20 и вывести сообщение об ошибке и сделать continue. Дальше уже идет тело цикла с вычислениями.

    2) Вместо if(chng == 1) {} else if (chng == 2) {}... стоит использовать конструкцию
    switch (chng) {
    case 0:
      // код
      break;
    case 1:
      // код
      break;
    case 2:
      // код
      break;
    default:
      // сообщение об ошибке
      continue;
    }


    3)
    sleep(1) после вывода сообщения об ошибке, на мой взгляд не нужен. Зачем это? Заставить пользователя прочитать сообщение об ошибке?
    Ответ написан
    4 комментария
  • Почему добавляется лишний символ в массив?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы не копируете '\0' на конце. Поэтому после приписывания идет мусор. И так получается, что у вас в памяти там мусор "v\0".

    Вторая проблема, вы пишите в строку s, не меняя ее размер.
    char s[] = "abc"; выделяет ровно столько памяти, сколько нужно для "abc", да еще и на стеке, раз у вас переменные локальные.

    Вы при дописывании чего-то к строке затираете другие переменные. Так у вас совпало, что после name идет surname на стеке. Поэтому вы переписываете память второй строки (но без первого символа, который занял место '\0' в name. Именно поэтому мусор в конце - это неперезаписанный конец surname "v\0". Если поменять местами переменные, то вы может стек перепишите и у вас программа вообще упадет.

    Вам надо строки выделять с запасом: char name[1000] = "Ivan";
    Ответ написан
    Комментировать
  • Параметры функции?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Потому что иначе невозможна рекурсия. Что если у вас f(1,3) захочет вызвать f(0,0). Еще придется эти глобальные переменные переписать и потом как-то восстанавливать, если после вызова f(1,3) еще что-то хочет делать с этими параметрами.

    Потом, это тупо неудобно. Для каждой функции нужен свой набор глобальных переменных.

    Это про второй ваш вариант.
    В третьем же a и b локальные переменные. Получается вы их никак снаружи функции не сможете задать.

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

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    У вас переменные correct_Login и correct_Password не инициализируются. Вы их можете затереть в 0, но 1 они никогда не были и не станут.

    Теперь несколько замечаний по коду.

    Не нужно декларировать extern в коде функции для глобальных переменных. Не нужно дописывать '\0' на конце строковых констант, оно там и так будет в конце добавлено автоматически.
    Ответ написан
    1 комментарий
  • Как распараллелить цикл for с помощью OpenMP?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Что за A(i, j)?
    Похоже у вас там алгоритм Гаусса, и это должен быть массив.

    Внешний цикл по i нельзя параллелить в Гауссе, а вот вычитание строк можно.
    Допишите перед циклами по j и k это:
    #pragma omp parallel for collapse(2)

    В последних двух циклах тоже нельзя внешний цикл параллелить, ибо результат последующих вычислений зависит от предыдущих итераций. А вот перед внутренним циклом смело втыкайте #pragma omp parallel for.
    Ответ написан
  • Почему вылезает ошибка при компиляции?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Какой-то библиотеки не хватает. Надо ее найти и дописать через -L путь к ней и через -l ее имя.
    Попробуйте дописать:
    -Lc:\Python39\Lib -lpython39
    Ответ написан
  • Зачем нужны нижние подчеркивания перед функциями в C?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В самом языке это подчеркивание не означает ничего. Это программисты какой-то смысл в эти подчеркивания вкладывают. Может, у авторов кода так принято обозначать "приватные" функции - что-то, что они сами используют, что не положено использовать пользователям библиотеки.
    Ответ написан
    Комментировать
  • Как распараллелить тройной цикл for с помощью OpenMP?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    В вашем примере скорее всего достаточно распаралеллить только циклы по i.

    Но, если у вас n меньше количества потоков, то можно использовать диррективу collapse. Подробнее можете почитать в документации (на странице 185).

    Или можете расплющить 3 вложенных цикла в один руками так:
    int n3 = (n-2)*(n-2)*(n-2);
    for (int iteration = 0; iteration < n3; ++iteration) {
      i = iteration / ((n-2)*(n-2)) + 1;
      j = iteration / (n-2) % (n-2) + 1;
      k = iteration % (n-2) + 1;
      // тут идет содержимое трех циклов по i,j,k = 1..n-2
    }

    Это просто перенумерация всех троек значений. Каждую тройку индексов i,j,k можно рассматривать как трехзначное число в (N-2)-ичной системе счисления. Поэтому можно каждое число от 0 до (n-2)^3 разложить в n-2)-ичную систему счисления через / и % и получить три индекса.

    Но collapse и, тем более, ручной вариант будут иметь накладные расходы на вычисление индексов. Поэтому их имеет смысл использовать только если у вас n меньше количества доступных потоков.
    Ответ написан
    Комментировать
  • Почему не происходит перемещение в нужную папку?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Потому что компилятор ищет Python.h во время компиляции. В это время никакой main() не выполняется и chdir ничего не делает. Надо указать компилятору, где искать хедеры.

    Как вы компилируете? Вы под виндовс, видимо, сидите - у вас visual studio или вы gcc используете? Или что-то еще? Используете ли вы cmake или какую-то еще систему сборки? Приведите буквально ту команду/ваши действия, которые приводят к выводу на экран ошибки.

    В итоге все должно вылиться в дописывание флага -I"c:\Python39\include" к команде компиляции. Если какая-то система сборки, то прямо в файле проекта можно как-то указать эту опцию.

    Сам же include нужно делать без всяких путей, просто #include <Python.h>.
    Ответ написан
  • Как вывести Среднее арифметическое через функцию?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    У вас переменная s локальная в main(), а вы ее в A() используете.

    Сделайте A() возвращающей среднее (и это должен быть не int а float). Заведите переменную для суммы внутри A. А функция PrintS() должна будет принимать это среднее для печати. А то и вообще удалите PrintS - функция для одной операции вывода несет мало смысла.
    Ответ написан
    Комментировать
  • Как разложить число на множители(си)?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не получается остановиться только на двух множителях.


    Приведите ваш код, который не останавливается. По идее, достаточно в него вставить return после нахождения первой пары множителей.
    Ответ написан
  • Не компилируется код?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    У вас операция присвоения лежит вне функции. Компилятор ждет там декларации переменных, функций, типов, вот это вот все, а у вас там операция. Перенесите присвоение в main().

    Если вы хотите структуру инициализировать, то можно пользоваться списком инициализации:
    struct {
            int debug;
    } config = {1};
    Ответ написан
    Комментировать
  • Как найти полусумму 32-битных знаковых чисел?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Прочитать бинарно не можете? Есть функция read.

    Читайте ей по 4 байта 2 раза в char buf[4].

    little-endian означает, что сначала идут самые минимальные байты. Т.е. buf[0] - это младшие 8 бит числа, buf[3] - старшие. Для собирания числа воедино смотрите на операцию сдвига. (int)buf[3] << 24 | (int)buf[2] << 16 поставит на место 2 старших байта (младшие додумайте сами).

    Тип 64-х битных чисел - long long. Вам в условии посоветовали им пользоваться.

    Сложить 2 числа сами сможете?

    Бинарный вывод делается, внезапно функцией write.

    Ну, еще входной и выходной файлы, возможно, открыть придется, через функцию fopen.
    Ответ написан
    3 комментария
  • Как сортировать массив с рандомными значениями?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    for(d=0; d < n; d++)
      x[i] = rand();
     printf("%d", x[i]);


    Цикл по d а присваивание в x[i]. Еще скобок нет, printf выполнится только один раз после цикла.

    Еще вы не выводите массив после сортировки, как вы вообще собираетесь понимать, что ваша программа работает?

    В самой сортировке (циклы по i и j), вроде, ошибок нет.
    Ответ написан
    Комментировать
  • Почему после очистки строки программа падает?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Вы очищаете msg_buf в цикле же. На второй итерации у вас msg_buf уже очищен и вы его передаете в realloc и все падает.

    Попробуйте после free присвоить msg_buf = NULL.
    Ответ написан
    Комментировать
  • Как портировать линуксовое консольное приложение под Windows?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Можно попробовать какой-нибуть mingw поставить. Получается какбы линуксовая оболочка в винде. Можно компилить в ней исходники, получающийся exe-шник автоматом получит транслирование системных вызовов. Нет гарантии, что любой код заведется, но шансы есть.

    Т.е. виндовые исходники вы не получите, но есть вариант скомпилить эти линуксовые исходники в exe-шник, который, возможно, потребует установки mingw на машину, где приложение будет работать.

    Edit, возможно mingw тут не поможет и нужен cygwin. Еще был какой-то msys. Но я не уверен.

    На худой конец, под 10 виндой есть WSL.
    Ответ написан
    8 комментариев
  • У меня калькулятор выводит целое число почему?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    y = c / d;

    Вы делите целое число на целое. В языке С в этом случае происходит деление нацело. Чтобы в результате был float, вам надо один из операндов перобразовать во float/double. Можно или явно это написать, или просто прибавить 0.0:

    y = (c + 0.0) / d;
    Ответ написан
    2 комментария
  • Как задать матрицу X[5][7] на С?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Два цикла вложенных в друг друга. Внешний по строкам, 5 итераций. Вложенный по столбцам, 7 итераций. Внутри считывание одного числа с клавиатуры, но читаете не в какую-то переменную а в x[i][j].
    Ответ написан
    Комментировать