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

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Число кратно n, если остаток от деления на n равен 0. Получить остаток можно, воспользовавшись оператором деления по модулю: x%n. Сравнение с 0 делается оператором сравнения ==.

    Число заканчивается на 1, если последняя цифра равна 1. Цифру можно получить, взяв остаток от деления на 10 (см. оператор % выше). Надо этот результат сравнить с 1.

    Чтобы выполнялись оба условия, надо объединить их оператором логического И (&&).

    Чтобы подсчитать числа, в которых выполняются условия выше - надо пройтись по ним циклом (или 5 раз написать похожий код). Там надо через if проверить условие и, если оно выполняется, увеличить счетчик (можно вот так: ++cnt;

    В код переводите сами, это же ваше задание по изучению C++.
    Ответ написан
    Комментировать
  • Почему delete вызывает ошибку?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Первая ошибка:
    char *marka_ = new char;

    Тут вы выделяете память под ровно один символ. Строку туда читать не получится никак (не забывайте, что вам еще байт для нулевого символа в конце строки нужен).

    Вторая ошибка:
    char* m = "Renault"

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

    У вас вообще проблема тут - marka может указывать на выделенную вами в Input() память, а может указывать на переданную из вне память. Кто ее удалять должен-то? Так же в Input() вы можете переписать переданный в конструкторе указатель. А надо ли было его удалять классу?

    Я бы сделал в конструкторе всегда копирование переданной строки. Тогда можно будет передавать туда и строковые константы и использовать вот такое вот значение по умолчанию.
    Ответ написан
    Комментировать
  • Как правильно оформить присваивание значения возвращаемого из функции C++?

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

    Возвращаемое функцией значение является временным значением. В него нельзя писать, но его можно читать. Оно const. И его нельзя передавать в описанный вами оператор копирования.
    Ответ написан
  • На сколько корректна такая реализация?

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

    А дальше надо поменять иерархию ваших классов.
    С такими циклическими зависимостями, конечно, можно что-то даже скомпилировать (в каждом cpp включать другой хедер, в интерфейсе второй класс передавать только как указатель. Или у вас в одном файле сначала сделать оба прототипа, forward declaration второго класса перед ними, потом реализации). Но это будет запутанно и сложно.

    Подумайте, а так ли вам надо в snakeUpdate передавать GameField? Можно, например, из Snake возвращать ее координаты или что там влияет на Update и потом их передавать какому-то методу в GameField. Сейчас ваш snakeUpdate вообще ничего из Snake не задействует - его можно наружу вывести, но это, наверно, еще в разработке. Не надо без крайней необходимости создавать усложненную структуру зависимостей классов. Решите, какой класс будет более важным, и пусть не ему передается второй класс, а второй класс наоборот дергает какие-то его методы.
    Ответ написан
    1 комментарий
  • Фабричный метод. Как создать рефлексивно по имени поля класс, наследуемый от абстрактного?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    В С++ рефлексии нет. Только ручками. Где-то придется писать список всех классов и по всем им пробегаться и сравнивать строку. Ну или map какой-то создать. В качестве ключа вставлять команду, в качестве значения - функцию создающую объект конкретного класса.

    Как вариант, можно как-то упростить себе работу с помощью шаблонной магии. Шаблон будет принимать список всех классов, сравнивать первый с заданной командой и или рекурсивно вызваться дальше или создавать объект текущего класса.

    Пример можно посмотреть вот тут. Там CreateEncoderInternal делает практически то, что вам надо. Только там не константное поле command проверяется, а проверяется, что заданный формат есть в статическом списке в текущем классе.

    И все-равно где-то в коде надо прописать список всех возможных классов, как тут.
    Ответ написан
    Комментировать
  • Зачем нужен отдельный синтаксис для препроцессора?

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

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

    Еще одна причина - это кросс-платформенный код. Ну вот вызов какой-то функции winapi просто не скомпилируется под linux, потому что ее там тупо нет. Значит надо сказать компилятору вот тот кусок вообще игнорировать. Если это делается на том же этапе, что и сама компиляция, да и с тем же синтакисом, то возникает проблема - в синтаксисе-то ошибка под linux. Как-то разбираться, что эта ошибка не критичская и весь кусок кода можно тупо выкинуть - это компилятору сложно, да и опасно это. Поэтому нужен именно какой-то предварительный этап, который не может использовать тот же самый синтаксис.
    Ответ написан
    Комментировать
  • [OpenGL]Почему получается такая фигура?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Вы точно этот код запустили? Пока очень похоже, что просто одна вершина не рисуется в коде.
    Ответ написан
  • [OpengGL] Почему вращается ось, а не фигура?

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

    Если хотите вращать только фигуру, то сначала через glTranslate перенесите ее центр в ноль, потом вращайте и задавайте координаты вершин (относительно центра!).
    Ответ написан
    9 комментариев
  • Как подключить файл?

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

    В хедере вы декларируете функцию и включаете этот хедер в начало вашего С++ файла, приведенного в вопросе.
    Другой С++ файл будет реализовывать функцию (и тоже включать хедер). Потом какая-то система сборки или IDE скомпилирует оба файла и соберет из получившихся объектных файлов одну dll-ку. Или вы руками скомпилируете каждый из двух C++ файлов и потом отдельным вызовом слинкуете все.

    Вы, видимо, предполагаете просто тупо написать код функции в файле и включить его в тело функции через #include. Вообще говоря, это даже скомпилируется, но это такой лютый говнокод получается, что так делать никогда и ни при каких обстоятельствах нельзя. Сообщения об ошибках будут со съехавшими номерами строк, сам файл с кодом будет некорректным С++ кодом, поэтому любой редактор не сможет вам ни подстветить его, ни понять какие там есть штуки, чтобы показывать их вам в подсказках. Такой подход не обобщается на более чем пару файлов - вы потом сами запутаетесь что где и куда включено.
    Ответ написан
    Комментировать
  • Здравствуйте, почему возникает ошибка?

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

    Похоже get_parent возвращает ссылку на unique_ptr. По-моему тут лучше возвращать сырой указатель или ссылку на объект. зачем вам тут unique_ptr вообще?

    Но, игнорируя дизайн, ссылка на unique_ptr в принципе будет работать. Проблема в том, что auto не выводит ссылочность. Поэтому переменная parent становится просто unique_ptr, который конструируется из ссылки копированием. Поэтому если вы напишите auto& parent = то все должно заработать.

    Вторая ошибка - .обращается к методам и полям класса unique_ptr, ведь переменная parent имеет тип unique_ptr<>. Чтобы обратиться к методам/полям хранимого класса надо использовать ->.
    Ответ написан
  • Почему один код выполняется быстрее другого C++?

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

    Первый вариант отбрасывает дробные части от копеек, а второй отбрасывает дробные части от рублей. Ведь при делении на 100 в целых числах идет округление вниз. Если брать p процентов с округлением вниз от числа в рублях, то и получится целое число в рублях. Если брать от числа в копейках, то и получится целое число в копейках.

    Поскольку второй код отбрасывает все копейки при прибавлении, то ему требуется больше итераций, чтобы дойти до y. На самом деле он может даже виснуть, если там получается прибавление 0.
    Ответ написан
    1 комментарий
  • Как ускорить работу скрипта?

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

    Ну или можно использовать std::unordered_map<std::string, int> вместо trie.
    Ответ написан
  • Почему возникает проблема "terminate called after throwing an instance of 'char const*'"?

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

    Обрабатывайте исключения (конструкция try..catch) где-нибудь в main, тогда можно будет вывести сообщение с ним связанное. Может станет понятнее, откуда оно было брошено. Или можно просто пискать в коде "throw" - скорее всего оно и срабатывает.
    Ответ написан
    Комментировать
  • Почему возникает ошибка?

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

    По второй ошибке: попробуйте написать LinearNavigation<T>::haveNext() там, где оно вызывается в isFullyConnectedQuad.

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

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

    Подозреваю, что ошибка исправится, если в for сделать item ссылкой.
    Ответ написан
    1 комментарий
  • Как передать массив вместо аргументов?

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

    Если вы хотите передавать массив, то поменяйте функцию f так, чтобы она его принимала.

    void f(const std::vector<int> &arg){
    }
    f({1,2,3});


    И да, массив не в квадратных скобках задается, а в фигурных.
    Передача по ссылке, чтобы не копировать эти все значения лишний раз. Для трех элементов погоды почти не делает, но если их 100, или тем более 1000 - это заметная оптимизация. const, чтобы можно было передавать временные объекты. Плюс так понятно, что это аргументы входные и вы их менять в функции не будете.
    Ответ написан
  • Как получить ввод c++ для задачи по спортивному программированию?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Число q, судя по тексту, уже дано вам в файле.
    Поэтому просто циклом q раз читайте команду.
    Там читайте одно число, и если это 1, то читайте i, x. Если это 2 - то читайте k.

    for (int line = 0; line < q; ++line) {
      cin >> command;
      if (command == 1) {
        int i, x;
        cin >> i >> x;
        UpdateValue(i, x);
      } else {
        int k;
        cin >> k;
        ShiftRight(k);
      }
    }
    Ответ написан
    3 комментария
  • Можете покритиковать мой код?

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

    2) обилие вложенных if. Практикуйте ранний выход. Например в Login() можно сделать так:
    if (Data.is_open()) {
      std::cout << "Ошибка. У вас нет аккаунта" << std::endl;
      return;
    }


    И весь оставшийся код оказывается на 1 уровень выше.

    3) Бесконечные рекурсивные вызовы - это плохо. Рано или поздно программа упадет с закончившимся стеком.
    У вас Menu вызывает Login, который опять вызывает Menu. Да и сам Menu тоже.

    Лучше сделать в Menu бесконечный цикл (while(true)) и или выходить из программы через exit(), или возвращать из Login, что надо завершаться и тогда в Menu делать break.
    Ответ написан
    1 комментарий
  • Для чего в C++ сделано описание методов вне класса?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    Это пошло еще из Си. Абсолютно тот же механизм, что используется для глобальных переменных и функций. Более того в ранних версиях Си надо было всегда отдельно объявлять функцию и отдельно ее определять.

    Используется для этих вещей:
    1) Можно иметь "циклические зависимости". Например, функция использует класс, а класс использует функцию. Или два класса используют друг друга. В каком порядке их определять в файле? Так уж повелось, что компилятору надо как-то знать о всех используемых в коде штуках до их использования (в основном). Возможность отдельно объявить функцию/класс как раз решает эту проблему. Можно было бы переделать весь компилятор, чтобы он сначала по всему файлу искал функции, но по каким-то, возможно веским, причинам это не было сделано еще в Си. А C++ потащил и это с собой.

    2) Разделение программы на "модули" или библиотеки. Этот ужасный, устаревший и неудобный механизм include-ов позволяет разбить программу на хедеры и файлы с реализацией. Потом хедеры только с объявлениями включаются в другие файлы, чтобы компилятор знал о коде в других модулях, а реализация собирается в отдельный объектный файл. В конце линкер собирает все объектные файлы в исполняемый файл и/или библиотеки. Если бы объявления и определения не были разделены, то весь код в проекте компилировался бы кучу раз в каждом объектном модуле. Это просто глупо.

    3) И вообще - это красиво. Иметь где-то аккуратный список всех методов класса (или функций в библиотеке) удобно, когда вам надо разобраться, а что этот класс делает и как его использовать. Если бы там еще и код методов был, то это было бы сложнее читать.
    Ответ написан
    Комментировать
  • STD::set erase не работает?

    wataru
    @wataru Куратор тега C++
    Разработчик на С++, экс-олимпиадник.
    У вас в set хранятся указатели на char. В set они сравниваются как указатели. Как значения адресов. Strcmp же смотрит на содержимое памяти, на которую указатели ссылаются. Поэтому имея в памяти две совпадающие строки вы получите вот это вот - указатели не равны, а strcmp - равно.
    Ответ написан
    Комментировать