• Что означает эта строка(модификатор в макросе)?

    @Mercury13
    Программист на «си с крестами» и не только
    Тут есть два модификатора.

    1. extern "C" — говорит, что функцию НЕ надо «козявить» на манер Си++, кодируя в имени её параметры наподобие h(int) → _Z1hi. Используется для доступа из Си++ к функциям, которые скомпилированы другим компилятором (Паскалем, Си…), а также для всяких там функций, которым надо дать фиксированное имя — например, функций DLL.

    2. __declspec(dllimport). Это нужно для доступа к функциям DLL: линкер будет брать функции прямо из DLL, без создания *.lib или *.a (как минимум MinGW так работает). Языки, сильно привязанные к определённой ОС (например, Delphi) могут создавать свои ключевые слова для доступа, например, к DLL или COM.
    procedure DoSomething(x : integer); cdecl;  external 'something.dll';

    Застандартизированный Си вынуждает полагаться на ключевые слова, начинающиеся с двух подчерков.
    Ответ написан
    Комментировать
  • Зачем нужен указатель на void?

    @Mercury13
    Программист на «си с крестами» и не только
    void* используется как указатель на сырые байтовые данные, не имеющие конкретного типа.
    Обычно это используется…
    1. В чтении-записи в файлы и на устройства, когда мы можем писать туда абсолютно любые типы.
    2. В «многоликих» функциях, которые могут принимать данные разных типов (malloc/calloc, часть функций WinAPI и ODBC).
    3. Как дескриптор — указатель, который запрещается разыменовывать. В Си для этого также часто используют указатель на недоопределённый тип, в Паскале с другими правилами эквивалентности типов — на пустой record. Но только пока не появится очередная многоликая функция вроде CloseHandle.
    4. Для обеспечения т.н. замыкания — передачи callback’у контекста, откуда была вызвана функция, вызвавшая callback.
    BOOL WINAPI EnumWindows(
      _In_ WNDENUMPROC lpEnumFunc,
      _In_ LPARAM      lParam
    );
    
    BOOL CALLBACK EnumWindowsProc(
      _In_ HWND   hwnd,
      _In_ LPARAM lParam
    );

    Вот этот LPARAM, который обычно определяется как какой-то указатель, и есть замыкание. Функция EnumWindows обещает передать его в функцию lpEnumFunc без изменений.
    (В Си++ для этого также используют виртуальные интерфейсы, но такой метод, сами понимаете, языкозависим и не годится для межъязыкового API.)

    Что происходит на стороне функции? Одно из двух (считаем, функция написана на ЯВУ).
    1. Либо вызывается некая функция устройства, которая говорит: «записать 100 байт», и дальше уже работает железо.
    2. Либо мы преобразуем void* в нужный нам тип и работаем с ним.

    Типы указателям дают по трём причинам.
    1. Вы забыли про операцию «разыменовать указатель». Чтобы его разыменовать, он должен иметь тип!
    2. Чтобы не ошибаться и не переприсвоить несовместимые указатели.
    3. Для полиморфизма — в Си++, давая delete x, мы даже можем не хранить, сколько байтов в блоке, поскольку мы знаем длину типа. (Есть ещё и виртуальные классы, но это другой вопрос.)
    Ответ написан
    Комментировать
  • Что за WINAPI, CALLBACK перед названиями функций?

    @Mercury13
    Программист на «си с крестами» и не только
    На x86 оба они — макроопределения для нестандартного соглашения вызова __stdcall.
    На ARM они ничего не делают.

    Соглашение вызова — это…
    • как на уровне регистров мы вызываем функцию;
    • кто подчищает стек за вызывающим;
    • кто отвечает за восстановление регистров, если они менялись (или есть риск, что они менялись).

    stdcall — вызов через стек, справа налево, за очистку стека отвечает функция, результат в eax (rax), функция отвечает за восстановление сегментных регистров, esp и ebp, программа за остальные.

    На ARM используется соглашение cdecl. То же самое, но за очистку стека отвечает программа (что там на ARM с регистрами, я не в курсе).
    Ответ написан
    Комментировать
  • Почему не совпадает сложность алгоритма?

    @Mercury13
    Программист на «си с крестами» и не только
    Это так называемая асимптотическая сложность — сложность при n→∞.

    Что никто не упомянул — так называемые символы Ландау.
    a(n) = o(b(n)), (читается «о малое», «меньшего порядка чем»), если lim{n→∞}a/b = 0
    a(n) = O(b(n)), (читается «о большое», «не большего порядка чем»), если a/b ограничено сверху (для дискретного n этого хватит, для непрерывного надо добавить «для какого-то n>N»).

    Два символа Дональда Кнута дополняют символы Ландау.
    a(n) = Ω(b(n)), если b(n) = O(a(n)). «Не меньшего порядка чем»
    a(n) = Θ(b(n)), если a(n) = O(b(n)) и b(n) = O(a(n)). «Такого же порядка».

    Ну а дальше идут простые пределы.
    • axn + bxn−1 + … = O(cxk + dxk−1 + …), если n ≤ k;
    • те же два многочлена o(·), если n < k.
    • те же два многочлена Θ(·), если n = k.
    Константа не важна: во-первых, при n→∞ меньшая сложность рано или поздно перевесит меньшую константу. Во-вторых, особенности реализации того или иного алгоритма на том или ином компиляторе/железе (больше/меньше команд, лучше/хуже с кэшем) эту константу могут варьировать в широких пределах;

    А значит, многочлен n(n−1)/2 = n²/2 − n/2 = Θ(n²).

    Да, и ещё: вы спутали асимптотический порядок самогó многочлена и асимптотическую сложность его вычисления. Первое, как я уже сказал, n². Сложность вычисления в лоб — n+const = O(n). А «не в лоб» — «за константу» , O(1).
    Ответ написан
    Комментировать
  • Зачем в абстрактном базовом классе создавать конструктор?

    @Mercury13
    Программист на «си с крестами» и не только
    Абстрактные классы делят на интерфейсы и частично реализованные. Грань между ними такова:
    • Интерфейс не имеет данных.
    • У интерфейса все неабстрактные виртуальные методы представляют собой или эталонное поведение, или самую частую реализацию. В обоих случаях, если что, их надо не расширять, а переписывать с нуля.

    Так вот, для интерфейсов таких конструкторов, разумеется, не нужно.

    Например, между абстрактным потоком и файлом Win32 может быть такая иерархия: Stream → HandleStream → File. Stream — интерфейс, даже если там есть что-то типа
    // virtual
    unsigned long long Stream::remainder() const { return size() - pos(); }


    HandleStream содержит уже данные (дескриптор Win32), и это уже частично реализованный класс, который крутится вокруг этого дескриптора: в деструкторе вызов CloseHandle, конструктор может принимать дескриптор, полученный каким-то «левым» образом.
    HandleStream::HandleStream(HANDLE aHandle) : fHandle(aHandle) {}
    HandleStream::~HandleStream() { close(); }
    
    void HandleStream::close()
    {
      if (Handle != INVALID_HANDLE)  { // не помню, как там эта константа в Win32
        CloseHandle(fHandle);
        fHandle = INVALID_HANDLE;
      }
    }

    Вот в таких полуреализованных классах, разумеется, конструктор может инициализировать те данные, которые там есть.
    Ответ написан
  • Как найти площадь объединения двух кругов(то что зеленым цветом)?

    @Mercury13
    Программист на «си с крестами» и не только
    Это сумма двух сегментов.
    Для каждого вычисляем угол, а дальше — ½R²(θ − sinθ).
    Ответ написан
    Комментировать
  • Законно парсить порно сайты?

    @Mercury13
    Программист на «си с крестами» и не только
    Какую информацию вы будете драть с сайтов?
    Если сам не очень легальный контент, то вы как минимум нарушаете авторские права владельцев порнухи.
    Ответ написан
  • Регрессия к среднему. Как найти коэффициент детерминации?

    @Mercury13
    Программист на «си с крестами» и не только
    Коэффициент детерминации тут ни к чему.
    Чтобы получить коэффициент детерминации, нужно много статистики и зависимость y(x).
    Этот товарищ, насколько я понял, использовал как модель единичный лаг. Взял много команд и футбольных сезонов, модель — сколько очков получено в прошлый год, зависимая переменная — сколько очков в этот год.
    Ответ написан
    Комментировать
  • Регрессия к среднему. Что за формула?

    @Mercury13
    Программист на «си с крестами» и не только
    R² — это так называемый коэффициент детерминации. Как он работает?
    Изначальная дисперсия переменной y будет D1.
    Наладили модель — дисперсия модели D2, которая, надо полагать, меньше D1 (особенно если вся выборка обучающая, без экзаменационной; здравствуй, переобучение!).
    Тогда R² = 1 − D2/D1 = (D1 − D2) / D1.

    Дисперсия, как известно, измеряется в квадратных попугаях. И, кроме того, для независимых величин D(x+y) = Dx+Dy. Таким образом, √(D1 − D2) ~ √R² — это тот разброс, который мы объяснили моделью.

    Но он, по-видимому, натягивает сову на глобус. В его модели объяснённый разброс — 0,780 (ещё и округлять не умеет), необъяснённый — √D2 ~ √(1 − R²) = 0,626, и в зависимости от того, что хочешь доказать, можно манипулировать статистикой в ту или иную сторону. Вот так я могу сказать, что с такими разбросами всего на 0,780 / (0,780+0,626) = 55% умение, и на 45% — удача. Так что нет, коэффициент детерминации, и точка. Повторяю, для независимых величин один разброс частично компенсируется другим, и D(x+y) = Dx+Dy. В квадратных попугаях.
    Ответ написан
    2 комментария
  • Как изменить систему счисления из 0-f в 0-z-Z?

    @Mercury13
    Программист на «си с крестами» и не только
    Скорее всего, какой-то вариант BASE64.
    Ответ написан
    Комментировать
  • Как найти число которое будет делиться без остатка на все элементы массива?

    @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 уже были бы конструктор копирования, конструктор перемещения и деструктор.
    Ответ написан
    Комментировать