• Как найти число которое будет делиться без остатка на все элементы массива?

    @Mercury13
    Программист на «си с крестами» и не только
    Берём НОК. При расчёте НОКа случилось переполнение ((a · b) div b ≠ a) → нет такого.
    Дальше (MAX_UNSIGNED_LONG div НОК) · НОК.

    UPD. Поставил новый код обнаружения переполнений при умножении; старый явно ошибочный: 11·11 = 121, и при двух десятичных знаках будет 21 > 11.
    UPD2. В курсе, как считают переполнение-устойчивый НОК? НОК(x,y) = (x div НОД(x,y)) * y
    Ответ написан
    Комментировать
  • Матрица поворота плоскости изображения или вектора на центр камеры относительно осей координат?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое. То есть в какую сторону смотрит объектив и как он повёрнут вокруг оси.
    Второе (указатель на центр камеры) — это вектор c.
    Ответ написан
    Комментировать
  • Решение уравнения 5 класса в Си?

    @Mercury13
    Программист на «си с крестами» и не только
    Это дело сложное. И я бы разделил его на три перекрывающихся этапа.
    1. Увидеть в строке уравнение от одной переменной. Например, в таком виде.
    5ac73cfdb0af3347885965.png
    2. Увидеть в том, что получилось, линейное уравнение.
    3. Запустить модуль «Линейное уравнение», который приведёт подобные слагаемые и высчитает ответ.
    Ответ написан
    Комментировать
  • Как програмным путем, закрепить ярлык на "Начальном экране" Win 10?

    @Mercury13
    Программист на «си с крестами» и не только
    Есть способы, но они периодически меняются.
    Это политика Microsoft: программы не должны засирать эти экраны.
    https://blogs.msdn.microsoft.com/oldnewthing/20030...
    Ответ написан
  • Как вернуть массив строк C++?

    @Mercury13
    Программист на «си с крестами» и не только
    ВНИМАНИЕ: У вас есть пара тонких мест.
    РАЗ. не забудьте, что строковые литералы в Си — это нуль-терминированные строки, и "\0" по факту будет пустой строкой. Строку из одного нулевого символа можно загнать в string — например, конструктором string(begin, end) или s += '\0', но не конструктором string(const char*).
    ДВА. Этот static будет инициализирован при первом вызове. Второй вызов вернёт тот же массив.
    ТРИ. Строчку лучше передавать как string *func(const string& s) {}

    К делу. Массив — это довольно сложный объект, и возникает вопрос: кто этим массивом будет владеть после того, как он покинет пределы функции?
    1. Владеет система времени выполнения. Это отлично ответил Роман, дам только ключевую строчку.
    string* arr = func(exp);
    НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ: если массив используется в чьих-то «конских» конструкторах-деструкторах статических объектов (из-за отсутствия модулей Си++ не позволяет установить на уровне языка порядок создания/уничтожения статических объектов).

    2. Владеет какой-то объект.
    string *func(string s) {
        static string* ar = nullptr;
        if (ar) delete[] ar;
        ar = new ar[3];
        ar[0] = "qwe";
        ar[1] = s;
        ar[2].clear();
        return ar;
    }

    НЕЛЬЗЯ ИСПОЛЬЗОВАТЬ: ну, это уж разбирайтесь сами с этим объектом, сколько он будет жить и насколько долго он будет держать массив. В данном случае каждый новый вызов уничтожает старый массив. (Код корявый, потому что последний массив не уничтожается.)

    3. Владеет тот, кто вызывает. Лучше для таких целей использовать какой-нибудь std::vector.
    vector<string> func(string s) {
        vector<string> r;
        r.reserve(3);
        r.push_back("qwe");
        r.push_back(s);
        r.push_back(std::string());
        return r;
    }
    Ответ написан
    Комментировать
  • Объясните пожалуйста смысл строк(указатели)?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами структура данных под названием «односвязный список». У каждого элемента ссылка на следующий, у всей очереди ссылка на голову (front) и иногда на хвост (rear).

    Для чего нужна проверка на заполненность — непонятно, ведь ёмкость списка не ограничена и единственный способ убедиться, что очередь полна — завести память под новый элемент. Выпадает авария std::bad_alloc — значит, памяти не хватило. Если только для каких-то прикладных нужд: так, в StarCraft очередь на строительство пять юнитов, и точка. (Есть другой тип очереди, т.н. циклическая очередь — вон там ограничено.)

    Как работает enqueue: создаём новый элемент, следующий за ним — nullptr. Если очередь пуста, направляем на него front и rear. В противном случае пристраиваем его за тем, на который «смотрит» rear, и перенаправляем rear. Таким образом, «направляем rear» можно вынести за скобки, а остальные два исполнить в зависимости от пустоты очереди.
    Ответ написан
    3 комментария
  • Расскажите в каких ситуациях используют класс quiloader в QT?

    @Mercury13
    Программист на «си с крестами» и не только
    В крайне-крайне редких случаях, когда вы пишете редактируемый пользовательский интерфейс. Например, в ERP.
    Разумеется, QUiLiader под капотом есть всегда, но среднему программисту он ни к чему.
    Ответ написан
    Комментировать
  • Как программировать игру в игре?

    @Mercury13
    Программист на «си с крестами» и не только
    Обычно для этого используют скриптовый движок. Наиболее известный — Lua.

    Также используют триггеры, эталонный пример — StarCraft.
    Но, работая с триггерами, надо разделять «условие» и «повод». Повод — это событие-импульс, которое МОЖЕТ спровоцировать срабатывание триггера. Условия — это уже дополнительные вещи, которые проверяются потом.

    Третья возможность — движок, основанный на данных. Например, задаём тип атаки, количество HP, тип движения и прочее, и вся эта библиотека уже записана в коде. Эталонный пример — Doom (самый ещё первый, 1993 года). Кстати, в его последователе Hexen появились скрипты.
    Ответ написан
  • Где ошибка в самодельном strcmp?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваш код коряв (и пишет за пределы буфера, если в потоке действительно окажется 2048 байт) но нуль-терминированные строки отрабатывает правильно.

    TCP работает сплошным потоком, и если вы послали в сокет нечто ещё, кроме «123123», он считает весь поток до 2048 байт и, разумеется, строки не совпадут: с одной строны «123123», с другой, например, «123123qwe».

    Вам надо своими силами разбивать TCP-поток на сообщения — например, тем самым нулевым символом, CR или двумя/четырьмя байтами длины пакета.
    Ответ написан
  • Какова очередность присваивания нового объекта?

    @Mercury13
    Программист на «си с крестами» и не только
    А это значит, что манипулируя членами b я буду редактировать память a?

    Нет, конечно.

    Type& Type::operator=(const Type& x);
    Задача операции присваивания — сделать, чтобы объект слева (он же *this) стал копией объекта справа (он же x).

    Почему операция присваивания берёт Type& по ссылке? Да потому, что взять по копии — это вызвать конструктор копирования. Вполне можно написать
    BigInt& BigInt::operator = (int x);
    когда слева «большой» тип, а справа — «маленький», и его конструктор копирования незначителен (а то и равняется накладным расходам на ссылку, как у того же int). Но когда с обеих сторон один и тот же тип — это часто бездумный вызов конструктора копирования (собственные конструктор копирования и операцию = обычно пишут, когда нужна хитрая логика, а не тривиальное копирование).

    Почему операция присваивания возвращает Type&? Просто чтобы работали конструкции типа a = b = c. Может и void возвращать, если хочешь.

    class C
    {
    public:
        C() {}
        C (const C&) { std::cout << "Copy ctor" << std::endl; }
        C & operator = (const C&) { std::cout << "Assign" << std::endl; return *this; }
    };
    
    int main()
    {
        C a;
        C b = a;

    Выведет «Copy ctor». То есть ответ на первый вопрос — конструктор копирования.

    В литературе что я читаю это называется присваиванием

    Не присваивание, а инициализация. Присваиванием было бы…
    Type b;
    b = a;


    Type b = Type(a);

    В идеале тут два конструктора копирования и один деструктор, однако компилятору даётся воля уменьшать их количество. Потому только «copy ctor».

    Код
    int a = 10;
    C b = C(a);

    также даёт один вызов C(int). А C(const C&) не вызывается ни разу.

    UPD. Одно из нововведений Си++11 — чтобы даже без этих негарантированных оптимизаций, когда один объект исчезает, а второй появляется, можно было вместо копирования проводить нечто более простое, не требующее отвода-возврата памяти. Я-то экспериментировал в режиме Си++03, но в Си++11 уже были бы конструктор копирования, конструктор перемещения и деструктор.
    Ответ написан
    Комментировать
  • Почему точность вычислений в float нарушается для чисел определённой степени двойки?

    @Mercury13
    Программист на «си с крестами» и не только
    Связано, вероятно, с особенностями перевода дробных чисел в текст. Я попробовал повторить на Си++, ничего интересного не вышло. Зато методы перевода дробного в текст G++ и GRISU дают несколько разные результаты.
    Ответ написан
    Комментировать
  • В чем здесь ошибка (перегрузка операторов)?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы наладили операцию String << ostream → ostream. Надо наоборот, ostream << string → ostream.

    Такую операцию можно наладить только за пределами класса (возможно, как friend).
    Ответ написан
    1 комментарий
  • Почему sizeof показывает фактический размер массива хотя по сути имя массива это указатель на первый элемент?

    @Mercury13
    Программист на «си с крестами» и не только
    Несмотря на то, что массив часто отождествляют с указателем, массив — это НЕ указатель. У него, например, другие операции приводят к неопределённому поведению.

    И самое противное в Си — это то, что в коде
    void sort(int x[5]);
    x — это не массив, а именно что указатель. Чтобы был массив, надо Си++
    void sort(int (&x)[5]);
    И компилятор даже подсвечивает, что параметр функции, отмеченный как массив — всегда указатель.
    typedef int Arr[SIZE];
    int sum(Arr arr, int n)
    // warning: 'sizeof' on array function parameter 'arr' will return size of 'int *' [-Wsizeof-array-argument]|
    Ответ написан
    Комментировать
  • Как написать визуализацию алгоритма сортировки в delphi?

    @Mercury13
    Программист на «си с крестами» и не только
    longclaps написал, как всё это дело должно выглядеть внешне.
    Внутренне это реализуется просто.
    1. В OnPaint какого-нибудь компонента (PaintBox, скажем) при определённых условиях выводим визуализацию.
    2. Блокируем весь пользовательский интерфейс (кроме какой-нибудь кнопки «Стоп»).
    3. Каждый раз, когда надо что-то увидеть, делаем paintBox.Repaint, Application.ProcessMessages и небольшую задержку.
    4. При нажатии кнопки «Стоп» ставим какую-то переменную в true. Сортировка реагирует на эту переменную и останавливает цикл: либо простым Exit, либо аварией Abort и последующей реакцией на EAbort.

    Если есть желание сравнить несколько алгоритмов сортировки, стоит сделать функцию типа DoSwap(i, j : integer), которая меняет местами элементы, устанавливает всё, что надо для визуализации, инициирует перерисовку и делает задержку.
    Ответ написан
    Комментировать
  • Что значит эта строчка?

    @Mercury13
    Программист на «си с крестами» и не только
    If the most significant bit is set, the key is down, and if the least significant bit is set, the key was pressed after the previous call to GetAsyncKeyState.

    Проверка на младший бит (сокращённая запись if ((GetAsyncKeyState(VK_F1) & 1) != 0). Он означает: с предыдущего вызова GetAsyncKeyState клавиша хоть раз нажималась. С одной стороны, этот бит нерекомендуемый (работает, когда нет других программ, вызывающих GetAsyncKeyState). С другой, возможно, младший бит GetAsyncKeyState() в современной реализации Windows работает именно так, как надо (если программа неактивна, GAKS возвращает 0).

    GAKS обычно используется в играх и прочих динамичных программах; в рабочем ПО используют оконные сообщения.
    Ответ написан
    1 комментарий
  • Как уменьшить связанность классов?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Что такое Container и для чего он нужен? Возможно, от этого дела удастся избавиться или заменить интерфейсом?
    2. Не должен конструктор Graph брать в параметры Parser. Наоборот, Parser функцией parse() должен возвращать Graph.
    3. Config стоит разбить на несколько частей: одна специфична для Graph, вторая для Parser. Как их объединять — зависит от того, кому какие настройки нужны.
    Ответ написан
    2 комментария
  • Есть ли разница между двумя функциями?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Будьте осторожны, перед нами динамический массив, сделанный расширением стека. Не на всех компиляторах есть, плюс стек ограничен парой мегабайт.
    Нормализацию размера лучше сделать shift %= size;
    Подпрограмма работает с локальной переменной и всё, что она делает, идёт на экран и больше никуда.
    (вообще стоит разделять обработку и вывод!)
    Время работы size.

    2. Сдвигаем на один элемент нужное количество раз. Время работы shift·size.

    3. Как за size «на месте»…
    квоПрох := НОД(shift, size)
    для i = [0..квоПрох)
      i1 := i
      tmp := a[i]
      вечный цикл
        i2 := (i1 + shift) % size
        если i2 = i
          прервать вечный цикл
        a[i1] := a[i2]    
        i1 := i2
      a[i1] := tmp
    Ответ написан
    Комментировать
  • Как создать "библиотеку" для NPC на языке C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Из такого вопроса видно, что человек всё ещё нетвёрдо знает программирование, а уже пытается программить игру.
    И тут есть два варианта.

    1. Движок с нуля. Тонкая графическая прослойка наподобие SDL, оставляющая 100%-ю свободу движкописателям — это тоже «с нуля» и всячески рекомендуется даже продвинутым (не нужно писать всякие там Alt-Tab’ы и прочую дрянь, далёкую от игры). Тогда пусть начнёт с «питончика» (https://ru.wikipedia.org/wiki/Snake_(игра) ) или текстового квеста.
    А потом, когда доберётся до платформера или CRPG, он поймёт, каким образом привязать к монстру характеристики.

    Первое приближение (не слишком удобное для скриптования и подходящее для платформеров/action-RPG, но негодное в настоящих RPG) — сделать каждому компьютерному персонажу «класс» (не путать с классом ООП), включающий кол-во HP, внешний вид и прочее. А также «набор скриптов» — для поведения в диалогах, запрограммированного передвижения, превращения из «болванчика» в компьютерного врага, и т.д. Без набора скриптов он просто компьютерный враг, тупо нападающий на ПиСя.

    Если скриптовый движок чужой (тут уже не зазорно брать чужое) — вы уж смотрите, что он может и куда его впихнуть. А если хотите написать сами — лучше делайте триггеры, как в StarCraft.

    2. На чужом движке. Это уж смотрите, что движок может, какие возможности в нём «в коробке», а какие придётся дописывать своим кодом и чужими модулями. Не знаком ни с одним. Чужой движок — довольно противное дело для начинающего программиста: он автоматически формирует какую-то структуру программы, и программисту приходится не столько творить, сколько разбираться с этой структурой. С одной стороны, можно быстро написать довольно сложную игру, с другой — не так много радости «а у меня заработало».
    Ответ написан
    Комментировать
  • Как реализовать метод буквенного номера по числу?

    @Mercury13
    Программист на «си с крестами» и не только
    Вот мой действующий код на «Си с крестами». Индексы — ВНИМАНИЕ — начинаются с нуля. Сумеете перевести на Яву, и из второго оставить одни буквы? Первое действует для любой длины, второе — для длины до 3 символов, присущей Excel’ю.

    std::wstring xl::colNameW(
            size_t aIndex)
    {
        wchar_t q[21];  // more than enough even for 64-bit system :)
        wchar_t* ptr = q + 20;
        *ptr = 0;   // debug
    
        // Getting size
        size_t n = 1;
        unsigned long long pw = 26;
        while (aIndex>=pw && n<20)
        {
            aIndex -= static_cast<size_t>(pw);
            pw *= 26;
            ++n;
        }
    
        FOR_S(i, 0, n)  // макрос, означающий for (size_t i = 0; i < n; ++i)
        {
            *(--ptr) = static_cast<wchar_t>(L'A' + (aIndex % 26));
            aIndex /= 26;
        }
        return std::wstring(ptr, n);
    }
    
    namespace {
    
        bool isCap(const char* x, const char* aEnd)
        {
            return (x != aEnd && *x >= 'A' && *x <= 'Z');
        }
    
        bool isDig(const char* x, const char* aEnd)
        {
            return (x != aEnd && *x >= '0' && *x <= '9');
        }
    
    }   // anon namespace
    
    
    xl::CellCoords xl::parseCellCoords(
            const char* aStart, const char* aEnd)
    {
        enum {
            AA = 26,
            AAA = 26 + 26 * 26
        };
        xl::CellCoords r;
        // Letter
        r.col = 0;
        if (!isCap(aStart, aEnd))
            return CellCoords::bad();
        r.col = *(aStart++) - 'A';
        if (isCap(aStart, aEnd)) {
            r.col = (r.col * 26) + *(aStart++) - 'A';
            if (isCap(aStart, aEnd)) {
                r.col = AAA + (r.col * 26) + *(aStart++) - 'A';
            } else {
                r.col += AA;
            }
        }
        // Number
        r.row = 0;
        while (isDig(aStart, aEnd)) {
            size_t r0 = r.row;
            r.row = r.row * 10 + *(aStart++) - '0';
            if (r.row < r0)
                return CellCoords::bad();
        }
        if (r.row == 0 || aStart != aEnd)
            return CellCoords::bad();
        --r.row;
        return r;
    }


    Принцип действия перевода цифра → буква.
    Находим, сколько букв в нашей колонке. Допустим, три. Вычитаем из цифры номер колонки AAA (т.е. 26 + 26·26, если нумеровать с нуля, и 1 + 26 + 26·26 — если с единицы), и оставшееся переводим в 26-ичную систему счисления (A=0, B=1, C=2…).

    Принцип действия перевода буква → цифра аналогичен. Находим количество букв. Если их три, то переводим из 26-ичной системы счисления в цифру и прибавляем номер колонки AAA.
    Ответ написан
    Комментировать
  • Возникает ошибка Ошибка C4700 использована неинициализированная локальная переменная как исправить?

    @Mercury13
    Программист на «си с крестами» и не только
    #include "stdio.h"
    #include "stdlib.h"

    Лучше это писать в угловых скобках.

    double dr(double zb)
    {
        return zb = (rand() % 100) / (100 * 1.0);
    }

    Присваиваем параметру zb что-то, чтобы его похѣрить? Параметр будет жить до конца функции и НЕ ВЕРНЁТСЯ в вызвавшую программу (параметры передаются по копии).
    Кстати, параметр zb ни на что не используется: что бы вы ни передали туда снаружи, подпрограмма в этот параметр не посмотрит.

    printf("%lf", dr(double zb));
    На G++ не скомпилировалось. Ну, написал dr(0), благо параметр не используется ни на что.

    if (d == e)
    {
        printf("Win! your cash:%lf", winWay(a, b));

    C:\TestApps\ErrUninitLocal\main.cpp|30|warning: 'd' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    А действительно, переменная d нигде никому не присваивается.

    И ещё одно. Я не знаю, как действует Visual C, но модификатор l для формата %f нужен для scanf, но не нужен для printf. Вот так-то всё это дело устроено.

    double a = winWay(a, b);
    }

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

    C:\TestApps\ErrUninitLocal\main.cpp|33|warning: 'a' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    Тут вообще забавно работает. double a — считаем, что a определилась. = winWay(a, b) — считаем, что используется ОНА ЖЕ, а не более ранняя a. Естественно, неинициализированная.

    (аналогично с loseway)
    C:\TestApps\ErrUninitLocal\main.cpp|38|warning: 'a' may be used uninitialized in this function [-Wmaybe-uninitialized]|
    Ответ написан
    Комментировать