Это не имеет никакого отношения к выделению памяти как таковой.
Проблема в этих строках
int zerosneeded = length - tmp.size();
while (zerosneeded != 0) {
tmp.push_back(0);
zerosneeded--;
}
, не зная, почему он делает то, что делает, у меня возникает вопрос, глядя на код: «Может ли zerosneeded
быть меньше нуля?». Тем более что zerosneeded
определяется как int
вместо unsigned int
(применимо к остальной части кода).
Если значение нуля меньше нуля, будет бесконечный цикл распределения до исчерпания. Быстрая проверка подтверждает это:
int zerosneeded = length - tmp.size();
if(zerosneeded < 0)
{
std::cout << "fatal, zerosneeded < 0 \n";
throw std::runtime_exception("fatal, zerosneeded < 0");
}
Надеюсь, это поможет в вашей отладке.
Редактировать
Относительно того, почему нули нужны, является отрицательным:
, во-первых, вычисляется количество возможностей, которое является длиной символов.
int possibilities = std::pow(symbols, length);
при отправке значений в tmp мы в основном находим первый x такой, что длина ^ x> частное. Частное находится в диапазоне [0, символы ^ длина] и используется push-значениями в tmp.
int quotient = i;
while (quotient!=0) {
tmp.push_back(quotient % length);
quotient = quotient / length;
}
Если символы ^ длина> длина ^ длина, первый x такой, что длина ^ x> частное, дает x> длину, в результате чего int zerosneeded = length - tmp.size();
становится отрицательным.
Для примера мы имеем длину = 4, символы = 6, поэтому коэффициенты имеют диапазон [0,6 ^ 4] = [0, 1296]. Но уже для 256 мы имеем 4 ^ 4 = 256 => 4 ^ 5> 256, поэтому наш x = 5 => zerosneeded = 4 - 5 = -1.
Это ничего особенного для длины = 4 и символов = 6, и на самом деле должно происходить до тех пор, пока длина < символов.
Имя функции является указателем при использовании как таковое. Это несколько похоже на то, как имя массива является указателем на его первый элемент.
При этом вызов функции через указатель с типом, отличным от фактического прототипа функции (как в вашем примере), является неопределенным поведением. Не делайте этого.
Если преобразованный указатель используется для вызова функции, тип которой не совместим с указанным типом, поведение не определено.
из раздел 6.3. 2.3 стандарта С.
Указатель в C - это адрес, то есть число, хранящееся в каком-то месте. Функция в C - это адрес некоторого кода. Эти двое - одно и то же.
Правильный термин - распад . Функция foo
распадается на указатель на foo
перед приведением. Само приведение будет неактивным на всех платформах, о которых я могу подумать.
Тем не менее, обратите внимание, что поведение программы, содержащей такое приведение, не определено стандартом C.
В Си абсолютно ничего. Это просто клей компилятора, чтобы помешать вам сделать что-то глупое. В C вызывающая сторона отвечает за поддержку кадра стека, поэтому приведение необходимо при вызове функции (т.е. аргументы и возвращаемое значение помещаются в стек). Это делает его безопасным (r), поскольку стек вызывающей стороны вряд ли будет изменен неправильно. Однако в некоторых редких случаях вызываемая функция все еще может испортить стек вызывающей стороны.
Я должен пояснить, что назначение копирует указатель функции. Но в C все указатели на функции являются просто указателями. Тип и приведение - все это клей компилятора.
Другое уточнение: Стандарт определяет (в 6.5.2.2), что поведение не определено, если вызывающая сторона использует несовместимые типы. Например, приведение функции, которая возвращает void, к функции, которая возвращает int, и затем вызов этой функции, возвращаемое значение не имеет смысла. Перед вызовом функции рекомендуется преобразовать функцию в совместимый тип, иначе вы можете получить неожиданные результаты.
Это будет комментарий к ответу Рика С. Петти, но он не умещается в 300 символов.
Стандарт C не очень ограничительный - указатели на объекты (и функции не являются объектами) могут быть преобразованы в указатель на void и обратно без проблем. POSIX требует, чтобы указатели на функции имели одинаковый размер и могли быть преобразованы в указатель на void.
Все типы указателей на функции должны иметь то же представление, что и указатель типа на void. Преобразование указателя функции в void * не должно изменять представление. Значение void *, полученное в результате такого преобразования, может быть преобразовано обратно в исходный тип указателя функции, используя явное приведение, без потери информации. Стандарт ISO C не требует этого, но это требуется для соответствия POSIX.