Ответы пользователя по тегу C++
  • Как решить ошибку LNK2019?

    @Mercury13
    Программист на «си с крестами» и не только
    Судя по всему, эти функции в библиотеках OpenGL. Надо включить в проект opengl32.lib (и, возможно, glu32.lib).
    Ответ написан
  • Как передать вывод?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Чтобы получить ссылку на CMD.EXE, прочитайте переменную окружения COMSPEC.
    2. Не используйте ShellExecute для запуска того, что гарантированно программа, для этого есть CreateProcess.
    3. Да, и не забывайте, что ShellExecute заканчивает работу, когда программа пошла на исполнение. Если нужен результат исполнения — всё тот же CreateProcess + ввод-вывод через каналы + WaitForSingleObject.
    Ответ написан
    Комментировать
  • Принцип работы анимации?

    @Mercury13
    Программист на «си с крестами» и не только
    time — это длительность такта (в игре, очевидно, не просто переменный FPS, но и переменная тактовая частота). Писал такое, правда, не в платформере, а в гоночке.

    rect.left — это точное решение дифура left′ = dx (движение с постоянной скоростью). Очевидно, dx где-то устанавливается по управлению.

    rect.top и dy — это приближённое решение дифура top′′ = 0,005, если снят флаг onGround (полёт под действием силы тяжести). Здесь 0,005 — это ускорение силы тяжести, ось Y направлена вниз. Дифур второго порядка, преобразуется в систему top' = dy, dy′ = 0,005, и то, что в первом случае было точным, здесь приближённое, но приемлемое для игр.

    currentFrame просто прокручивается, чтобы 6-кадровая анимация прошла за 1200 тактов, независимо от частоты. Здесь 1200 = 6 / 0,005.

    Заметьте, dx и dy проходят по разным трактам данных: один — состояние управления, второй — состояние физики персонажа. К тому же что делает dx = 0 и где он ставится не в 0, чтобы не зависеть от частоты автоповтора клавы — непонятно. И много магических констант. Говнокод.

    UPD. Прямые ответы на ваши вопросы.
    1) 6-кадровая анимация, но тут одно из двух. Либо из-за огромного цикла (1200 тактов) явно анимируются не ноги. А может, афтар гонит такты с предельной частотой и потому 1200 тактов действительно пройдут за секунду-две, но тогда это слишком уж явная привязка к скорости компьютера;
    2) в зависимости от номера кадра выбираем тот или иной спрайт на атласе;
    3) dy — скорость, и чтобы откорректировать положение (rect.y), надо прибавить к нему скорость·время.

    UPD2. Кроме того, непонятно, почему в коде анимации нет бега в разные стороны. Хотя из-за крайне простой физики есть подозрение, что жанр — бесконечная бегалка.
    Ответ написан
    3 комментария
  • Нету вывода из массива с указателями из структуры с++?

    @Mercury13
    Программист на «си с крестами» и не только
    Первое и главное. Удивительно, что у вас программа заработала, ведь text.sentences не инициализировано. У меня вылет.

    Ну и извечная ошибка начинающего «плюсовика»: память выделяется, непонятно, кто чем владеет, и, разумеется, память «течёт». Для чего, извините, в Си++ сделали инкапсуляцию, конструкторы и деструкторы?
    Ответ написан
    Комментировать
  • Почему компилятор не видит конструктор?

    @Mercury13
    Программист на «си с крестами» и не только
    Нет, дело не в этом. Линкер не может найти среди OBJ-файлов конструктор MyDb::MyDb. Очевидно, mydb.cpp не скомпилировался или не подключён.
    1) Убедиться, что mydb.cpp включён в проект. 2) Build → Run Qmake.

    Гуглите понятие «единица трансляции» и что делает линкер.
    Ответ написан
    1 комментарий
  • Какое время жизни объекта в std::unique_ptr?

    @Mercury13
    Программист на «си с крестами» и не только
    Уничтоженный unique_ptr уничтожит ваш объект.

    «Уничтожит» — это значит, вызовет деструктор и сделает память доступной менеджеру памяти. Теперь другие указатели, которые смотрят на этот объект, будут «висячими», и при их разыменовании программа может сделать ЧТО УГОДНО.

    А теперь посмотрим, что именно ей угодно. Ваша функция foo() невиртуальная и не имеет дела с полями, ей нужен только this (указатель на объект), который даже не разыменовывается. Она в принципе не может вылететь, даже если десять раз занулить этот объект!

    То, что вы хотите сделать — это семантика std::shared_ptr/weak_ptr.
    std::shared_ptr<ttt> sh1 = std::make_shared<ttt>();
    std::weak_ptr<ttt> we = sh1;
    {
      std::shared_ptr<ttt> sh2 = sh1;
      sh1 = nullptr;
    }
    std::cout << we.expired();  // должно быть true


    UPD. Вот для таких, как ты, и ввели в C++14 функцию std::make_unique, по аналогии с std::make_shared. Просто чтобы было меньше таких ошибок.
    Ответ написан
    Комментировать
  • Разделение строки из символом в массив?

    @Mercury13
    Программист на «си с крестами» и не только
    // считать строчку
    std::string s;
    std::getline(std::cin, s);
    // …и разбираем её потихоньку через поток-строку
    std::istringstream is(s);
    int i;
    std::vector<int> v;
    while (is >> i)
      v.push_back(i);
    Ответ написан
    Комментировать
  • Как выделяется память в классах?

    @Mercury13
    Программист на «си с крестами» и не только
    Examp ex = new Examp ();
    Неверный код, надо Examp* ex = new Examp;

    В случае статического определения (Examp ex2;) — в той памяти, где обычно располагаются объекты. То есть:
    • Если это поле объекта — то в теле объекта, которое может быть где угодно (куча, сегмент данных, стек).
    • Если static/глобальный — то в сегменте данных.
    • Если локальный — в стеке. Конкретно тут локальная переменная, и она будет в стеке.

    В случае динамического определения (Examp* ex = new Examp;) — в «куче».
    В этом примере, кроме операции new, которая заводит объект в куче, видим ещё и указатель, который располагается «там, где обычно» — в теле объекта, сегменте данных или стеке.
    Ответ написан
    Комментировать
  • Bit shift (swap bytes) как это в действительности работает?

    @Mercury13
    Программист на «си с крестами» и не только
    Банально сначала надо unsigned value = 0;
    Вы вроде делаете полный порядок, но начальное присваивание неверное.

    UPD. Проверил в деле — так и есть.
    Ответ написан
    1 комментарий
  • Как проверить существует ли указатель или был удален?

    @Mercury13
    Программист на «си с крестами» и не только
    В Си++11 для этого есть два класса: std::shared_ptr и std::weak_ptr.

    Первый служит для того, чтобы несколько указателей «смотрели» на один объект, и при исчезновении ВСЕХ объект автоматически исчезал.

    Второй «смотрит» на тот же объект, что управляется shared_ptr’ами, но не мешает объекту удаляться. Его можно преобразовать в shared_ptr и тогда уж посмотреть, исчез объект или нет.

    UPD. Вы делаете свой shared_ptr. Тогда, если shared_ptr не NULL — значит, считаем, что объект действительно там есть! А если кто-то удалил своими силами — значит либо shared_ptr глючный, либо кто-то удалил объект в объод семантики умных указателей.

    Кроме того, код по ссылке странный. if (ref_count == 0) — это мы сравниваем указатель с NULL! Написано «переписываем оператор равенства» — по факту переписываем операцию присваивания…
    Ответ написан
    9 комментариев
  • Почему не работает (с++)?

    @Mercury13
    Программист на «си с крестами» и не только
    Надо long long n;
    Дело в банальном переполнении, но profesor08 дал явно неверный ответ.
    Ответ написан
    1 комментарий
  • Что не даёт на C++ писать кроссплатформенные приложения?

    @Mercury13
    Программист на «си с крестами» и не только
    Си — язык очень близкий к железу. Когда мы пишем на Java, мы пишем код под Java-машину. На Си мы пишем код под процессор. Главная проблема, связанная с любыми подобными языками,— отсутствие понимания целевых ОС программистами и тестирования — тестерами. Это нужно, ибо абстрагирование от машины очень тонкое.

    Поскольку перед нами очень тонкая прослойка, абстрагирующая от машины, приходится принимать меры, чтобы код переносился с машины на машину (даже с x86 на x64). Отлично это описано в блоге PVS-Studio.

    В Windows и Linux машина-то одна и та же, но конкретно в Си++ к этому добавляется устаревшая по некоторым вещам стандартная библиотека. Примеры…
    • Поддержка юникодных имён файлов пока не кроссплатформенная.
    • Унаследоваться от std::ostream — ужос такой ещё.
    • Как сконвертировать текст в UTF-8? Загугли и посмотри, какой там вавилон из шаблонов.
    Отсюда огромное количество производителезависимых расширений, чужих библиотек, повторяющих стандартную, и прочее. Важный пункт тут: чужих библиотек, повторяющих стандартную. Если у тебя строки нестандартные и файлы нестандартные — какая тут кроссплатформенность?
    Ответ написан
    Комментировать
  • Наследование оператора присваивания (=), как это сделать?

    @Mercury13
    Программист на «си с крестами» и не только
    Почему не прописывается автоматически? А потому что в Test2 будет больше полей, и никто, кроме вас, программиста, не знает, что с ними делать.

    Но никто не мешает самому написать операцию =, например.
    class Test2 : public Test
    {
    private:
      typedef Test Super;
    public:
      Test2& operator = (const Test& x);
    };
    
    Test2& Test2::operator = (const Test& x)
    {
      Super::operator = (x);
      // придумай, что сделать с недостающими полями
      return *this;
    }
    Ответ написан
    3 комментария
  • В чем суть WinApi?

    @Mercury13
    Программист на «си с крестами» и не только
    Windows API — это самый низкоуровневый интерфейс Windows, доступный прикладному программисту — в том плане, что он на долгосрочной поддержке и не изменится с Windows 11.

    Поверх Windows API работают все BOOST и STL.

    Пример: читать файл в 130 мегабайт по одному байту. Добавив асинхронного чтения через OVERLAPPED, я сумел это сделать менее чем за 2 секунды (это был поток общего назначения с виртуальными read(), write() и seek(); специализированный прикладной буфер даст ещё выигрыша, но и это хорошо). То же самое через FILE* — не дождался.

    Пример второй, всё те же файлы. Дело в том, что Excel захватывает свои файлы на всё время, пока он открыт. Закрывать? — плохой выбор. Добавив один флажок в CreateFile, документы всё-таки стало возможным открывать при работающем Excel.
    Ответ написан
    2 комментария
  • Как передать вектор в функцию?

    @Mercury13
    Программист на «си с крестами» и не только
    Раз мы изменяем наш вектор — то по неконстантной сцылке.

    void add (int n, std::vector<int>& vec){
        vec.push_back(n);
    }
    
    std::vector <int> myVec;
    add(5, myVec);
    Ответ написан
    Комментировать
  • Какие есть библиотеки для работы с RAW изображениями?

    @Mercury13
    Программист на «си с крестами» и не только
    1. RAW есть несколько штук: RAW CHDK, CRW Canon, NEF Nikon, платформонезависимый, но мало кем используемый DNG…
    2. Если у вас графической редактор общего назначения, крайне не советую. Для «проявки» RAW нужен особый инструментарий, которого в редакторе общего назначения нет. Плюс куча очень умных вещей, вроде дебайеризатора и шумодава. Оставьте это лайтрумам!
    XnView, допустим, смотрит, но получается дрянь — в CHDK RAW все эти дебайеризации и кривые яркости сделаны как попало, и шумодава никакого. Хотя формат, признаться, редкий, Adobe его берёт только через промежуточный платформонезависимый DNG.
    В Nikon NEF, по-видимому, смотрит превьюху: нет никакой разницы с Medium JPEG — любая программа проявки хоть где-то да проявит свой характер. Впрочем, одна есть: адовы искажения, присущие пережатому JPEG. К тому же снял в ч/б — он и вывел ч/б, в отличие от DxO, которому надо ещё указать, что формат с матрицы надо ещё в ч/б конвертнуть.
    (Других фотоаппаратов у меня не было.)
    Но XnView — просмотрщик, ему позволительно, он должен поддерживать как можно больше форматов и показывать их, пускай как попало.
    Фотошоп открывает, но там этот инструментарий в каком-то виде есть, и под капотом нечто очень умное, на голову превосходящее внутрикамерную проявку мыльниц Canon (зеркалку Nikon не проверял). Но и они собрали все свои наработки по RAW и сделали отдельную программу специально для проявки цифрофото — Lightroom.
    3. Обратно в RAW в принципе не стоит. Это файл с матрицы фотоаппарата, и точка. Вы что, хотите снимки подделывать?

    UPD. Ясно, вы решили именно проявлять несколько кадров в один HDR…
    Тогда задача библиотеки — дебайеризовать, возможно, подавить шум, И ВСЁ. Вам нужны картинки в ЛИНЕЙНОМ цветовом пространстве с 16-ю битами на канал. Обычная проявка в JPEG (BMP, TIFF) НЕ КАТИТ, у них по умолчанию ГАММА-СКОРРЕКТИРОВАННОЕ пространство и единица около нуля не равна единице около 255. Скажем так: на экране, чтобы выделялось на чёрном фоне, надо осветлять почти на 60 единиц, на белом — затемнять на 16.

    Остальную магию вы уж как-то сами проведите. 1) Подправьте искажения объектива (как геометрические, так и цветовые). 2) Склейте три кадра в один с дробным цветовым пространством. 3) Придумайте, как всё это чудо свести в узкий диапазон экрана. 4) Наладить все эти гамма-коррекции и прочие кривые. 4) И только тогда преобразовать в целое [0…255].
    Ответ написан
    2 комментария
  • Не могу найти ошибку в использовании long double в C?

    @Mercury13
    Программист на «си с крестами» и не только
    У меня всё сработало. Может, зависит от библиотеки Си? Какой компилятор?

    UPD. Сработало на MinGW.
    Ответ написан
    1 комментарий
  • Почему меняется выходное значение после нескольких запусков программы?

    @Mercury13
    Программист на «си с крестами» и не только
    Компилятор какой используете? У меня на MinGW всё постоянно — и постоянно не дробная часть. Есть две возможные причины нестабильного поведения.
    1. Флаги сопроцессора — какая-то библиотека Си их не выставляет в постоянное значение.
    2. Неопределённое поведение (uint32_t)var в предпоследней строке. Число-то >1016, а uint32 — это 4·109.

    Тут вы множите число на 10, пока оно не станет целым. Если оно не точный double (а оно не точный), получается ситуёвина, когда младшие биты зависят от флагов сопроцессора, и неизвестно, сколько итераций проработает программа. В любом случае крайне мала вероятность, что будет нечто умещающееся в uint32_t. Таким образом, есть такие варианты обойти проблему.
    1) Умножить сразу на 1e8, а затем обрезать нули.
    2) Сконвертировать в uint64_t.

    Преобразование в uint64_t даёт постоянные 28800000000000024.
    Умножение на 1e8 (число подобрано такое, чтобы в uint32_t вмещалось)
    var *= 1e8;
        number = (uint64_t)var;
    
        while (number % 10 == 0)
            number /= 10;

    даёт 288.

    UPD. Сам я для преобразования дробного в строку в коммерческой проге использую собственную функцию, основанную на GRISU. Там есть много функций наподобие: точность 7 знаков, но если число <1010 — выводим его как целое, с 9-ю знаками.
    Ответ написан
    Комментировать
  • Почему код не работает C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Этим переменным не присваивали начального значения и в них могло оказаться что угодно.

    Переводите с английского!
    Ответ написан
    8 комментариев
  • Как реализовать сумму дробей?

    @Mercury13
    Программист на «си с крестами» и не только
    Заводим структуру-сумматор. Изначально она 0/1. Что-то типа
    typedef struct {
      int num, den;
    } Fraction;
    
    …
    
    Fraction sum = { 0, 1 };

    Дальше пишу псевдокодом, НОД и НОК разберись, как реализовать самому.
    для каждой очередной дроби
      ввести(дробь)
      новыйЗнам = НОК(сумматор.знам, дробь.знам)
      множСумм = новыйЗнам / сумматор.знам
      множДробь = новыйЗнам / дробь.знам
      новыйЧисл = сумматор.числ × множСумм + дробь.числ × множДробь
      сокрНод = НОД(новыйЧисл, новыйЗнам)
      сумматор.числ = новыйЧисл/сокрНод
      сумматор.знам = новыйЗнам/сокрНод

    Можно и оптимизировать, но тогда нужна хитрая разновидность алгоритма Евклида; в учебных целях не стоит.

    И ещё. Одна из известных ошибок в написании НОК — произведение аргументов не влезает в свой тип, а НОК влезает. Поймёшь, как в такой ситуёвине избавиться от переполнения?
    Ответ написан
    Комментировать