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

    @res2001
    Developer, ex-admin
    А если я смотрю strlen(recvbuf) то получаю 16. Откуда берется такой хвост?

    В recvbuf вы получаете не с-строку, а массив байт, применять строковые функции к массиву байт бессмысленно.
    Отличие с-строки от массива в том, что строка оканчивается завершающим нулем, а в массиве байт вы должны знать длину массива. В с-строке символ 0 не может быть в теле самой строки, только в качестве терминального символа, в массиве байт 0 - такой же равноправный элемент данных, как и все остальные, может быть в любом месте массива или не быть вовсе.
    Вам еще повезло, что выдает 16 байт, вместо 4, вполне могло бы сложиться так, что нулевого байта не было бы на достаточно продолжительном участке памяти, тогда был бы просто вылет из программы или какие-либо трудно диагностируемые глюки.
    Ответ написан
    5 комментариев
  • Что делать с include-ами?

    @res2001
    Developer, ex-admin
    Не правильно вы понимаете. Директивы препроцессора используются практически в любом проекте на С/С++. Посмотрите заголовочные файлы стандартной библиотеки. Темплейты - это про другое.
    ада с define-ами

    Это сильно преувеличено.
    Пример использования:
    1. При компиляции устанавливаете через опцию компилятора /D свой define: /Dsome_const_name
    2. В коде:
    #ifdef some_const_name
    #include "my_header.h"
    #else
    #include "my_other_header.h"
    #endif

    3.Все
    Ответ написан
    2 комментария
  • Как вывести каждый байт значения типа int?

    @res2001
    Developer, ex-admin
    1234 в шестнадцатеричной системе 4D2.
    Младший байт равен D2, в двоичной системе это: 1101 0010
    Как видите старший бит установлен в 1 - значит, если это знаковое число, то оно отрицательное и закодировано дополнительным кодом. Осталось только разложить D2 в дополнительном коде и получите -46 - это результат вам и вывела printf.
    Ответ написан
    Комментировать
  • В чем разница между malloc() и calloc() а также free() и dellete()?

    @res2001
    Developer, ex-admin
    Разница только в том, что calloc обнуляет выделенную память перед тем, как возвратить указатель, а malloc этого не делает. Внутри calloc, наверняка вызывает malloc для выделения памяти, а потом memset для обнуления. Так что calloc это просто надстройка над malloc для удобства. Вот схематично реализация calloc:
    void * calloc (size_t num, size_t size)
    {
       void * mem = malloc(num * size);
      memset(mem, 0, num * size);
      return mem;
    }

    Сами эти функции оперируют исключительно размером выделяемой области в байтах, им все равно что вы в дальнейшем будете делать с выделенной памятью - инты туда писать или "стринги".
    Ну и как бы никто не мешает вам одну и ту же область памяти сначала использовать как массив интов, а потом как массив байт. Или так например:
    int a = 0x33323130;
    char * c = (char*)&a;
    printf("%c %c %c %c\n", c[0], c[1], c[2], c[3]);

    Пример не использует malloc/calloc для выделения памяти, память выделяется в стеке просто объявлением int a. Тут я попытался показать, что содержимое памяти можно интерпретировать как угодно, главное находится в границах выделенного диапазона.
    Причем языки С/С++/asm это позволяют делать, а другие - нет.
    Пример предполагает, что int имеет размер 32 бита, не для всех платформ это так, но в основном - именно так.
    Кстати этот пример можно использовать для определения порядка байтов платформы: если выведется "1 2 3 4" значит у вас LITTLE ENDIAN, а если "2 1 4 3" - BIG ENDIAN.

    PS: free() - это Си, а delete - C++
    Ответ написан
    4 комментария
  • Как правильно передать двумерный массив в функцию?

    @res2001
    Developer, ex-admin
    Если вы изучаете С++, то лучше использовать классы стандартной библиотеки для массивов. В функцию передаете ссылку на класс.
    В чистом Си передается просто указатель и размер в отдельном параметре (или 2 размера для двумерного массива).
    Сам двумерный массив может быть представлен в двух вариантах:
    1.Как массив указателей, где каждый указатель представляет собой одномерный массив. Нужно отдельно выделять память для массива указателей и для каждого одномерного подмассива и аналогично освобождать. В этом случае возможна операция индексации обоих измерений массива, при этом массив указателей и каждый подмассив могут находится в разных участках памяти.
    void foo(int ** arr, int N, int M)
    {
    ...
    }
    int main()
    {
      int N = 10; // первое измерение массива
      int M = 20; // второе измерение массива
      int ** arr = new int * [N];
      for(int i = 0; i < M; ++i)
      {
         arr[i] = new int[M];
      }
      ...
      foo(arr, N, M);
      ...
      // Тут освобождение массива аналогично выделению в обратном порядке
    }

    2.Как одномерный массив размерностью N * M. В этом случае память под массив выделяется и освобождается вся оптом одним куском, но операция индексации первых размерностей не возможна. Но можно легко переходить от двумерного массива к одномерному, сразу вычислять нужный индекс или просто перемещаться по элементам массива с помощью временного указателя.
    void foo(int * arr, size_t N, size_t M) 
    {
      ...
    }
    int main()
    {
      int N = 10; // первое измерение массива
      int M = 20; // второе измерение массива
      int * arr = new int * [N*M];
      int * arrcur = arr;  // временный указатель для обхода массива
      int * arrone = arr;  // вариант с переходом к одномерному массиву
      for(int i = 0; i < N; ++i)
      {
        for(int j = 0; j < M; ++j)
        {
            // Вариант с вычислением адреса текущего элемента по индексам
           *(arr + i * M + j) = rand() % 10;   // вычисление нужного индекса на месте
           // Вариант с обходом массива с помощью временного указателя
           *arrcur = rand() % 10; 
           ++arrcur;  // переход к следующему элементу
           // Вариант с переходом к одномерному массиву
          arrone[j] = rand() % 10; 
        }
        arrone += M;
      }
      ...
      foo(arr, N, M);
      ...
      delete[] arr;
    }
    Ответ написан
  • Какую книгу по C++ стоит прочитать новичку?

    @res2001
    Developer, ex-admin
    Хорошая книга, можете ее продолжать изучать, а главное делайте побольше примеров, возможно в дальнейшем захочется реализовать что-нибудь свое. Тут главное практика, а не то какую книгу читаете.
    Ответ написан
    Комментировать
  • Записать значения дискретных каналов в бинарный файл. С++?

    @res2001
    Developer, ex-admin
    Инициализируя вот так массив:
    int ChValue [6] = {000011};
    Вы получите в ChValue[0] = 9 - десятичное 9 - это восьмеричное 011. По правилам языка, целочисленные числовые константы, начинающиеся с 0 являются восьмеричными. В остальных элементах массива будут 0.
    Вы хотите записать шесть значений в одну двухбайтовую переменную (хотя было бы достаточно и 1 байта).
    Для этого вам нужно использовать битовые операции.
    Например:
    // ChValue - исходный массив значений по каждому каналу
    int ChValue [6] = {0, 0, 0, 0, 1, 1};
    uint16_t val = 0;
    for(int i = 0; i < 6; ++i)
    {
      if(ChValue[i] == 1)
         val |= 1 << i;
    }
    // в результате в val будет установлен в 1 бит с номером канала в котором в ChValue единица.

    После этого просто запишите val в файл.
    Ответ написан
  • Как распределять свои проекты?

    @res2001
    Developer, ex-admin
    Освойте утилиту make и makefile.
    Ответ написан
    1 комментарий
  • С ++. Создание и запись бинарного файла?

    @res2001
    Developer, ex-admin
    1. unsigned int на большинстве платформ - 4 байта, поэтому используйте более подходящие типы для сигналов: uint16_t например.
    2. Раз количество каналов меняется, то есть смысл отделить заголовок (n и timestamp) от собственно данных каналов. Заголовок пишете отдельно, а данные каналов храните в массивах соответствующих типов и записываете целиком массив.
    3.Т.к. у вас не известно заранее количество каналов, то стоит писать в файл эту информацию (включить количество аналоговых и дискретных каналов в заголовок). 4.Так же есть смысл ввести в заголовок некую преамбулу (набор из 2-5 символов идентифицирующих ваш тип файла) и версию файла. Это поможет при последующих модификациях структуры файла.
    5.Удобно проверять получившийся файл с помощью HEX редактора 010 Editor - там можно на бинарный файл накладывать структуру и просматривать уже структурированный файл. Структуры описываются в Си подобном стиле, так что научится можно за 20 минут на готовых примерах.
    Ответ написан
    Комментировать
  • Как из программы на c++ отправлять ответ на запрос в консоль linux?

    @res2001
    Developer, ex-admin
    Генерируйте random_port > 1024 и запроса на ввод пароля не будет.
    Ответ написан
    Комментировать
  • Как редактировать скрытые расширенные атрибуты файлов в windows?

    @res2001
    Developer, ex-admin
    WinAPI тут не причем, это не аттрибуты файла (с которыми работает WinAPI), это метаинформация (теги), записанная непосредственно в файле так же как. Ищите описания нужных форматов файлов, изучайте. Наверняка есть готовые библиотеки с помощью которых можно работать с медиа файлами.
    Ответ написан
    Комментировать
  • Разделить число на разряды c++?

    @res2001
    Developer, ex-admin
    Откройте для себя операцию взятия остатка от деления - % (в вашем случае на 10), с ее помощью ваша задача решается тривиально.
    Ответ написан
    Комментировать
  • Почему не работают массивы переменной длины?

    @res2001
    Developer, ex-admin
    Поддержка VLA (и вообще всех новых расширений языка), действительно, зависит от компилятора.
    Например в MSVC, по моему, до сих пор поддержки VLA нет.
    Официально микрософт заявляет о поддержке С90: https://docs.microsoft.com/en-us/cpp/c-language/an...
    Но в компиляторе присутствуют расширения языка (по умолчанию включенные), список расширений можно посмотреть в описании опции компилятора /Zc, и VLA там нет.
    При том, что присутствуют некоторые расширения из С++17.
    Кроме того присутствуют некоторые вещи, которые появились в С99, но их в "расширениях" нет, они уже вошли в компилятор "по умолчанию", например переменное количество аргументов в #define.
    Ответ написан
    2 комментария
  • Как используются ссылки и указатели в С++?

    @res2001
    Developer, ex-admin
    Указатель - это такая же переменная как и все остальные, т.е. область памяти для хранения целочисленного значения. Чтоб ее использовать, ее нужно сначала инициализировать корректным значением, иначе получите ошибку/предупреждение на этапе компиляции.
    Т.е. чтоб использовать *p, в p должно лежать корректное значение, поэтому перед этим оператором идет присваивание. В принципе ваш пример откомпилируется, но скорее всего он вызовет падение программы, т.к. адрес 0x1010101 взят с потолка и скорее всего укажет в нераспределенную область памяти. Может и не вызвать падение, тут уж как повезет.
    Ответ написан
    Комментировать
  • Как закрыть фоновый экземпляр программы?

    @res2001
    Developer, ex-admin
    Используйте любой механизм межпроцессного взаимодействия (IPC) - сокеты, каналы, именованные мьютексы, общая память, ...
    Просто посылаете сообщение второму процессу, чтоб он закрылся.
    Ответ написан
    Комментировать
  • Есть ли разница между двумя функциями?

    @res2001
    Developer, ex-admin
    Ваша функция работает делает свое дело за 1 проход по массиву, второй вариант - за shift проходов - сложность O(N) и O(N*shift) соответственно. Во втором случае скорость зависит от величины сдвига, что очень плохо для такого алгоритма.

    Циклический сдвиг массива "на месте" реализуется с помощью трех операций revers (операция изменения порядка элементов на противоположный):
    1.весь массив делится на 2 массива в точке сдвига (условно, без выделения памяти)
    2.revers первой части
    3.revers второй части
    4.revers всего массива
    Встречал на stackoverflow реализацию на Си.
    Работает за 2 полных прохода с операциями swap по массиву - O(2*N), но каждая операция тяжелее чем в ваших вариантах. Но быстродействие не зависит от величины сдвига и не требует дополнительной памяти, что может быть важно при работе с массивами большой размерности.
    UPD: вспомнил, этот способ был описан в книге Бентли "Жемчужины программирования"!
    Ответ написан
    Комментировать
  • С++ Как поменять символ на другой?

    @res2001
    Developer, ex-admin
    a[2]='n';
    В двойных кавычках - это строка с завершающим нулем, даже если она содержит 1 символ. В одинарных кавычках - символ.
    Ответ написан
    Комментировать
  • Какую литературу выбрать для изучения WINAPI?

    @res2001
    Developer, ex-admin
    PVOID - void*
    PWSTR - wchar_t *
    HANDLE - просто целое, подробностей, обычно, знать не нужно - это идентификатор объекта (хэндл).
    И берите Русиновича по совету 15432
    Ответ написан
    3 комментария
  • Как сделать невидимое консольное приложение - видимым?

    @res2001
    Developer, ex-admin
    Попробуйте в настройках службы, в командной строке запуска приложения, сделать перенаправление потоков стандартного вывода и ошибок в файл:
    proga.exe 1>praga.log 2>&1
    тогда сможете видеть в файле весь вывод приложения без окна. Файл должен быть доступен на запись для пользователя, под которым запускается приложение/служба.
    Настройки всех служб хранятся в реестре в HKLM\System\CurrentControlSet\Services
    Ответ написан
    1 комментарий
  • Альтернатива Visual Studio?

    @res2001
    Developer, ex-admin
    В качестве компилятора подойдет msys2/mingw64 или тот же микрософтовский компилятор, его можно установить отдельно от студии.
    На счет библиотек - в msys2 есть пакетный менеджер, можно установить огромное количество свободные библиотеки и использовать их. Для микрософтовского компилятора либо придется искать уже готовые бибилотеки, либо собирать самому из исходников (обычно это не вызывает особых проблем).
    Ответ написан
    Комментировать