Ответы пользователя по тегу C++
  • Почему недоступны приватные поля для дружественного метода?

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

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

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

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

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

    Единственный возможный косяк в порядке байт. Может, они в файле записаны от младшего к старшему. Тогда вам при склейке надо a,b,c,d в обратном порядке использовать.
    Ответ написан
    9 комментариев
  • Где ошибка в коде?

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

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

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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Похоже линкер не может найти библиотеку xbase. У вас в коде указана pragma xbase32.lib, но видимо этого не достаточно. Пропишите в ключах компилятору где искать эту xbase.

    edit: ошибка говорит, что линкер не может найти определение перегруженного метода << для вывода xb::xbString в cout.
    Ответ написан
    Комментировать
  • Как реализовать побитовый сдвиг чисел, которые записаны как строки ( длинные числа хранятся в строках)?

    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 секцию исполняемого файла.
    Ответ написан
    Комментировать
  • Тонкости Компиляторов. Почему в классах с++ не требуется объявление функции до вызова?

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

    Правила видимости функций растут еще из Си. Не знаю конкретно о чем думали, но сделали точно также и в Си++. Когда стали вводить классы от этого наследия отказались, ведь в Си никаких классов и методов нет.
    Ответ написан
    Комментировать
  • Почему в С++ не работают 2 цикла for?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    for(; i < n; i++) Ничего глаз не режет? Зачем там точка с запятой после скобочки?
    Ответ написан
    Комментировать
  • Как нарисовать кривую Серпинского (см. ниже), не используя графические библиотеки, а '*' или слешы?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Напрягает требование, что нельзя использовать контейнеры. Так-то ваш подход правильный: Заводим поле для вывода, рекурсивной функцией, которой передаются порядок кривой, и где ее рисовать (квадрат и его поворот). Функция рекурсивно вызывает 4 кусокчка в каждом из 4 квадратов и рисует 3 соединительных кусочка. Но поле для вывода это так или иначе массив. Можно и самому его завести, но почему нульзя использовать контейнеры - не понятно.

    Второй вариант: релизовать функцию, которая (опять рекурсивно) считает какой символ вот на этой позиции в кривой вот такого порядка. Функция проверяет, лежит ли искомый символ между четырьмя квадратами. Если да, то сразу понятно - стоит там пустота или один из трех соединительных кусочков. В противном случае, рекурсивно вызываемся для нужного квадрата, пересчитав координаты, и может быть поворачиваем ответ на нужный угол.

    А потом циклом выводим результат работы функции для всех координат. Это работает в логарифм раз медленее, но зато не требует выделения памяти под все поле вывода.

    edit: Да, еще есть трюк - считайте, что кривая не замкнута. Левый верхний угол - пустота. И надо отдельно в самом конце замкнуть ее в этом углу через "/".
    Ответ написан
    6 комментариев