Ответы пользователя по тегу C++
  • Как решить данную задачу на двумерные массивы c++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    int sum = 0;
    int cnt = 0;
    for (int dx = -1; dx <= 1; ++dx) {
      for (int dy = -1; dy <= 1; ++dy) {
        if (dx == 0 && dy == 0) continue;
        int nx = i + dx;
        int ny = j + dy;
        if (nx < 0 || nx >= N || ny < 0 || ny >= M) continue;
        sum += A[nx][ny];
        ++cnt;
      }
    }
    B[i][j] = cnt == 0 ? 0 : sum / cnt;
    Ответ написан
    Комментировать
  • Что не так с кодом, проверяющим логическую схему?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Во-первых, у вас цикл от 0 до 32 включительно. Т.е. вы на последней, 33-ей итерации пытаетесь преобразовать 0b100000 в bitset, фактически, второй раз учитывая вариант со всеми нолями. Вот почему вы получаете 33 а не 32.

    Во-вторых, у вас ошибка с тем, что вы из bitmask берете биты, которые есть числа 0 и 1 и проводите над ними битовые операции, а не логические. И это у вас там 32-битные числа же! Для | и & оно еще совпадает с вашими ожиданиями, а вот ~ обращает ВСЕ 32 бита числа.

    Поэтому ~(bitset[E] | bOrD) всегда выдаст или -1 или -2. Вы потом это пропустите через or, получите опять же -1 или -2 и в конце преобразуете это в bool. И вот тут-то оно всегда и станет true.

    Чтобы это исправить, или используйте логические операции (||, &&, !), или вместо ~x используйте x^1, или в самом конце возвращайте результат с &1, чтобы значения остальных бит ни на что не влияли.
    Ответ написан
    5 комментариев
  • Правильно ли понимаю работу ссылок в С++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это называется передача по ссылке/передача по значению. С амперсантом, передается ссылка на переменную. Иначе - копия значения переменной. Если вы будете менять копию значения, ничего вне функции не изменится, ведь вы копию меняете. А если будете менять значение ссылки, вы будете менять значение той же самой переменной.
    Ответ написан
    Комментировать
  • Почему нельзя использовать std::function как аргумет шаблонной функции?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Потому что лямбда не ялвяется std::function. Компилятор, вообще говоря, может лямбду привести к типу std::function, но не в вашем случае. Вам надо, например, самим преобразовать лямбду в std::function:
    std::function<bool(int, int)> comp = [](int left, int right)
      {
        return left < right;
      };
      Sort(vec, comp);


    Сам компилятор тут это сделать не может, потому что ему тип к которму приводить-то неизвестен - он зависит от параметра шаблона T.

    Можно, еще, например, указать компилятору параметры шаблона, тогда все скомпилируется:
    Sort<int>(vec, [](int left, int right)
      {
        return left < right;
      });


    Но лучший вариант - не использовать std::function в шаблоне. Просто используйте какой-то typename U, у которого вы продполагаете существует operator(int, int). Если туда передать не function и не лябмду, оно не скомпилится:

    template <typename T, typename U>
    void Sort(std::vector<T>& vector, U comparison) {
        // Используете comparison, как-будто это std::function:
        if (comparison(1, 1)) return;
    };
    
    
    int main()
    {
      std::vector<int> vec = { 1, 2, 3, 4, 5, 7, 6, 9 ,8 };
    
      Sort(vec, [](int left, int right) -> bool
      {
        return left < right;
      });
        return 0;
    }
    Ответ написан
    Комментировать
  • Почему умножение матрицы 8x8 медленнее чем 10x10?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Скорее всего тут дело в кеше процессора. После первых запусков так получилось, что данные оказались в кеше.

    Вообще, писать бенчмарки - очень сложно. Надо сначала прогонять тест несколько раз и отбрасывать результаты, а уже потом мерять. Надо быть очень внимательным, если вы запускакте разные тесты в одной программе подряд: результаты работы одного теста могут повлиять на остальные.

    Ну и главное, выполнять такое короткое действие всего один раз - это вообще моветон. Надо выполнить его сотню тысяч раз и потом общее время делить на количество запусков. Иначе вы меряете случайный шум в основном. Может тут вам просто все время (не)везет и вот так третий тест оказывается быстрее остальных.
    Ответ написан
    3 комментария
  • Почему недоступны приватные поля для дружественного метода?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    А есть вообще такая вещь, как дружественный метод в C++? Я вот тут что-то не вижу такого варианта.

    Вот дружественные функции там есть, да.

    И в вашем коде компилятор видит, что есть какая-то функция TakeApple в namespace Human. Метод класса Human он тут не замечает вообще. Ну и там, понятное дело, нет никакого доступа к приватным членам класса Apple.

    Вам надо или помечать дружественным весь класс Human, или выносить ваш код в отдельную функцию, которая будет дружественная обоим классам.
    Ответ написан
    3 комментария
  • Где ошибка в коде?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Проблема в том, что strtok нельзя вот так использовать вложенно. Вы когда разбиваете строку по пробелам, вы ломаете состояние доя разбития по строкам. Выделите сначала все строки.

    Но вообще, тут не надо никаких strtok. Нельзя строки сразу читать через scanf, например? А вообще, лучше читать число и символ. И там в зависимостм от символа или начинать новую строку, или нет.
    Ответ написан
    Комментировать
  • Графическая библиотека для C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Судя по всему, вы про винду спрашиваете. Надо использовать всякие виндовые апи. Помимо GDI+ есть возможность работы через DirectX (c Win8) и WindowsGraphicsCapture (с Win10). С этим можно получать скриншот в текстурах. Потом можно прям на GPU их с шаблонами сравнивать, что будет на порядки быстрее работы с отдельными пикселями.
    Ответ написан
    2 комментария
  • Как реализовать побитовый сдвиг чисел, которые записаны как строки ( длинные числа хранятся в строках)?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Из комментариев понятно, что это вы так пытаетесь умножение двух длинных чисел через сдвиги реализовывать. Соответственно, у вас сдвиги тоже длинные.

    Можно сдвигать не двоичные цифры, а десятичные. Или вообще любые. Тогда помимо сдвига еще появляется умножение на цифру. Такой сдвиг в строке из цифр - это просто сдвиг всей строки на нужное количество позиций. Саму сдвинутую строку вам не надо и получать, в общем-то.

    Основной цикл будет вроде
    for (int i = 0; i < a.length(); ++i) {
      for (int j = 0; j < b.length(); ++j) {
         c[i+j] += a[i] * b[j];
      }
    }


    В этом коде i+ - это и есть сдвиг. a[i] - это цифра на которую приходится домножать. а b[j] - это собственно само сдвигаемое и прикладываемое число.
    Ответ написан
    Комментировать
  • Как сделать ограничение максимума и минимума в генерации случайных чисел с помощью строк?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Во-первых, дополните минимум нулями слева, чтобы две строки были одинаковой длины.

    Потом генерируйте посимвольно, считая, какие значения текущая цифра может принимать. Смотрите, если где-то вы сгенерируете цифру меньше maximum, то дальше может быть вообще что угодно. Ваше сгенеренное число уже меньше максимума. Так же с минимумом. Поэтому, поддерживайте 2 флага: "сгенрированная строка уже меньше максимума" и "сгенерированная строка уже больше минимума". Каждый следующий символ не должен превосходить цифру в максимуме, если не первый флаг. Также он не должен быть меньше минимума, если не второй флаг.

    Что-то вроде этого:
    bool smaller_than_max = false;
    bool bigger_than_min = false;
    for (int i = 0; i < n; ++i) {
       int left = bigger_than_min ? '0' : minimum[i];
       int right = smaller_than_max ? '9' : maximum[i];
       answer[i] = left + rand() % (right - left + 1);
       bigger_than_min |= answer[i] > minimum[i];
       smaller_than_max |= answer[i] < maximum[i];
    }


    Edit: тут все возможные числа не будут равновероятны. Чтобы они были равновероятны придется хорошенько поизвращаться.
    Ответ написан
    Комментировать
  • Знает ли кто-то системную DLL, которая не фиксирует себя в памяти при загрузке?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вряд ли тут какие-то хитрые методы остаться в памяти тут используются. Просто библиотека приложением итак используется. LoadLibrary лишь увеличивает счетчик использований, FreeLibrary просто уменьшает его, и ничего не загружается/выгружается. Попробуйте найти какую-то dll-ку, которая не выводится в списке в начале.
    Ответ написан
    1 комментарий
  • Как хранятся многомерные массивы в памяти?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Зависит от типа массива.
    int **a;
    // или vector<vector<int>> a;
    a[10][7];


    Тут происходит 2 разименовывания указателя. Массив в памяти хранится строчками. Каждая строка может быть где угодно. При этом дополнительно хранится массив указателей на строки (длиной с длину столбца). Поэтому такой массив занимает в памяти M*(sizeof(int*))+M*N*sizeof(int). Чуть сложнее для vector, но идея такая же.

    int a[10][3];
    a[4][5];


    Тут массив, хоть и многомерный, но фиксированного размера. Поэтому он хранится одним блоком. Компилятор знает длины всех строк и сразу вычисляет адрес конкретного элемента - сдвигаясь на (длину строки)*(номер строки)+(номер столбца). Он занимает N*M*sizeof(int).

    Сравните ассемблерный код.

    Кстати, именно поэтому вы не можете преобразовать int[4][5] к int**. И такой массив при передаче в функцию надо передавать по типу int[][5] (можно опустить количество строк. Ибо для адресации нужна лишь длина строк, но нестолбцов, но размер строки указать предется обязательно).

    arr[1][2] => *(*(arr + 1) + 2) Это действительно работает, потому что arr имеет тип int[][3] или int*[3]. Коспилятор видя arr+1, знает, что над сместится на 1 размер int[3]. * разыменовывает это, но при этом указывает на то же место. И получает просто указатель на int начало строки. Фактически тут просто меняется тип указателя с int*[3] на int*. +2 сдвигается в строке на 2 размера int.
    Ответ написан
    Комментировать
  • Не могу понять, правильно ли я ввел формулу?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Какое значение эта формула принимает при x=1, например?

    Ну и у вас условие в бинарном поиске неправильное. Если f(a) и f(c) принимают разные значения, то корень находится между a и c. Вы же переходите к отрезку [c,b].
    Ответ написан
    2 комментария
  • Не удается открыть семафор, в чем ошибка?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    А он точно создается? Добавьте в процесс производителя вывод возвращаемого значения. Убедитесь, что семафор создан.

    Может, там, вполне NULL возвращается. И да, лучше HANDLE не сравнивать с nullptr. Это, все-таки, не указатель.
    Ответ написан
    1 комментарий
  • Почему не работает перемещение в C++?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас полная каша в голове. Вы не понимаете, что такое перемещение, копирование.

    Вот как вы себе пердставляете перемещение int*?
    int* - это адрес в памяти. Число. Когда вы "перемещаете" img этого типа, вы перемещаете одно число. Из переменной img, в вектор.

    При этом что там лежит в памяти по адресу, равному этому числу (или на 20 сдвинутому), вообще не поменялось.

    Да, указатели используются в перемещении. Вместо того, чтобы копировать буффер в новое место. можно просто переприсвоить указатель в новой структуре на указатель в старой. Именно так вы перемещаете указатель, вместо копирования данных по этому адресу. Вот чем перемещение отличается от копирования.

    Так, у вас в imgs вы не пихаете копию данных, а пихаете указатель.
    Ответ написан
    2 комментария
  • Как правильно подключить #include?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас тут циклическая зависимость: c_image использует c_window, который использует c_image

    Надо forward declaration расставить кое где. Чтобы не было зависимости от порядка include в файлах, стоит, наверно, расставить их в обоих файлах:
    class c_image;
    class c_window {
    // ...
    }


    И для красоты стоит image.hpp включать не в window.hpp, а window.cc. Ну и для второго класса аналогично сделать.

    Но лучше иерархию классов перетряхнуть. Такие циклические зависимости - это плохо. Надо использовать какой-то базовый класс с общим интерфейсом. Тогда и window и image будут принимать вот этот вот базовый интерфейс, а не конкретный тип.

    Edit: Да, ошибка возникает потому, что в каком-то cc файле сначала вставился image.hpp, из которого вставился window.hpp (внутренний image.hpp в нем не вставляется из-за pragma once. Иначе бы была бесконечная рекурсия). В итоге у вас в .cc файле сначала идет определение класса window, и только потом класса image.
    Ответ написан
    Комментировать
  • Какая обёртка позволяет разыменовывать без неопределённого поведения?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Ну просто проверяйте в operator*: если nullptr, то бросайте исключение.
    Ответ написан
    2 комментария
  • Издержки полиморфизма или неправильный дизайн?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Не совсем правильный дизайн. Смысл складывать float и int в одну кучу, если все, что вы с ними делаете - это берете int или float значение.

    В хорошем дизайне у вас какая-нибудь функция print будет. Которая будет соответствующее число красиво, в соответствии с типом, выводить. Или рисовать на экране что-то, или считать что-то.

    Если же вы действительно хотите брать вот такие совершенно разные по смыслу значения у разных наследников, то, да, в интерфейсе должны быть все функции. Можно в интерфейсе их определить с ассертами и переопределить только в нужных наследниках.
    Ответ написан
    1 комментарий
  • В чём ошибка вычисления бесконечно убывающей прогрессии с точностью до эпсилон?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Целочисленное переполнение при умножении i на i+1. Замените на, скажем prog += 1/((double)i*(i+1));, должно сработать.

    При i порядка 50000 результат перемножения не влезает в int. А у вас там 6697830 операций. В результате используются отрицательные или слишком маленькие неправильные значения i для вычисления слагаемых после 50000, и результат вообще не правильный.

    Ну и, кстати, логика решения у вас неправильная. Надо не с конечным значением сравнивать, а останавливаться, когда следующее слагаемое становится слишком маленьким.
    Ответ написан
    5 комментариев
  • Откуда взялся const?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    const char* взялся вот отсюда: "Hello world". Это строковая константа в коде. Ее программа менять никак не может. Компилятор ее засовывает в read only секцию исполняемого файла.
    Ответ написан
    Комментировать