Контакты

Достижения

Все достижения (9)

Наибольший вклад в теги

Все теги (54)

Лучшие ответы пользователя

Все ответы (85)
  • Лишние символы в c++, откуда?

    Во-первых, new char выделит память только для одного символа, а у вас их много. То есть уже в следующей строке (cin >> array) проезд по памяти. Если пишете в целях обучения и нельзя брать std::string, то выделяйте с запасом, например new char[256]; Освобождать при этом память надо будет при помощи delete[] array;
    Во-вторых, конец строки определяется по нулевому символу на конце. cin >> array делает это сам (пишет в конец array нулевой символ), а вы в своей функции нулевой символ не выставляете. Сделать это можно так:
    str[length_str] = '\0';
    Но надо иметь в виду, что памяти надо выделить [хотя бы] на 1 больше, чем length_str.

    Итого:
    1. Вам надо в обоих случаях память выделять под массив. В первом случае можно под 256 элементов. В идеале при этом читать не при помощи cin, а другими функциями, дабы избежать переполнения на случай, если введут строку более длинную.
    2. В reverse надо выставлять терминирующий нуль и исправить длину массива. Возможно вообще разворачивать строку по месту, т.е. менять местами буквы, а не создавать новую строку (в этом случае не надо ни память выделять, ни трогать терминирующий нуль, он останется на месте).
    3. Вам надо удалять выделенную память по окончании использования при помощи delete []
    Ответ написан
    2 комментария
  • В чем отличие промисов от монад?

    Promise - одна из монад, где bind (>>=), упрощённо, из обещания и из последующей функции делает новое обещание, которое дожидается выполнения первого обещания и передаёт результат в следующую функцию. В итоге управление в вызывающую функцию возвращается на первом же ожидании.

    Но монады есть и другие. Например Either, позволяющий выдать "ошибку", т.о. обрывая всю цепь вычислений на первой же ошибке. Или Maybe, ведущий себя аналогично Either, но не с возвратом какого-то ошибочного значения, а просто с остановкой на первом фейле. Список - тоже монада, там последующая функция будет вычислена на каждом элементе, а результате сконкатенированы.
    Ответ написан
    Комментировать
  • Как сделать перебор всех возможных комбинаций из символов?

    Напрашивается вариант представить результирующие строки записями в N-ричной системе счисления, где заданные буквы есть цифры от 0 до N-1, тогда задача сводится к выводу однозначных чисел от 0 до N-1, двузначных от 0 до N²-1, трёхзначных от 0 до N³-1. Запись в N-ричной системе легко получить, используя остаток от деления и деление.

    #include <vector>
    
    std::string gen(std::vector<char> alphabet, std::size_t idx, std::size_t digits)
    {
    	std::string ret(digits, alphabet[0]);
    
    	std::size_t alphas = alphabet.size();
    	while (digits--)
    	{
    		ret[digits] = alphabet[idx % alphas];
    		idx /= alphas;
    	}
    	return ret;
    }
    
    void gen_and_out(std::size_t n, std::vector<char> alphabet)
    {
    	std::size_t numbers = 1;
    	std::size_t alphas = alphabet.size();
    	for (std::size_t i = 0; i < n; ++i)
    	{
    		numbers *= alphas; // на каждом шаге чисел в alphas раз больше
    		for (std::size_t cur = 0; cur < numbers; ++cur)
    		{
    			std::cout << gen(alphabet, cur, i + 1) << std::endl;
    		}
    	}
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	gen_and_out(3, std::vector<char>({ 'a', 'b', 'c'}));
    }


    Второй вариант - это представить эти строки как запись числа в особой системе счисления без нуля - с цифрами от 1 до N. В этом случае легко преобразовать такую запись в число - ∑aᵢ×Nⁱ, а вот обратное преобразование должно учитывать, что у нас нет нуля, тогда если остаток получился равным нулю, цифру нужно взять N.
    В отличие от первого варианта, здесь нет отдельных циклов для однозначной, двузначной и трёхзначных записей, так как результаты идут подряд, за "c" следует "aa", за "cc" - "aaa", и так далее.

    #include <vector>
    
    std::string gen(std::vector<char> alphabet, std::size_t idx)
    {
    	std::vector<char> ret;
    
    	std::size_t alphas = alphabet.size();
    
    	while (idx)
    	{
    		std::size_t cur = idx % alphas;
    		if (!cur) // нет нуля
    			cur = alphas;
    		ret.push_back(alphabet[cur - 1]);
    		idx = (idx - cur) / alphas;
    	}
    
    	return std::string(ret.rbegin(), ret.rend());
    }
    
    void gen_and_out(std::size_t n, std::vector<char> alphabet)
    {
    	std::size_t numbers = 1;
    	std::size_t alphas = alphabet.size();
    	for (std::size_t i = 0; i < n; ++i)
    	{
    		numbers *= alphas;
    		numbers += 1;
    	}
    	for (std::size_t i = 1; i < numbers; ++i)
    		std::cout << gen(alphabet, i) << std::endl;
    }
    
    int _tmain(int argc, _TCHAR* argv[])
    {
    	gen_and_out(3, std::vector<char>({ 'a', 'b', 'c' }));
    }


    На закуску, как та же задача решается на Haskell:
    gen alphas n = concatMap (`replicateM` alphas) [1..n]
    main = mapM_ putStrLn $ gen "abc" 3
    Ответ написан
    Комментировать
  • Как создать композицию функции на саму себя?

    Функция применяется n + 1 раз к n. Для этого надо список из n + 1 функций f свернуть при помощи композиции, а затем применить к аргументу. Добавим ещё fromIntegral, так как в примерах у вас синусы, которым нужно число с плавающей точкой, а n же у вас - целое (функцию можно применить только целое кол-во раз).

    execute f n = foldr1 (.) (replicate (succ n) f) (fromIntegral n)


    где replicate (succ n) f - список из n + 1 функций f, foldr1 (.) - свёртка списка композицией

    Есть и второй вариант, не сворачивать n + 1 функций f через композицию, а сворачивать список, на каждом шаге сразу применяя к аргументу, т.е. так:

    execute f n = foldr ($) (fromIntegral n) (replicate (succ n) f)


    где ($) - функция применения, т.е. f $ x = f x
    Ответ написан
    Комментировать
  • Как получить указатель на метод объекта?

    Можно
    Если напрямую, то надо использовать тип "указатель на функцию член" вида Ret (Class::*)(Args...) [const]. Сам указатель получать &Class::Fun, а вызывать операторами .* или ->*
    Или использовать std::function (boost::function), std::bind (boost::bind) или std::mem_fun, std::mem_fn для более унифицированного подхода:

    struct some
    {
    	some() : value(0) {}
    
    	int inc() { return ++value; }
    	int dec() { return --value; }
    	int get() const { return value; }
    
    	int value;
    };
    
    int main()
    {
    	some s;
    
    	int (some::*inc_f)() = &some::inc; // inc_f - указатель на функцию
    	std::cout << "(s.*inc_f)() = " << (s.*inc_f)() << std::endl; // оператор .* - оператор вызова по указателю на функцию
    	int (some::*val_ptr) = &some::value; // val_ptr - указатель на член
    	s.*val_ptr = 10;
    	std::cout << "s.*val_ptr = " << s.*val_ptr << std::endl;
    
    	int (some::*const_f)() const = &some::get; // const-функция
    	std::cout << "s.*const_f() = " << (s.*const_f)() << std::endl;
    
    	using namespace std::placeholders;
    	std::function<int (some&)> mem_f;
    	
    	mem_f = std::bind(&some::inc, _1); // биндим на функцию-член, _1 - placeholder для объекта
    	std::cout << "mem_f(s) = " << mem_f(s) << std::endl; // s.inc();
    	mem_f = std::mem_fn(&some::dec); // другой способ через mem_fn
    	std::cout << "mem_f(s) = " << mem_f(s) << std::endl; // s.dec();
    
    	std::function<int()> mem_f_ = std::bind(&some::inc, &s); // биндим на функцию член и сразу указываем объект, получаем функцию без аргументов
    	std::cout << "mem_f_() = " << mem_f_() << std::endl; /// s.inc();
    
    	std::function<int(some const &)> const_fn = std::mem_fn(&some::get); // some const &
    	std::cout << "const_fn(s) = " << const_fn(s) << std::endl;
    
        return 0;
    }
    Ответ написан
    Комментировать