Ответы пользователя по тегу C++
  • Столкнулся с проблемой парсинга заголовка wav звука?

    @Mercury13
    Программист на «си с крестами» и не только
    Пропускать «левые» блоки, пока не дойдём до data! Что ещё делать?
    У меня получился файл длиной 5.241.822, и там такие блоки: по смещению 0C fmt длиной 0x10, по смещению 24=0C+8+10 LIST длиной AA, и по смещению D6=24+8+AA будет нужная нам data.

    Уточню, что я имел в виду. RIFF — это стандартный блочный формат, не ограничивающийся WAV’ом. Допустим, есть формат RMI = RIFF MIDI. Ваше решение подразумевает, что за блоком «fmt» сразу идёт блок «data», что не всегда верно.

    Ещё раз, мужик! По смещению 0C будет блок «fmt»: 4 байта сигнатура, 4 байта длина и 0x10 байт данные.
    За этими 0x10 байтами, по смещению 24=0C+8+10, идёт блок LIST: 4 байта сигнатура, 4 байта длина и 0xAA байт данные. Блок не наш — пропускаем эти байты, и переходим сразу на смещение 0xD6=24+8+AA. Там 4 байта сигнатура, 4 байта длина и 0x4FFB00 байт данные. Их-то и читаем.
    Ответ написан
  • Почему "идентификатор не определён"?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Вытащи p, p1, p2 наружу из if. Читай «область видимости».

    2. Я бы сделал так…
    Work* p = NULL;
    if () {
      p = new Work();
    }
    delete p;

    Работает, потому что NULL можно спокойно уничтожать, и ничего не будет.

    На Си++11 можно также использовать умные указатели.
    std::unique_ptr<Work> p;
    if () {
      p = std::make_unique<Work>();  // простите, это Си++14, на 11 чуть не так.
    }
    Ответ написан
    Комментировать
  • Сhar *dictionary[][] = {}; Зачем тут const?

    @Mercury13
    Программист на «си с крестами» и не только
    Итак. Да, строковый литерал — это const char[], преобразуемое в const char*.
    • Си++03 разрешал (но не одобрял).
    • Си++11 запрещает.
    • Одинаковые строковые литералы компилятор может преобразовать в один адрес, а также хранить в памяти, куда писать нельзя — потому const. И в Си без крестов тоже, только там попытка записи даст простой AV.
    • Const — это т.н. «cv-модификатор» (const-volatile), входит в систему типов Си++, устанавливается свободно, снимается операцией const_cast и означает, что объект нельзя изменять.
    Ответ написан
  • Есть ли в для C++14 map с поддержкой constexpr хэша?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, разумеется. ООП подразумевает смену состояния объекта, а в константных выражениях смена состояния запрещена. Может, и можно какую-то собственную горбушку придумать, но не знаю, как (даже конструктор — смена состояния).

    Если же задача — посчитать при компиляции хэш для константного элемента, и всё… вот это интересно, но тоже не знаю, как реализовать.
    Ответ написан
  • Какой парсер для математических выражений на Qt посоветуете?

    @Mercury13
    Программист на «си с крестами» и не только
    Egorithm, Отлично, теперь у вас есть файл библиотеки *.a, include-файлы *.h и разделяемая библиотека *.so.
    Задачи, в порядке приоритета.
    1. Заставить прогу компилироваться, для этого надо в проекте прописать доступ к include-файлам *.h.
    2. Заставить прогу линковаться, для этого надо в проекте прописать доступ к *.a (-lmuparser -L$$PWD).
    3. Заставить прогу запускаться, закинув куда надо *.so.
    Ответ написан
    1 комментарий
  • Как собрать библиотеку .lib [muParser]?

    @Mercury13
    Программист на «си с крестами» и не только
    Ну, раз уж решил пойти третьим путём (Как подкючить библиотеку [muParser] к Qt? ) — лови проект.

    Как вы видите, в большинстве случаев проект библиотеки строится тривиально: ищем, что надо включить в DEFINES, и затыкаем предупреждения.
    CONFIG -= qt
    
    TEMPLATE = lib
    CONFIG += staticlib
    
    CONFIG += c++11
    
    # The following define makes your compiler emit warnings if you use
    # any Qt feature that has been marked deprecated (the exact warnings
    # depend on your compiler). Please consult the documentation of the
    # deprecated API in order to know how to port your code away from it.
    DEFINES += QT_DEPRECATED_WARNINGS MUPARSER_STATIC
    
    QMAKE_CXXFLAGS += -Wno-deprecated-copy -Wno-cast-function-type
    
    # You can also make your code fail to compile if it uses deprecated APIs.
    # In order to do so, uncomment the following line.
    # You can also select to disable deprecated APIs only up to a certain version of Qt.
    #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
    
    SOURCES += \
        src/muParser.cpp \
        src/muParserBase.cpp \
        src/muParserBytecode.cpp \
        src/muParserCallback.cpp \
        src/muParserError.cpp \
        src/muParserInt.cpp \
        src/muParserTest.cpp \
        src/muParserTokenReader.cpp
    
    HEADERS +=
    
    INCLUDEPATH += include


    (ВНИМАНИЕ! Я использую новейший MinGW из MSYS, он на две версии новее, и, возможно, некоторые из предупреждений, которые я заглушил, не нужны.)

    В программе придётся указать
    DEFINES += MUPARSER_STATIC
    
    INCLUDEPATH += ../MuParser/include
    
    LIBS += -L$$PWD -lmuparser


    Если что, в MSYS тоже есть MuParser, хотя он у меня не установлен.
    pacboy sync muparser:i muparser:x
    Ответ написан
    Комментировать
  • Как подкючить библиотеку [muParser] к Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Тут есть несколько вариантов.
    1. Собрать *.a (любым подходящим методом), закинуть h-файлы в каталог include компилятора, *.a в каталог lib компилятора. В проекте добавить LIBS += -lmuparser.
    2. Закинуть исходный текст библиотеки куда-то в проект, добавить *.cpp (возможно, не все) в этот самый проект. Чтобы удобнее было подключать файлы, прописать INCLUDEPATH += muparser/include
    3. Промежуточный вариант — собрать *.a, закинуть его и *.h куда-то в проект. В проект добавить LIBS += -L$$PWD -lmuparser, INCLUDEPATH += muparser/include
    4. Собрать пакет для Qt. Как — не знаю.

    Когда каким методом пользуюсь.
    1. Только если библиотека есть в дистрибутиве MSYS.
    2. В подавляющем большинстве случаев.
    3. Иногда, особенно если библиотека большая. Ну и если авторы предлагают «официальную» DLL’ку — предварительно собрав, например, через Dependency Walker + DllTool подходящий *.a и заверсионировав его. (В больших проектах не обойтись без линкера LLD, но он, в отличие от LD, не подхватывает *.DLL, надо создавать файл библиотеки.)
    4. Если есть «официальный» пакет. Одна такая библиотека — QWT.
    Ответ написан
    1 комментарий
  • Восходящее преобразование массива производного класса к родительскому?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему нельзя: если мы объявим ящик бананов ящиком фруктов и положим туда яблоко, он перестанет быть ящиком бананов.
    #include <iostream>
    
    class Vocal {  // интерфейс
    public:
        virtual void shout() = 0;
        virtual ~Vocal() = default;
    };
    
    class Dog : public Vocal {
    public:
        virtual void shout() override { std::cout << "Woof!" << std::endl; }
    };
    
    class Unrelated {};
    
    // ВАРИАНТ 1. Метод выкручивания рук.
    
    void shoutAll_v1(Vocal** x, int n)
    {
        for (int i = 0; i < n; ++i)
            x[i]->shout();
    }
    
    template <class T, int N>
    inline void shoutAll_v1(T* (&x)[N]) {
        // Тупая проверка концепции, ждём Си++20
        static_assert (std::is_base_of<Vocal, T>(), "Need array of Vocal");
        T** xx = x;
        shoutAll_v1(reinterpret_cast<Vocal**>(xx), N);
    }
    
    // ВАРИАНТ 2. Виртуальный полиморфизм.
    
    class Choir { // интерфейс
    public:
        virtual int size() const = 0;
        virtual Vocal& at(size_t i) const = 0;
        virtual ~Choir() = default;
    };
    
    void shoutAll_v2(const Choir& x)
    {
        int sz = x.size();
        for (int i = 0; i <sz; ++i)
            x.at(i).shout();
    }
    
    template <class T>
    class VocalArray : public Choir {
    public:
        template <int N>
        VocalArray(T* (&x)[N]) : fData(x), fSize(N) {}
        int size() const override { return fSize; }
        Vocal& at(size_t i) const override { return *fData[i]; }
    private:
        T** const fData;
        int fSize;
    };
    
    int main()
    {
        Dog* sons[3];
        for(auto& x : sons) {
            x = new Dog;
        }
        //Unrelated* unrel[3];
    
        std::cout << "V1" << std::endl;
        shoutAll_v1(sons);
        //shoutAll_v1(unrel);   не компилируется
    
        std::cout << "V2" << std::endl;
        shoutAll_v2(VocalArray<Dog>(sons));
        //shoutAll_v2(VocalArray<Unrelated>(unrel));  не компилируется
    
        return 0;
    }
    Ответ написан
    4 комментария
  • Символ собачка в строке?

    @Mercury13
    Программист на «си с крестами» и не только
    Какую СУБД вы используете? Не думали работать с подготовленными запросами?

    SELECT * FROM users WHERE email=? and password=?;
    Ответ написан
  • Вопрос по алгоритму хеширования паролей?

    @Mercury13
    Программист на «си с крестами» и не только
    На сервер идёт пароль (нечего и говорить, что должен быть поднят HTTPS).
    Сервер вычисляет хэш этого пароля и сверяет.
    Задача хэша — исключить восстановление пароля при утечке базы.

    > Получать ли мд5 хеш с сервера и потом сравнить
    Принятие решений на клиенте

    > или же загружать на сервер и там он сравнит?
    Загружать, но не хэш, а пароль!
    Ответ написан
    Комментировать
  • Почему я не вижу результаты работы метода?

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

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

    @Mercury13
    Программист на «си с крестами» и не только
    goto перед концом внешнего цикла.

    for(первый) {
      for(второй) {
        goto a;
      }
      a:;
    }
    Ответ написан
    Комментировать
  • Как это должно работать?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, ищите Hello World на WinAPI. Поскольку WinMain() там стандартный и немаленький, его опустили.

    Основано это на поведении Windows: она всегда пытается закрыть прогу корректно. Хорошо, закроем корректно, зато вот тебе вторая.
    Ответ написан
  • Как понять условие задачи?

    @Mercury13
    Программист на «си с крестами» и не только
    Что вы не поняли в решении: вы оптимизируете «чёрную» половинку графа, забыв, что самое малое ребро может быть в «белой».

    ДЛЯ КАЖДОЙ ВЕРШИНЫ: ук-ль на «начальника» + флаг инверсии. Если у вершины нет начальника — то указывает в null.
    ДИРЕКТОРОМ назовём вершину, у которого нет начальников. Считаем также, что у директора флаг инверсии всегда false.

    Заведём функцию getInfoNonDestructive, она возвращает структуру из двух элементов. Во-первых, это директор (никогда не null!!). Во-вторых, это цвет — XOR флагов инверсии от самóй вершины до директора.

    Функция getInfo вызовет getInfoNonDestructive, а затем проведёт ОПТИМИЗАЦИЮ СТРУКТУРЫ: ЕСЛИ вершина имеет начальника, ТО: начальник вершины := директор, флаг инверсии вершины := цвет вершины.

    СЛИЯНИЕ фирм происходит так. Директор фирмы становится подчинённым кому-то из членов другой фирмы.

    ИЗНАЧАЛЬНО для всех вершин начальник — null, флаг инверсии — false. То есть каждая вершина белая и сама себе директор.
    РЕШЕНИЕ: Отсортируем рёбра в порядке возрастания.
    Для каждого ребра…
    • Находим информацию о вершинах — концах ребра.
    • Если директор один и цвета разные — ничего не делаем.
    • Если директор один и цвет один — выводим вес этого ребра как ответ.
    • Если директора разные — сливаем фирмы. Подкручиваем флаг инверсии того директора, который исчез, так, чтобы цвета вершин — концов ребра были разные. Хотя бы так.
    VertexInfo info1 = getInfo(vertex1);
    VertexInfo info2 = getInfo(vertex2);
    if (…) {
      info1.director->superior = info2.director;
      VertexInfo info1new = getInfoNonDestructive(vertex1);
      if (info1new.color == info2.color)
        info1.director->inverseFlag = !info1.director->inverseFlag;
    }

    ВНИМАНИЕ, без оптимизации структуры сложность с «чуть более O(N)» превращается в N²! Но конкретно в этом месте важно получить инфу без разрушений — временно запрещается кого бы то ни было выводить из-под старого директора, пока не выставим ему флаг инверсии цвета.

    Если рёбер не осталось — перед нами двудольный граф, такого по условию не бывает.

    (такая структура данных, только без флага инверсии, называется, «система непересекающихся множеств»).

    ТЕОРИЯ. Начиная от самых «маленьких» рёбер, начинаем раскрашивать вершины в разные цвета. Если в какой-то момент это не удалось (цвета уже одинаковые) — выводим это ребро как ответ. Если соединяются два раскрашенных «островка» (в нашей терминологии «фирмы») — возможно, один из островков придётся инвертировать, и надо наладить инверсию так, чтобы она не захватила весь островок (судя по цифре 105, от нас ожидают сложность N log N, а не N²). Поскольку соединение кусков графа рёбрами и подсчёт компонент связности — это самая настоящая система непересекающихся множеств, я попытался приделать к этой самой СнПМ раскраску, не повышающую общую сложность (амортизированные почти что O(1) за транзакцию).

    Попробуй доказать самостоятельно, что данная система не зависит от того, в каком порядке оказались рёбра с одинаковым весом.

    И кончайте на чужом буе в рай въезжать!
    Ответ написан
  • Как линковщик производит подстановку функций из динамических библиотек?

    @Mercury13
    Программист на «си с крестами» и не только
    Это называется name mangling — как по-русски, я не знаю, но называю это «козявить имена».

    Названия foo в объектных файлах действительно не будет существовать.

    Линкер тут ни к чему, имена готовит компилятор. Потому, кстати, в межъязыковых библиотеках стараются имена не козявить.

    Чтобы функция называлась именно так, как надо, в Си++ есть ключевое слово extern "C", и часто его применяют, например, при экспорте в межъязыковой DLL, при интеграции Си-кода с Си++. Что в Ди, не знаю.
    В Си такого точно нет, как ты назвал, так и называются.

    Линкер, конечно, может каким-то образом подхватывать DLL (так работает LD), но это очень не стандартно — при переходе с LD на LLD пришлось готовить *.a для всех имеющихся DLL. Но в любом случае именами занимается компилятор.
    Ответ написан
    4 комментария
  • Почему программа на C++ не выводит результат?

    @Mercury13
    Программист на «си с крестами» и не только
    printf("%d %f", &n, &sum);
    printf("%d %f", n, sum);
    Ответ написан
  • В чем разница между методом в public и private?

    @Mercury13
    Программист на «си с крестами» и не только
    Это права доступа к методу. Относятся не к Cи++, а к ООП в целом.

    private — имеют доступ только методы самого объекта.
    protected — имеют доступ методы объекта и его потомков.
    public — кто угодно.

    Также существуют права доступа типа «не важно, что объекты станут связанным клубком; я готов к тому, что этот клубок придётся добавлять в программу целиком». В общем, когда объекты имеют доступ к private-методам друг друга.
    • В Си++ — ключевое слово friend
    • В Java — без ключевого слова (т.н. права доступа package)
    • В Паскале — по умолчанию есть доступ к private-полям и методам всех объектов в том же модуле.

    Эти особые права доступа (friend/package) оправданы, когда…
    • Издержки от клубка незначительны (например, объекты невелики и хорошо взаимосвязаны).
    • В клубок входят объект и его утилиты (например, какая-нибудь операция ++).
    Ответ написан
    Комментировать
  • Детерминирована ли реализация typeid?

    @Mercury13
    Программист на «си с крестами» и не только
    Не детерминирована.
    В зависимости от компилятора, может скомпилироваться, но не заработать правильно.
    Ответ написан
    Комментировать
  • Как решить задачу c++?

    @Mercury13
    Программист на «си с крестами» и не только
    У вас нормальное (хоть и корявое по части кода, я за такой код пинаю!) лобовое решение. Очевидно, придётся наладить какой-нибудь ускоритель, позволяющий выполнить запрос быстрее, чем за O(n).

    Моё предложение: map (ради скорости можно прикрутить собственный аллокатор типа «объектный пул», благо кол-во блоков данных ограничено сверху 100k), показывающий, например, для третьего примера картинку «1→1, 2→2, 3→3, 4→4, 5→5». После первой транзакции — «1→2, 3→3, 4→4, 5→5». Поиск в этом map’е — upper_bound минус единичка (даже поиск 1-цы укажет или на второй элемент, или за первый). Сможете наладить методику разделения и склеивания диапазонов?

    Можно и наоборот: 2→1, 3→3, 4→4, 5→5. Поиск в таком map’е — lower_bound (даже поиск 5-ки не выкинет за пределы, правильно?).
    Ответ написан