Ответы пользователя по тегу C++
  • Важен ли return в main?

    @res2001
    Developer, ex-admin
    Если писать код, соответствующий стандарту языка, то корректно, конечно, указывать return.
    В большинстве современных ОС любой запущенный процесс возвращает код возврата. Это требование ОС. Кодом возврата процесса обычно является значение возвращаемое из main.

    Но, если код возврата не нужен, то можно не указывать return и объявлять void main(). Тогда считается, что код возврата из программы нулевой. Обычно это нормально отрабатывает. Но это не стандартная фича и ваша программа может не собраться на какой-то платформе и/или компиляторе.
    Ответ написан
    Комментировать
  • Как правильно выделить память (с проверкой выделения) для массива класса?

    @res2001
    Developer, ex-admin
    какой из вариантов наиболее эффективен / наиболее используемый

    Создание класса в динамической памяти делится на 2 этапа:
    1. выделение "сырой" памяти у менеджера памяти
    2. инициализация памяти - вызов конструктора класса на выделенном участке памяти.
    Вариант с malloc не выполняет вторую часть. Для того что бы закончить процесс в этом варианте вам надо использовать размещающий new, передав указатель на ранее выделенную память. Деструкторы так же нужно будет вызывать явно.

    Если вариант с malloc довести до логического конца, то он будет делать то же самое что и вариант с new, никаких преимуществ тут нет. Но не забываем про явный вызов деструктора.

    При удалении класса из динамической памяти присутствуют обратные этапы: вызов деструктора и освобождение памяти.

    malloc обычно используют в плюсовом коде, когда реализуют собственные аллокаторы и нужен "сырой" не инициализированный блок памяти. Но и в этом случае вполне можно обойтись без malloc - использовать new char[MEM_SIZE]
    Ответ написан
    Комментировать
  • Как использовать namespace в header?

    @res2001
    Developer, ex-admin
    Заверните весь код в input.cpp в namespace input {}
    namespace добавляет к символам в объектом файле имя namespace, но т.к. у вас определения в input.cpp не включены в namespace, то в объектном файле эти символа будут без добавления имени namespace, поэтому и undefined reference.
    Ответ написан
    Комментировать
  • Можно ли изменить размер типа int?

    @res2001
    Developer, ex-admin
    1. Размер всех типов всегда кратен 8 битам. Просто потому, что минимально адресуемый размер памяти в современных процессорах - это 1 байт. Так что 31 или 33 сделать не возможно. Теоретически можно сделать, например, 24 или 40, но смотри следующий пункт.
    2. Все базовые типы С/С++ однозначно проецируются на типы данных, поддерживаемые процессором. Поэтому реально использовать только типы, которые поддерживаются железом. А их не так много и все они, скорее всего, уже есть среди базовых типов С/С++.

    Да можно использовать вариант с битовыми полями или библиотеки для длинных чисел и т.п., но вычисления в этом случае будут медленные, т.к. все операции придется реализовывать программно. Кроме того, если взять битовые поля - там вы можете определить поле размером в 31 бит, но переменная все равно будет занимать 32 бита в памяти (см п.1).
    Ответ написан
    Комментировать
  • Почему побайтовый сдвиг даёт разные результаты?

    @res2001
    Developer, ex-admin
    Читайте тут до прояснения раздел "Bitwise shift operator.
    Смысл в том, что если вы знаковое число сдвинули влево так, что старшим разрядом стала 1, то в результате получится отрицательное число. При сдвиге вправо знакового числа, освобождающиеся слева разряды заполняются битом знака (а не нулем), поэтому результат сдвига отрицательного числа так же будет отрицательным (а положительного - положительным:). Если сдвигать вправо беззнаковое число, то свободные биты будут всегда заполнятся нулями.
    Кстати, на сколько помню, по стандарту знаковость char не определена (может быть как знаковым так и беззнаковым). Вам с вашим примером не повезло, char оказался знаковым. Зато это дало возможность немного глубже понять сдвиги.
    Ответ написан
    6 комментариев
  • Как исправить AccessViolation при чтении указателя, считанного при помощь CArchive?

    @res2001
    Developer, ex-admin
    Не заню, что там в CArchive и вообще MFC давно не брал в руки, но предполагаю, что нужно использовать такой вариант:
    Fruit fruit;
    ar >> fruit;

    Для сериализации/десериализации вызывается метод Serialize вашего же класса, т.е. сам CArchive не создает сериализуемые классы. Следовательно вы должны передать операции >> ссылку на существующий класс, а не указатель. ar просто перезапишет содержимое класса, точнее не ar перезапишет, а ваш же метод Serialize.
    Ответ написан
  • Как написать простой калькулятор?

    @res2001
    Developer, ex-admin
    Например:
    atoi(ex.c_str())+atoi(ex.c_str())
    это выражение 2 раза преобразует в число одну и ту же строку, а затем складывает эти 2 одинаковых числа.
    Так что "не дублирует", а выполняет то что написано у вас в коде.

    Вам нужно сначала разделить строку на "токены", т.е. на операнды и операции.
    Если вы на этом этапе расчитываете обрабатывать только простейшие действия, то вводите строку и разбиваете ее на 3 токена. Затем операнды преобразуете в числа и после этого уже выполняете действие.
    Ответ написан
    Комментировать
  • Книги по сетевому программированию на c++?

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

    @res2001
    Developer, ex-admin
    qtcreator - хорош
    Eclipse - довольно тяжел для понимания, тормозит на больших файлах или когда открыто много файлов (Java дает о себе знать). Но если планируешь программировать для embeded, то полезно научиться с ним работать, т.к. многие IDE предоставляемые производителями железа основаны на Eclipse.
    С clion не приходилось сталкиваться.
    Ответ написан
    1 комментарий
  • Член класса/структуры типа uint8_t * или int8_t *, оптимизация?

    @res2001
    Developer, ex-admin
    Если нет необходимости в подобной локальной переменной, то не нужно "кэшировать".
    На уровне ассемблера все обращения к памяти происходят через регистры, так что в любом случае адрес из указателя будет записан в регистр и этот регистр будет индексироваться.

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

    Часто удобно использовать локальную переменную, только потому, что указатель (ссылка) лежит где-то в третьей вложенности внутри класса - проще его сразу достать и дальше использовать короткую запись. Но это удобно программисту, а компилятору пофиг.

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

    С restrict можно поиграть, но в чистом С++ его нет, на сколько я знаю, но можно включить расширения в gcc/clang и, возможно его можно будет использовть в плюсовом коде. Но применяйте его лучше сразу к локальному bufferу, а не к this.

    Напоследок: подобного типа код выполняется достаточно быстро, оптимизировать тут особо нечего, есть смысл заморачиваться только если это очень-очень горячий код в вашем приложении. Ну и в плане оптимизации для подобных случаев лучше поискать варианты, как обойтись без копирования данных, чем надеятся, что restrict вам сильно поможет.
    Ответ написан
  • Выделение текста между двумя запятыми C++?

    @res2001
    Developer, ex-admin
    Потому что второй параметр в substr - это не конечная позиция, а количество символов. Ощути разницу.
    Ответ написан
    Комментировать
  • Почему мой вектор не работает со строками?

    @res2001
    Developer, ex-admin
    С clon все в принципе нормально. Можно конечно добавить std::move, но проблема не в этом.
    Проблема в том, что у тебя массив arr размером length - 1, а temp - length. А в clon() ты пытаешься копировать length элементов из arr, поэтому происходит выход за пределы массива.
    В PushBack делай инкремент length, только после того как вызовешь clon первый раз, но до второго вызова.

    Жаль немецкий убрал, было забавно :-) Но так гораздо привычней и понятней.
    Ответ написан
    Комментировать
  • Как выделить подстроку с числом с фиксированной точкой?

    @res2001
    Developer, ex-admin
    В string то же можно обращаться к отдельно взятому символу с помощью оператра индексации.

    Все просто: В цикле проходишь по строке ищешь "+" или "-" или "." или любую цифру.
    Если нашел что-то из этого списка, то натравливаешь на строку, начиная с этой позиции функцию strtod - она сконвертирует строку в double и вернет позицию первого не цифрового символа в строке. Полученное от strtod число вывести на экран. Продолжаешь поиск дальше, начиная с позиции, которую вернула strtod и так до конца искомой строки.
    Ответ написан
    2 комментария
  • Как отсортировать дробную и целую часть числа в C++?

    @res2001
    Developer, ex-admin
    Целую часть можно получить с помощью floor(v)
    Дробную: (v - floor(v))
    Для сортировки используйте стандартный sort.

    Кстати, отсортировать вы можете массив (он у вас уже есть в памяти), когда говорят про поток, то это нечто потенциально бесконечное, порции данных из потока вы получаете частями и обрабатываете их.
    Соответственно, если у вас действительно поток, то надо строить из его данных дерево. Для этого можно использовать стандартный map. Данные будут укладываться в дерево по мере поступления с одновременной сортировкой. Получить из дерева отсортированный список можно просто обходом дерева с помощью итератора.
    Данные в дереве сортируются по ключу. Для ключа можно использовать примерно такую конструкцию: floor(v) + (1 - (v - floor(v)))
    Ответ написан
    3 комментария
  • Правильно ли я понимаю работу программы?

    @res2001
    Developer, ex-admin
    Правильно понимаете.

    Цикл for (int i = count-1; i < count; i++) всегда из одной итерации, так что смысла в нем нет. Оставьте просто одно выделение памяти для последнего элемента массива А (сам цикл уберите).
    В конце вы не освобождаете память - это утечка. В реальных проектах подобное поведение плохо заканчивается.
    Ответ написан
    1 комментарий
  • Как сымитировать потерю пакетов?

    @res2001
    Developer, ex-admin
    Например во FreeBSD в штатном фаерволе ipfw есть такая штука как dummynet - специально для целей тестирования. Там можно настройками задавать скорость и процент потерь. Можно очень хорошо отлаживать сетевые приложения, если сделать фряху с подобным фаерволом шлюзом между клиентом и сервером вашего приложения. Подобную сетку запросто можно поднять на виртуалках.
    Ответ написан
    Комментировать
  • Как передать массив в функцию С++ ( пишет no matching function to call)?

    @res2001
    Developer, ex-admin
    Написал опус на вопрос, который вы удалили, хорошо сохранился в буфере обмена :-) а то было бы обидно.

    Ваш массив пожно просто привести к указателю, по старинке (int*)a или используя касты.

    Но у вас тут на самом деле 2 проблемы.
    Первая - обращение к элементам массива в average используя [i][j]. Вторая - VLA.
    По первой проблеме:
    В С/С++ оператор индексации (array[i]) выполняет следующее действие: *(array+i).
    Отсюда должно быть понятно, что раз array у вас это int*, то после array[i] вы получите int, от которого уже нельзя взять второй индекс, т.к. это просто 1 int, а не массив.

    Отсюда есть несколько выходов:
    1. дурацкий (самый долгий по исполнению и затратам памяти): использовать динамический массив массивов
    Выглядит примерно так:
    int **array = new int*[rowCount];
    for(int i=0; i < rowCount; ++i)
       array[i] = new int[colCount];

    Как видите array превратился в двойной указатель, теперь каждый элемент в первом измерении - это указатель на одномерный массив. Всего у вас получается rowCount + 1 выделений памяти. Не забудьте столько же раз вызвать оператор delete.
    В average теперь передавайте int** и у вас будет работать оператор [][], т.к. первая индексация уже будет возвращать int*.
    Не рекомендую использовать этотт способ.

    2. Вычислять индекс массива вручную (не использовать индексацию):
    *(array + i*colCount + j)
    Это такой хардкорный стиль. Но зато работает быстро и масштабируется на массивы любой размерности без особых проблем.

    3. использовать std::vector<std::vector<int>> - это то же самое, что и вариант 1, но закамуфлированный под вектор :-)

    Вторая проблема это VLA (Variable Length Array).
    Статические (автоматические) массивы в С++ вы можете определять, только константным размером (размером известным на этапе компиляции).
    У вас же размерность массива динамическая (вводится пользователем во время выполнения программы). Отсюда следует, что вы должны использовать динамические массивы, выделенные с помощью new.
    В стандарте С++ нет VLA. VLA есть только в Си и то начиная с С99.
    Ваша функция task3 компилируется, только потому что в gcc/clang по умолчанию включены расширения. В расширения входит так же и возможность использовать VLA. Если задать опциями более строгое соответствие стандарту С++, то функция не соберется.
    И кстати, например в микросовтовский компилятор VLA до сих пор не завезли.

    Но если уж у вас есть VLA, то вы можете преобразовывать указатель в VLA массив с помощью такой кучерявой конструкции:
    int (*array2)[colCount] = (int(*)[colCount]) array;

    В этом случае обращаться к элементам массива можно как обычно через двойную индексацию: array2[i][j]
    Когда-то делал тест на эту тему: https://ideone.com/4i6lRw
    Кстати, если в average сначала передать размерности, и последним параметром массив, то по идее массив можно сразу объявить двумерным, используя ранее переданные размерности:
    void average(int rowcount, int colcount, int aarray[rowCount][colCount])

    Это то же VLA.

    Вообще не рекомендую в С++ использовать VLA, т.к. программа становится не переносимой и зависимой от компилятора.
    Ответ написан
    4 комментария
  • Стоит ли учить Boost в 2021 году?

    @res2001
    Developer, ex-admin
    Вполне востребованная библиотека.
    Но учить не стоит. Стоит знать, какие возможности она предоставляет и как ее исопльзовать в своем проекте. Сделать пример с какими-нибудь достаточно сложными компонентами буста, например asio.
    Ответ написан
    Комментировать
  • Как удалить наименьшую цифру из числа?

    @res2001
    Developer, ex-admin
    Проще всего, по моему, перевести число в строку и работать с символами. Находите минимальную цифру перебором, запоминаете ее позицию в строке, копируете остаток строки после минимальной цифры в позицию минимальной цифры.
    Ответ написан
    Комментировать