Ответы пользователя по тегу C++
  • WinAPI: Нарушение прав доступа при записи. Как исправить?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Ошибка в вызове ReadFile. Причём я говорил про эту ошибку.
    DWORD nRead;
     isSucceed = ReadFile(myfile, buffer, 10, &nRead, NULL);


    А также.
    2. Файл открывать только для чтения.
    3. Проверить myFile на корректность.
    4. Читаем 10 байтов, пишем 100?
    Ответ написан
    Комментировать
  • Как вывести результат работы функций WinAPI?

    @Mercury13
    Программист на «си с крестами» и не только
    Ваши ошибки.

    1. Это разные дескрипторы.
    FindFirstFile даёт дескриптор поиска файлов.
    А ReadFile требует дескриптор файла, который можно получить через CreateFile.

    2. Второй параметр FindFirstFile не может быть NULL. Это указатель на WIN32_FILE_DATA, в которую функция и будет кидать информацию о найденных файлах.

    3. Если вы не ищете по маске и точно хотите открыть файл, на что вам FindFirstFile? Орудуйте сразу CreateFile.

    4. Вы подключили пару излишних хедеров.

    5. Не советую вместо нулевого указателя NULL писать 0.

    6. В ReadFile два последних параметра не могут одновременно быть NULL: первый — для синхронного чтения, второй — для асинхронного.

    В общем, «курите маны». Благо, у M$ они хорошие.
    Ответ написан
    9 комментариев
  • Как перевести код из С++ в Си?

    @Mercury13
    Программист на «си с крестами» и не только
    Перед нами совершенно необъектный код, на вид тупо написанный на Си средствами Си++. Так что будет несложно.
    1. Убрать из структуры private/public.
    2. Вынести функции из структуры, явно прописав в них this:
    int BMP::Load(char FileNames[])
    →
    int BMPLoad(struct BMP* this, char FileNames[])

    3. Для старых версий Си — поднять определения всех переменных на верх функции.

    А что нам с масштабированием? — на вид написан на том же Си и ничего не требует, кроме задания этого this.
    Ответ написан
    3 комментария
  • Даны 4 последовательные точки, как узнать что образуют они параллелограмм?

    @Mercury13
    Программист на «си с крестами» и не только
    Ну разумеется, по критерию параллелограмма: диагонали пересекаются и точкой пересечения делятся пополам! На языке математики:
    x1 + x3 ≈ x2 + x4
    y1 + y3 ≈ y2 + y4
    Почему «приблизительно равно». Float в принципе неточный, совпадение приходится проверять с точностью в какой-то эпсилон. Какой эпсилон — это уже зависит от задачи.
    Ответ написан
    Комментировать
  • Как получить доступ к камере?

    @Mercury13
    Программист на «си с крестами» и не только
    Это обыкновенный IBM (разве что, возможно, с несколько кастрированным BIOS’ом), там нормальная, без RT, Windows.
    Я могу дома погонять, правда, у меня самый обычный настольник с вебкой. А так…
    doc.qt.io/qt-5/cameraoverview.html
    https://habrahabr.ru/post/148775/
    На вид их API ещё в виде беты… ну, я на работе и не могу пока разобрать.
    Ответ написан
    Комментировать
  • Как обратиться по индексу к списку C++?

    @Mercury13
    Программист на «си с крестами» и не только
    std::list — связанный список. Адреса там не обязательно соседние. Не надо с адресами работать! Надо работать именно что с итераторами — они действуют как указатели, только не на непрерывном буфере, а на списке непонятно какого устройства.

    Операцию [] не наладили намеренно: она там O(n). И если вы с такой сложностью через эту операцию наладите быструю, она будет O(n² log n). В то время как пузырёк, учитывающий специфику связного списка,— O(n²). А ведь на двусвязном списке при желании можно написать и быструю. Я писал.

    И не только я: у std::list есть свой sort: ru.cppreference.com/w/cpp/container/list/sort
    Ответ написан
    8 комментариев
  • Что такое мультисписок?

    @Mercury13
    Программист на «си с крестами» и не только
    Мультисписок имеет несколько указателей «next» и позволяет собирать несколько (до N) не связанных друг с другом списков по разным признакам, не дублируя полезной нагрузки.
    typedef enum {
      LI_A, LI_B, LI_N
    } ListIndex;
    
    enum { LEN = 40 };
    
    typedef struct {
      Entry* next[LI_N];
      char name[LEN];
    } Entry;
    
    typedef Entry* PEntry;
    PEntry heads[LI_N], tails[LI_N];    // считаем, что = NULL
    
    int isIn(ListIndex aIndex, Entry* aEntry)
    {
      return (aEntry->next[aIndex] || tails[aIndex] == aEntry);
    }
    
    void addExisting(ListIndex aIndex, Entry* aEntry)
    {
       /* Уже есть? Поскольку такой код чреват ошибками, лучше всё же проверить */
      if (isIn(aIndex, aEntry))
        return;
      if (tails[aIndex]) {
        tails[aIndex]->next = aEntry;
        tails[aIndex] = aEntry;
      } else {
        heads[aIndex] = tails[aIndex] = aEntry;
      }
    }
    
    Entry* addNew(ListIndex aIndex, char* aName)
    {
      int i;
      Entry* newEntry = (Entry*)malloc(sizeof(Entry));
      strncpy(entry->name, aName, LEN);
      entry->name[LEN-1] = '\0';
      for (i = 0; i < LI_N, ++i)
        entry->next[i] = NULL;
      addExisting(aIndex, entry);
      return entry;
    }
    
    /* closure — т.н. замыкание, передача контекста, из которого была
       вызвана функция, вызывающая callback */
    typedef void(*ListCallback)(Entry* aEntry, void* aClosure);
    
    void traverseList(ListIndex aIndex, ListCallback aCallback, void* aClosure)
    {
      Entry* entry = heads[aIndex];
      while (entry) {
        aCallback(aEntry, aClosure);
        entry = entry->next[aIndex];
      }
    }

    О замыкании можно прочитать тут: Для чего нужны замыкания в C++ и как вы их используете?
    Ответ написан
    Комментировать
  • Как редактировать бинарный файл?

    @Mercury13
    Программист на «си с крестами» и не только
    Допустим, надо перезаписать i-й полёт.
    Надо перескочить на i*sizeof(…), и там читать-писать. То есть
    if (strcmp(flight_d[i].destination, edit) == 0)
                {
                       flight_d[i] = …;
                       file.open(…);
                       file.seekg(i * sizeof(…));
                       file.write(reinterpret_cast<const char*>(&flight_d[i]),
                                             sizeof(Flight_Details));
                       break;
                }


    Да, и вы путаете глобальную переменную flight_d и локальную flight.
    Ответ написан
  • Как узнать время выполнения сортировки в C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Используйте либо time.h из Си, либо std::chrono из Си++11. Вот пример по второму.
    #include <iostream>
    #include <chrono>
    
    int main()
    {
        using Time = std::chrono::time_point<std::chrono::high_resolution_clock>;
        using Diff = std::chrono::milliseconds;
    
        Time t1 = std::chrono::high_resolution_clock::now();
        int i;
        std::cin >> i;
        Time t2 = std::chrono::high_resolution_clock::now();
        Diff diff = std::chrono::duration_cast<Diff>(t2 - t1);
        std::cout << diff.count() << " ms" << std::endl;
        return 0;
    }
    Ответ написан
    Комментировать
  • Как вытянуть одномерный массив Arr[j] с функции min и отсортировать его в функции quicksort?

    @Mercury13
    Программист на «си с крестами» и не только
    double* min(double **Arr, int SizeArr) {
       // Всё оставь как есть, убери вывод   
       return MinArr;
    }

    Ну и не забудь уничтожить результат функции min где-то ниже по коду. «Си с крестами» сам ничего созданного через new не уничтожит.
    Ответ написан
    1 комментарий
  • Почему деструктор выполняется раньше конструктора копирования?

    @Mercury13
    Программист на «си с крестами» и не только
    По крайней мере у меня G++ выдал предупреждение вот тут:
    List<size_t>& newList(size_t a) {
        	List<size_t> result;
        	result.pushBack(a);
        	return result;
        }

    C:\TestApps\ListTest\main.cpp | 118 | warning: reference to local variable 'result' returned [-Wreturn-local-addr]
    Понятно?

    Что изменить…
    1. Изменить сигнатуру на…
    List<size_t> newList(size_t a) {
    2. Поработать с временными ссылками Си++11. Добавить две функции.
    List(List<T>&& other);
    List<T>& operator = (List<T>&& other);

    Два амперсанда — это не ссылка на ссылку (понятие «ссылка» идемпотентно), а новая вещь Си++11 — ссылка на временный объект. Она говорит: объект идёт на заклание, из него можно выпотрошить все данные.
    3. Насчёт обычной операции присваивания — её можно или реализовать, или =delete (тоже нововведение Си++11).
    4. UPD. Проглючил, но да, верно. Обычный конструктор копирования должен иметь параметр const!
    Ответ написан
    Комментировать
  • Как синхронизируются потоки на низком уровне?

    @Mercury13
    Программист на «си с крестами» и не только
    Этого мало.
    Первое. Нужны особые операции, которые гарантированно выполняются атомарно. Например (из исходников Delphi)
    function InterlockedAdd(var Addend: Integer; Increment: Integer): Integer;
    asm
          MOV   ECX,EAX
          MOV   EAX,EDX
     LOCK XADD  [ECX],EAX
          ADD   EAX,EDX
    end;

    Здесь префикс LOCK (блокирование шины) и даёт атомарность. Также используют операцию XCHG (exchange) — единственная атомарная без префикса LOCK.

    На основе этого можно устроить объект, который называется spinlock. Крутим цикл, пока система не скажет: свободно. Из Википедии.
    mov eax, spinlock_address
    mov ebx, SPINLOCK_BUSY
    
    wait_cycle:
    xchg [eax], ebx  ; xchg - единственная инструкция, являющаяся атомарной без префикса lock
    cmp ebx, SPINLOCK_FREE
    jnz wait_cycle
    
    ; < критическая секция захвачена данным потоком, здесь идёт работа с разделяемым ресурсом >
    
    mov eax, spinlock_address
    mov ebx, SPINLOCK_FREE
    xchg [eax], ebx  ; используется xchg для атомарного изменения
    ; последние 3 инструкции лучше заменить на mov [spinlock_address], SPINLOCK_FREE -
    ; это увеличит скорость за счёт отсутствия лишней блокировки шины, а mov и так выполнится атомарно
    ; (но только если адрес spinlock_address выровнен по границе двойного слова)


    От спинлока до настоящего мьютекса остаётся один небольшой шаг. Спинлок потребляет ресурс процессора, не производя полезной работы. После того, как спинлок проработал несколько микросекунд и не освободился, мы говорим: не судьба — и передаём работу другому процессу. Надеюсь, вы в своей мини-ОС как-то научились переключать процессы.

    В однопроцессорном ядре никаких спинлоков нет. Если надо захватить ресурс, а он чей-то — сразу отдаём управление другому.

    UPD1. Почему не сразу отдавать работу другому процессу. Хороший тон — защищать мьютексом не системные вызовы (которые действительно долги) а какие-нибудь структуры данных вроде связных списков и атомарных struct. Так что вероятность, что объект просидит занятым долго, крайне мала. В настоящем мьютексе есть очередь с приоритетом, которая защищается, как ни странно, спинлоком. И этого достаточно.
    Ответ написан
    2 комментария
  • Как работает генератор случайных чисел?

    @Mercury13
    Программист на «си с крестами» и не только
    Рассказываю на пальцах.
    Компьютер запомнил число (или кучу чисел), которое называется «случайная затравка» (random seed).
    По команде «сгенерируй случайное число» он проводит два алгоритма.

    1. Собственно генератор случайных чисел — преобразование seed → seed.
    Например: seed := (37·seed + 234) mod 997.
    (знаком :=, как в Паскале, я обозначил «переприсвоить»)

    2. Интерпретация результатов: seed → Y*.
    Например, y = seed/997.
    Y — это [0…1), {1…6} или любое другое желаемое множество.
    Y* — множество конечных последовательностей: каждый бросок генератора может не дать ни одного числа (и потребуется переброс), одно число, два числа… Например, наиболее известный генератор нормально распределённых чисел каждым броском даёт или ноль чисел (т.е. нужен переброс), или сразу два.

    Затравку надо инициализировать чем-то действительно случайным, и для этого используют таймер, счётчик тактов и прочие труднопредсказуемые места. А ещё можно запомнить затравку и снова повторить ту же последовательность чисел (раньше это использовали для повторов и мультиплеера в играх).

    Если же нужны настоящие случайные числа, да в большом количестве — это откровенно тяжело. В ход идут…
    • таймеры и счётчики команд — ну, это понятно;
    • шум в звуковой плате;
    • задержки ввода с клавиатуры и мыши;
    • аппаратные датчики случайных чисел на диодном шуме, применяемые в некоторых процессорах.
    MacOS, например, этим добром не пользуется; и в dev/random, и в dev/urandom идёт один и тот же криптостойкий псевдослучайных генератор Ярроу.
    Ответ написан
    Комментировать
  • Как сравнивать значения строки в структуре на языке С++?

    @Mercury13
    Программист на «си с крестами» и не только
    1. У вас неверное условие (z[i].birth >= ageyoungest).
    2. Никакой защиты от переполнения буфера в scanf.
    3. Идентификатор birth реально означает возраст. Плохо.
    4. Неверное условие
    if (z[i].education == "master" || z[i].education == "specialist" || z[i].education == "bachelor")
    . Для массивов это просто сравнение адреса массива с адресом вкомпилированной в программу строчки, что автоматически даёт false. Используйте str(n)cmp.
    5. Излишнее условие
    else if (z[i].education != "master" || z[i].education != "specialist" || z[i].education != "bachelor")
    . Оно автоматически выполнено.
    6. Отсутствует delete[] employees;
    Ответ написан
    Комментировать
  • В чем проблема файла std lib facilities.h?

    @Mercury13
    Программист на «си с крестами» и не только
    Проблема в подключённом к нему файле hash_list или hash_map (они никогда не были стандартом Си++, но по факту их многие реализовывали, с двумя разными стандартами — один от SGI, второй переименованный вошёл в STL).
    Переименуйте в unordered_list, unordered_map. И надейтесь, что третий и далее параметры шаблонов не использовались.

    Существуют версии этого файла, откорректированные под C++11.

    А можно заглушить ошибку, добавив в «#defines» проекта _SILENCE_STDEXT_HASH_DEPRECATION_WARNINGS. И будьте готовы, что в один прекрасный день вы обновите компилятор и хватитесь этого файла.
    Ответ написан
    Комментировать
  • Почему появляется ошибка при выделении памяти?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Чему равняется nChilds?
    2. Сам-то CalculateCountOfObjectsInside() в порядке?
    3. Случайно наша система не ходит по каталогам «.» и «..»?
    Ответ написан
    3 комментария
  • Что изучить C или C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Информационная безопасность требует от вас понимать, что такое эксплойт. Потому нужны оба языка. Может, не очень глубоко, но какой-то код надо писать на том и на другом.
    Дело в том, что «няшная сишка» стала отличным полигоном для эксплойтов, да и низкоуровневые библиотеки пишут часто на ней (для компактности). А на Си++ пишут современный софт.
    Раз вы на ПэХаПэ, вы не понимаете, что такое указатель, и потому лучше начать с Си++. Просто потому, что как-то можно программировать без указателей, а понять, что это за чёрт указатель — дело наживное.
    Ответ написан
  • Как создать связный список?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Виртуальный деструктор тут нужен — ведь в списке будут вперемешку элементы разных классов.
    2. Не видны два компонента, которые и делают список связным — указатель на следующий элемент (test* next) и указатель на голову (test* head = NULL).
    3. В попытке скрыть реальную жизненную задачу — ведь СС не вещь в себе, а решает какую-то задачу вроде «держать список объектов в игре» — вы слишком уж напереименовывались.
    Ответ написан
    4 комментария
  • Есть ли игры в открытом мире с круглой землей (картой)?

    @Mercury13
    Программист на «си с крестами» и не только
    В первую очередь авиасимуляторы. Знаю, что из-за масштабов Земли им приходится справляться с ошибками float: если Земля 12000 км в поперечнике, то единица младшего разряда — полметра.
    Первый X-COM имел круглую землю, но полёты были по локсодроме. А вот в опенсорсном ремейке 2014 года полёты уже по большому кругу.
    Симуляторы бога от Питера Молиньё: Populous, Black and White. Возможно, и другие симуляторы богов (например, Spore — не проверял).

    Я говорю именно про шарообразную карту, а не трубу/тор.

    А так — я бы предостерёг от шарообразной земли с открытым миром. 1) Расстояния (глобальная карта с ускоренным временем или без времени не в счёт). 2) Навигация по миру (в том числе понятие «север»), проекция миникарты. 3) В какой-то момент нужно закругляться и выкатывать игру, а в какой-то — выдавать аддон. Тяжеловато будет. Кстати, во всех упомянутых играх мир или замкнутый, или намного больше, чем одна планета.

    P.S. Моё определение открытого мира: игра, дающая относительную свободу действий и передвижения, но локальный участок, где орудует игрок/группа, намного меньше мира. В замкнутом мире, наоборот, участник орудует практически по всему «миру», оперативно переходя с одного участка на другой. Есть и пограничные случаи: огромное побережье нового Hitman — открытый мир или замкнутый?
    Ответ написан
    1 комментарий
  • Почему на 4-х ядерном процессоре происходит эмуляция 12-и ядерного?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Такую работу со счётчиком threadEnd лучше делать через std::atomic.
    2. В вашем процессоре два гипертредированных ядра, 4 потока.
    3. Главный поток ждёт-крутится. «1 поток» — это работают ДВА потока (не забывайте, главный просто крутится). «2 потока» — это ТРИ потока, два настоящих ядра и одно виртуальное — потому результаты не вдвое ниже. Так что вижу локальный минимум на трёх потоках, это верно. У меня на рабочем 8-поточном процессоре, как и полагается, даёт минимум на семи потоках.
    4. Условие if (natur > 0) кажется излишним.
    5. Вижу большой разброс результатов. То ли таймер недостаточно точный, то ли компьютер загружен кучей посторонней работы — таким результатам доверять не стоит.
    Ответ написан
    2 комментария