Ответы пользователя по тегу C
  • Как сформировать сумму матриц с возможностью использовать разное их количество?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Сначала подумайте над более простой задачей и решите ее: Введите и сложите k чисел.

    С матрицами все тоже самое, но вместо ввода одного числа надо читать NxM чисел (очевидно, двумя циклами). Вместо одной переменной суммы у вас будет матрица, к которой вы двумя циклами будете прибавлять. Можно написать функции ReadMatrix, AddMatrix, может так понятнее будет.

    Да, вам нужен внешний цикл до k. Внутри он будет вводить матрицу и прибавлять ее в матрицу-сумму.
    Ответ написан
    Комментировать
  • Как написать функцию добавления/удаления элемента в массив?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    На Си будет практически то же самое. Только вместо new надо делать malloc, а вместо delete - free.
    Ответ написан
    4 комментария
  • Как исправить ошибку "Not enough RAM 'ucHeap'"?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Не специалист по микроконтроллерам... Но похоже там тупо нет столько памяти, сколько вы хотите выделить под кучу. И, если вашей программе столько надо, то вам нужен контроллер по-круче или более эффективный по памяти алгоритм.
    Ответ написан
    Комментировать
  • Почему C/C++ проекты очень долго компилируются?

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

    Архаичная система заголовочных файлов же приводит к тому, что при изменении небольшой части проекта, фактически меняется куча файлов, которые все надо заново парсить и оптимизировать.
    Ответ написан
    4 комментария
  • Как правильно использовать getopt?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    https://man7.org/linux/man-pages/man3/getopt.3.html

    Прокрутите вниз, там есть пример в examples.

    Проще некуда. Понять за вас никто не сможет.
    Ответ написан
    Комментировать
  • В каком виде изобразить такую программу?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В каком виде? В виде программы. Или в виде блок схемы.
    Ответ написан
  • Как организовать работу двух динамических массивов используя malloc?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Надо так:
    void arr_cr( int ***a , int n, int m){
        int i,j;
        a*=(int **)malloc(n*sizeof(int *));
        for( i=0 ; i < n ; i++)
            (a*)[i]=(int *)malloc(m*sizeof(int));
    }


    У вас везде напутано - вы создаете n/10/10 int*, а потом заполняете их циклом до m/8/12. Выделили 10 элементов, заполнили 8 или 12. Непорядок.

    И когда вы выделяете память под строку массива в цикле, вы должны не sizeof(int) памяти выделять, а в m/8/12 раз больше - вы же под всю строку память выделять должны.

    edit: еще не заметил, что массив передается по значению. Надо передавать int***.
    Ответ написан
    Комментировать
  • Написать функцию которая возвращает строку с тремя пробелами между слов, начало и конец строки не должны быть с пробелом?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Лень разбираться в вашем коде, но на кой черт там вообще замена? Эта задача решается потоково - прочитали символ из входной строки, добавили от 0 до 4-х символов выходную строку. Можно еще сначала один раз пройтись и подсчитать длину в ответа, если жалко 3*strlen(input) заводить. Длина ответа - 3*(k-1) + c, где k - количество слов, а с - количество непробельных символов.

    Главное наблюдение - любое слово начинается с непробельного символа, перед которым идет пробельный (или начало строки).

    Соответственно решение вообще тупое - прочитали непробельный символ - если он начало слова, вывели 3 пробела. В любом случае вывели этот непробельный символ. Если прочитали пробельный символ - пропустили его (ну или флаг установили для упрощения кода в первом случае).
    Ответ написан
    Комментировать
  • Fopen segmentation error?

    wataru
    @wataru
    Разработчик на С++, экс-олимпиадник.
    Еще ошибка:
    struct BMP_HEADER *header;
    ...
     fread(&header,sizeof(BITMAPFILEHEADER),1,fp);


    header - это указатель. 8 байт (на 64-битных системах). Вы в указатель (переменную-адрес) читаете структуру BITMAPFILEHEADER, сколько бы байт оно не было. Вряд ли это то, что вы хотели сделать.

    Надо выделять BMP_HEADER через malloc или на стеке (как локальную переменную, а не указатель). И передавать в fread указатель на структуру, а не адрес указателя. То же самое со второй структурой.
    Ответ написан
    Комментировать
  • Почему инициализация целочисленного указателя 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>.
    Ответ написан