Задать вопрос
  • Как переставить в обратном порядке элементы массива, расположенные между его минимальным и максимальным элементами?

    @Mercury13
    Программист на «си с крестами» и не только
    Найти индекс минимального и максимального.
    Если нужно, поменять местами, чтобы один был меньше другого. ИНДЕКСЫ, не элементы.
    А теперь цикл.
    ++низИндекс
    --верхИндекс
    пока низИндекс < верхИндекс
      поменять a[низИндекс], а[верхИндекс]
      ++низИндекс
      --верхИндекс

    Если индексы беззнаковые, надо проверить как-то, что первое --верхИндекс не приведёт к «антипереполнению». Например, «если верхИндекс > 0»…
    Ответ написан
    Комментировать
  • Структура RGBA матрицы, декодированных чанков PNG-изображения?

    @Mercury13
    Программист на «си с крестами» и не только
    Это так называемый фильтр, для каждой строчки свой. Хорошо описано в англовике.

    В первой строчке фильтр 1 — пиксель слева. Сначала к (0,0,0,0) (все пиксели за пределами картинки имеют цвет (0,0,0,0)) добавляем (0,255,0,255). Для всех остальных пикселей прибавка будет (0,0,0,0).
    Во второй строчке фильтр 2 — пиксель сверху. То есть к пикселю сверху (зелёному) прибавляем (0,0,0,0) — и получаем такой же зелёный пиксель.
    Когда начинается красная полоска, поступаем так же — первая строчка строится по пикселю слева, остальные — по пикселю сверху.
    В оранжевой строчке у нас хитрый фильтр 4 — фильтр Пэта. Для каждого из каналов берём пиксель сверху, слева или сверху-слева — в зависимости от того, что ближе к В + Л − ВЛ. Ну и соответственно прибавляем 0, 100, 0 и 0. Почему система выбрала именно этот фильтр, если фильтр 1 справится не хуже — не знаю.

    Есть пять фильтров.
    0 — как есть.
    1 — прибавить к пикселю левее.
    2 — прибавить к пикселю выше.
    3 — прибавить к их полусумме.
    4 — прибавить к тому пикселю из трёх, что ближе к В + Л − ВЛ. Приоритет на случай «ничьей» — Л > В > ВЛ.

    Всегда работаем с байтами; если глубина <1 байта — значит, один байт захватывает несколько пикселей, а под «пикселем слева» подразумеваем предыдущий байт. Если >1 байта — отступаем на глубину цвета (2, 3 или 4). Полусумма байтов вычисляется в достаточной точности с округлением вниз; «прибавить» — в типе byte (т.е. по модулю 256).

    Главное, что так долго делает программа PNGOUT — это экспериментирует с фильтрами. Подобная оптимизация может серьёзно уменьшить результирующий PNG.
    Ответ написан
    Комментировать
  • Как подключиться к MySQL из Qt?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужны две DLL’ки: libmysql.dll в каталоге с программой, и qsqlmysql.dll в каталоге plugins/sqldrivers.
    От подкаталога plugins можно избавиться, написав в программе

    QApplication a(argc, argv);   // это наша программа, обычно создано автоматом
    a.addLibraryPath(QCoreApplication::applicationDirPath());


    От sqldrivers, насколько мне известно, так нельзя.
    Ответ написан
    Комментировать
  • Почему косинус иногда изменяется на синус?

    @Mercury13
    Программист на «си с крестами» и не только
    Что такое синус и косинус? У нас есть отрезок (0, 0) — (1, 0). Повернём его вокруг первого конца, и координаты второго конца — это cos и sin.

    А теперь нарисуем на плоскости вторую систему координат: у неё ось x' смотрит вниз, а ось y' вправо. Эти две системы координат совпадают началом координат, масштабом (т.е единица в одной будет единицей в другой) и ориентацией (ось y против часовой стрелки от оси x).

    У нас есть отрезок (0,0) — (x, y) длины 1. В системе (x, y) это единичный, повёрнутый на угол α, в системе (x', y') — на угол β=90°+α.

    Поскольку x = y' (мы так нарисовали вторую сетку), то cos α = x = y' = sin β = sin(90° + α).

    P.S. Я попробовал доказать всё это относительно строго, не ссылаясь ни на графики, ни на более сложные утверждения вроде синуса суммы.
    Ответ написан
    Комментировать
  • Какой компонент использовать для работы с Excel в RAD Studio 10.1 Berlin (Delphi)?

    @Mercury13
    Программист на «си с крестами» и не только
    Можно загуглить NativeExcel — он распространялся с исходниками, и вполне найдётся хакнутая версия.
    Есть, правда, несколько не слишком удачных вещей в NativeExcel, и если модуль приглянется, спросите меня, что в нём можно улучшить. Вкратце.
    1. Портирование WideString → UnicodeString.
    2. Портирование Delphi ZLib port → Embarcadero Zlib interface.
    3. Разглючка для Zip’ов LOo.
    4. Разглючка для XML LOo.
    5. Разглючка с цветами XLSX. LOo тут, как ни странно, ни к чему, но однажды попадался такой XLSX.
    6. Разглючка с распознаванием bool (тоже LOo).

    UPD. Сам NativeExcel три года как брошенный, его домен с недавних пор ничей — надеюсь, автор коммерческой библиотеки будет не сильно против.
    Ответ написан
    Комментировать
  • Как QFileDialog вывести диалог открытия файла и получить имя файла в char?

    @Mercury13
    Программист на «си с крестами» и не только
    this — это скрытый параметр каждого не-static-метода, который говорит: для какого объекта он вызван. Если этот объект не QWidget, или функция static, или вообще не метод, то или подставляйте другой QWidget (это значит: кнопка на панели задач та же, что и у этого QWidget), или ставьте NULL (завести новую кнопку на панели задач).

    В вашем случае, разумеется, NULL. Или nullptr, если работаете в Си++11.

    QString *qs = new QString("переведи меня в чары! :)");
    char const* ch = qs->toLocal8Bit().constData();

    Верно придумали, только нет нужды заводить строку в куче операцией new. Строка в Qt и так достаточно «экономная», так что хватит
    QString qs("переведи меня в чары! :)");
    char const* ch = qs.toLocal8Bit().constData();

    Только не забывайте про время жизни этого char const*: он будет жить ровно столько, сколько будет жить конкретное значение строки.
    Ответ написан
    Комментировать
  • Можно ли в C++ узнать позицию с которой начинается подстрока без перебора символов в строке?

    @Mercury13
    Программист на «си с крестами» и не только
    1. Надо проверить pSubStr на NULL. Если оно так — не найдено.
    2. Всё наоборот, pSubStr - str.
    Ответ написан
    Комментировать
  • Запуск консольного приложения при перетаскивании на него файла Drag&Drop C++?

    @Mercury13
    Программист на «си с крестами» и не только
    Перетаскивание просто запускает программу, подставив имя файла как параметр командной строки. Те самые argc и argv, передаваемые в main().

    Кроме того, очень желательно (если у вас Windows) работать в Юникоде (в MinGW настройка компилятора -municode, для других компиляторов разбирайтесь сами). Функция main меняется на _wmain, её параметры на int argc, wchar_t** argv. Хотя не обязательно, если пути не содержат расширенных символов.
    Ответ написан
    1 комментарий
  • Не понимаю почему не работает for правильно?

    @Mercury13
    Программист на «си с крестами» и не только
    arr — исходные строки.
    arr2 — сортированные.
    Исходные строки, скорее всего, не будут совпадать ни с одной из сортированных — потому arr2[i]==sarr[j] во втором фрагменте, скорее всего, не выполнится.
    Я бы поступил таким образом. Сделал бы индексированный список сортированных строк и порядковый массив исходных. Поиск сортированной строки в индексированном списке. Если не обнаружена — сортированную в индексированный, исходную в порядковый.

    Что в JS будет индексированным списком — просто не знаю. Вероятно, можно обойтись массивом, присвоив sortedList[arr2[i]] = 1. Вот только как найти то, есть ли?

    UPD. Можно также воспользоваться хранилищем «ключ-значение»: ключом будет сортированная строка, значением — исходная. iamevg_ так и поступил. Единственная засада (которая хороша или плоха, в зависимости от задачи) — портит порядок строк.
    Ответ написан
    1 комментарий
  • Как написать путь файла с пробелами в функции system в C?

    @Mercury13
    Программист на «си с крестами» и не только
    Заэкранировать кавыки.
    system("gcc \"C:/Folder/My Folder/example.c\"" );

    Точно так же экранируется и обратный слэш, если вдруг потребуется.
    system("gcc \"C:\\Folder\\My Folder\\example.c\"" );


    Экранирование символов — механизм, имеющийся в текстовых языках и протоколах. Он служит, чтобы символы, которые считаются служебными и имеют особое значение, этого значения лишить и объявить «просто символами». Нам нужно двойное экранирование: для ОС (строка с пробелами закавычивается) и для Си (перед кавычкой слэш).
    Ответ написан
    Комментировать
  • Почему не видит функцию из библиотеки в Ардуино?

    @Mercury13
    Программист на «си с крестами» и не только
    Запомни раз и навсегда! Inline не создаёт кода, создаёт факт его использования где-либо.
    С одной стороны, inline-функция при каждом использовании должна быть определена. С другой, она не попадёт в объектный файл сама по себе.
    Потому inline держат в хедерах (кроме хитрых случаев вроде private inline, когда синтаксически нельзя эту функцию вызвать откуда попало, а хедер лучше не засорять).

    Когда доберётесь до шаблонов Си++ — они обладают теми же свойствами. Шаблон не создаёт кода, создаёт расшаблонивание. И тоже в хедерах, кроме хитрых случаев вроде private template или шаблона, у которого есть ровно N предопределённых специализаций и (N+1)-я не нужна.

    А вот полная специализация шаблонной функции типа template<> (в угловых скобках пусто, не inline) создаёт и ей место в CPP.
    Ответ написан
    4 комментария
  • Как сделать и вывести срез строки(String) C/C++?

    @Mercury13
    Программист на «си с крестами» и не только
    1.
    std::cout << text.substr(начало, длина) << std::endl;

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

    2. Ничего, что, если строка не оканчивается точкой, последнее «недопредложение» выведено не будет? Может быть, так и верно, но если задача — разделить текст по tab’ам или запятым, надо после цикла выкинуть то, что осталось.
    Ответ написан
    Комментировать
  • Удаление объекта в C++ без создания его через new, или можно ли удалять объекты взятием адреса (&)?

    @Mercury13
    Программист на «си с крестами» и не только
    > Объект BaseClassObj будет удален только по завершению программы.
    BaseClass baseClassObj;
    Здесь создаётся объект на стеке. Имя — это просто имя объекта. Никаких указателей здесь нет. Как только мы покинем блок (любым образом: штатно выйти, goto, break, выброс аварии — кроме «жёсткого» выхода из программы функциями типа exit), у объекта автоматически исполнится деструктор и прямой вызов не нужен. Блок, то есть подпрограмму BaseClassPresentation.

    BaseClass *BaseClassObjPtr = new BaseClass(2);
    Здесь BaseClassObjPtr это имя указателя (а не указатель на указатель). Объект создаётся в динамической памяти, и его придётся уничтожать вручную. Многое в Си++11 сделали для того, чтобы подобные объекты уничтожались не вручную, а всё теми же автодеструкторами.
    std::unique_ptr<BaseClass> BaseClassObjUp = new BaseClass(2);
    Это уже маленький объект со своим деструктором. А в деструкторе находится delete, и он сработает, как только программа выйдет из своего блока.

    То, что вы хотите, иногда бывает нужно, и я вижу этому две причины.
    1. Объект управляет какими-то сложными и важными ресурсами: большим количеством памяти, файлом, мьютексом… И этот важный ресурс бывает нужно освободить раньше, чем наступит деструктор. Например, у любого файлового потока есть функция close() — она закрывает файл.
    2. У нас сложное и хитрое управление памятью, когда приходится использовать placement new и прямой вызов деструктора. Скажу честно, не использовал никогда. Как и 90% программистов на Си++.
    Ответ написан
    9 комментариев
  • Почему линия не прорисовывается с права?

    @Mercury13
    Программист на «си с крестами» и не только
    UPD2. Запомните уж, рисование на форме надо делать только в OnPaint. Сверни-разверни окно — линия исчезнет Код будет примерно такой.
    TForm1 = class(TForm)
       ...
      private
        MyLabel,MyLabel2:TLabel;  // тут они занулятся автоматически, да и фэншуйнее
        ...
      end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
    ...
    MyLabel2.Caption:='3';
    Invalidate;   // Запросить перерисовку
    end;
    
    procedure TForm1.FormPaint(Sender: TObject);  // Событие OnPaint
    begin
      if MyLabel <> nil then
        with Canvas do begin
          Pen.Color:=clRed;
          MoveTo(MyLabel.left,MyLabel.top+(MyLabel.Font.Size+MyLabel.Font.Size div 2) div 2);
          LineTo(MyLabel2.left,MyLabel2.top+(MyLabel2.Font.Size+MyLabel2.Font.Size div 2) div 2);
        end;
    end;

    А для расчёта ваших выносок вариантов несколько.
    1. Нарисовать цифру во внеэкранный буфер и рассчитать размеры реально закрашенной части.
    2. Получить метрику шрифта, по ней прикинуть размеры типичной «заглавной» цифры. Справа убрать пиксель межбуквенного пространства, плюс внести какую-то поправку на «узкую» единичку.

    UPD3. В чём было дело? А в том, что TGraphicControl (к коим относится и TLabel) — это абстракция Delphi, не имеющая аналога в Windows. Он просто берёт тот TWinControl, на котором находится, в случае Transparent рисует фон под собой через WM_PAINT, а затем рисует себя. При этом чёрточка, нарисованная НЕ через OnPaint, стирается.

    UPD4. Полный порядок, рисование через OnPaint — это всё, что надо было. TGraphicControl умный и обходится без лишних перерисовок.

    Ну и наконец «хорошие качества» вашего кода.
    MyLabel := TLabel.Create(Form1);
    MyLabel.Parent := Form1;
    Лучше использовать Self, а не Form1.

    Form1: TForm1;
       p,c,z,j:integer;
    Если бы эти переменные были нужны, лучше было бы их внести в Form1. Если бы…

    function rez(p:integer): integer;
       begin
       c:=p+20;
    
       end;
    Мы тут, очевидно, рассчитываем габариты наших надписей. А нельзя это сделать без побочных эффектов?

    UPD. Это только макет и будет глючить на высоких DPI. Пожалуйста, если хотите такое широкой публике — усложните расчёты.
    Ответ написан
    Комментировать
  • Где располагаются переменные в данном случае (стэк, куча)?

    @Mercury13
    Программист на «си с крестами» и не только
    Вы совершенно правы. Это массив из одного элемента, и при таком расположении он будет в стеке. Со всеми его полями: alloc, size и mp_d. При выходе из функции есть шансы, что он будет затёрт, и так действовать нельзя.

    Кто затрёт? Да кто угодно. Хоть драйвер, пожелавший воспользоваться твоим стеком. Хоть последующий вызов какой-нибудь функции.

    С другой стороны, на то и помечена структура __mpz_struct двумя подчерками, чтобы её не использовали.
    __mpz_struct* foo()
    {
        mpz_t var;
        return (__mpz_struct *)var;
    // C:\TestApps\RetLocal\main.cpp|15|warning: address of local variable 'var' returned [-Wreturn-local-addr]|
    }


    А так работает: всё в куче. Только не забывайте очищать через delete[].
    __mpz_struct* bar()
    {
        __mpz_struct* var = new mpz_t;
        return var;
    }
    Ответ написан
    2 комментария
  • При компиляции VC++, Opencv 3.2 проекта не работает exe на другой системе, требует opencv_world330.dll что делать?

    @Mercury13
    Программист на «си с крестами» и не только
    Краш, вероятно, связан с другой вещью. Компилятор-то новенький, и на ту машину не успели подвезти его среду исполнения. Выясни, какие файлы нужны: MSVCR140.DLL, MSVCP140.DLL или MFC140U.DLL.
    (при условии, что сам OpenCV также скомпилирован C++2017; если нет — также нужны и файлы другого компилятора.)

    Если так и не удастся отыскать — найди программу Dependency Walker и точно найди, чего ей не хватает.
    Ответ написан
    6 комментариев
  • Сортировка по нескольким полям в одном компараторе?

    @Mercury13
    Программист на «си с крестами» и не только
    Не понял. Если по одному, при равенстве — по другому, если всё ещё равны — по третьему, то примерно так.
    public int CompareTo(Book book)
        {
          if (book != null)
          {
            int r = name.CompareTo(book.name);
            if (r != 0)
              return r;
            r = author.CompareTo(book.author);
            if (r != 0)
              return r;
            return Math.sign(releaseDate - book.releaseDate);
          }
          else
          {
            throw new Exception("Невозможно сравнить два объекта");
          }
        }


    Если же вы хотите, чтобы, в зависимости от каких-то настроек, сортировало то по названию, то по автору, сделайте коллекцию разнотипных объектов.
    const int NAME = 0, AUTHOR = 1, COUNT = 2;
    
    class ByName : Comparer<Book> {}
    class ByAuthor : IComparer<Book> {}
    
    Comparer<Book> comparers[COUNT] = {  new ByName(), new ByAuthor() };

    C# знаю плохо, возможны синтаксические ошибки.

    Третий вариант — для полей одинаковых типов сделать унифицированный доступ.
    const int S_NAME = 0, S_AUTHOR = 1, S_COUNT = 2;
    const int I_DATE = 0;
    
    public class Book
    {
        string stringFields[S_COUNT];
        int intFields[I_COUNT];
    
        public string name {
            get { return stringFields[S_NAME; ] }
            set { stringFields[S_NAME] = value; }
        }
    }
    
    class StringComparer : IComparer<Book> {
       int code;
       StringComparer(int aCode) { code = aCode; }
       int Compare(Book a, Book b) { return a.stringFields[code].compareTo(b.stringFields[code]); }
    }
    
    const int ALL_NAME = 0, ALL_AUTHOR = 1, ALL_DATE=2, ALL_COUNT = 3;
    
    Comparer<Book> comparers[ALL_COUNT] = {  
       new StringComparer(S_NAME), new StringComparer(S_AUTHOR), new IntComparer(I_DATE) };
    Ответ написан
    2 комментария
  • Возможен ли в XML атрибут с пространством имён ранее XMLNS?

    @Mercury13 Автор вопроса
    Программист на «си с крестами» и не только
    Опять приходится отвечать самому. Возможен.
    www.oracle.com/technetwork/articles/srivastava-nam...
    <?xml version="1.0"?>
    <Book isbn="1234"
          pfx:cover="hard"
          xmlns="http://www.library.com"
          xmlns:pfx="http://www.library.com">
      <Title>Sherlock Holmes</Title>
      <Author>Arthur Conan Doyle</Author>
    </Book>
    Ответ написан
    Комментировать
  • Как правильно из zip архива считать текстовый файл с помощью PHYSFS?

    @Mercury13
    Программист на «си с крестами» и не только
    Нужно закрыть Си-строку.
    int length = PHYSFS_fileLength(myfile)
    myBuf = new char[length + 1];
    int length_read = PHYSFS_read(myfile, myBuf, 1, length);
    myBuf[length_read] = 0;
    Ответ написан
    Комментировать
  • Как превратить то что вернет WM_CHAR в юникод?

    @Mercury13
    Программист на «си с крестами» и не только
    Recardo_Recoly,
    Понятно.
    1. Лучше использовать WM_UNICHAR, он работает и с кодами более 65535. Поддерживается как минимум WinXP.
    2. Как превратить кодовую позицию в UTF-8, есть много вариантов. Сейчас найду свой.

    enum {
        SURROGATE_MIN = 0xD800,
        SURROGATE_MAX = 0xDFFF,
        SURROGATE_LO_MIN = SURROGATE_MIN,
        SURROGATE_HI_MIN = 0xDC00,
        SURROGATE_LO_MAX = SURROGATE_HI_MIN - 1,
        SURROGATE_HI_MAX = SURROGATE_MAX,
        UNICODE_MAX = 0x10FFFF,
        U8_1BYTE_MAX = 0x7F,
        U8_2BYTE_MIN = 0x80,
        U8_2BYTE_MAX = 0x7FF,
        U8_3BYTE_MIN = 0x800,
        U8_3BYTE_MAX = 0xFFFF,
        U8_4BYTE_MIN = 0x10000,
        U8_4BYTE_MAX = UNICODE_MAX,
        U16_1WORD_MAX = 0xFFFF,
        U16_2WORD_MIN = 0x10000,
        U16_2WORD_MAX = UNICODE_MAX,
    };
    
    void str::putCpNe (char*& p, unsigned long aCp)
    {
        if (aCp <= U8_2BYTE_MAX) {  // 1 or 2 bytes, the most frequent case
            if (aCp <= U8_1BYTE_MAX) {  // 1 byte
                *(p++) = static_cast<char>(aCp);
            } else { // 2 bytes
                *(p++) = static_cast<char>((aCp >> 6)   | 0xC0);
                *(p++) = static_cast<char>((aCp & 0x3F) | 0x80);
            }
        } else {  // 3 or 4 bytes
            if (aCp <= U8_3BYTE_MAX) {  // 3 bytes
                *(p++) = static_cast<char>( (aCp >> 12)        | 0xE0);
                *(p++) = static_cast<char>(((aCp >> 6) & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp       & 0x3F) | 0x80);
            } else {    // 4 bytes
                *(p++) = static_cast<char>(((aCp >> 18) & 0x07) | 0xF0);
                *(p++) = static_cast<char>(((aCp >> 12) & 0x3F) | 0x80);
                *(p++) = static_cast<char>(((aCp >> 6)  & 0x3F) | 0x80);
                *(p++) = static_cast<char>( (aCp        & 0x3F) | 0x80);
            }
        }
    }
    
    void str::appendCp(std::string & s, unsigned long aCp)
    {
        char c[5];
        char* end = c;
        putCpNe(end, aCp);
        s.append(c, end);
    }

    Слово Cp у меня означает code point, кодовая позиция Юникода. Ne — no error-checking, без проверки кодовых позиций на корректность.

    В Си++ есть и штатные функции преобразования кодовых позиций Юникода в UTF-8 и UTF-16. Но страшны, как чёрт, и половина из них в C++17 deprecated :(

    И последнее, что я хочу сказать.
    Вы путаете две вещи: Юникод и его кодовые позиции, и форматы записи юникодных строк UTF-8 и UTF-16. Соотношение «один символ Юникода — один char» только в UTF-32!
    Ответ написан
    33 комментария