Почему я получаю двойную бесплатную ошибку с перевыделением ()?

import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)
14
задан Kirill Kobelev 9 January 2017 в 20:33
поделиться

7 ответов

Как правило Вы никогда не должны делать свободного или перевыделения на пользователе, предоставленном буферу. Вы не знаете, где пользователь выделил место (в Вашем модуле, в другом DLL), таким образом, Вы не можете использовать ни одну из функций выделения на пользовательском буфере.

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

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

Получающийся в:

void  strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void  strrepmfree(char *input);
13
ответ дан 1 December 2019 в 06:32
поделиться

Прежде всего извините я опаздываю стороне. Это - мой первый ответ stackoverflow.:)

Как был указан, когда перевыделение () называют, можно потенциально изменить указатель на перераспределяемую память. Когда это происходит, аргумент "строка" становится недопустимым. Даже при переприсвоении его изменение выходит из объема, после того как функция заканчивается.

Для ответа на OP перевыделение () возвращает указатель на недавно перераспределенную память. Возвращаемое значение должно быть сохранено где-нибудь. Обычно Вы сделали бы это:

data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));

/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
   foo = bar;
   bar = NULL;
}
else
{
   fprintf(stderr, "Crap. Memory error.\n");
   free(foo);
   exit(-1);
}

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

void foobar(char *input, int newlength)
{
   /* Here, I ignore my own advice to save space. Check your return values! */
   input = realloc(input, newlength * sizeof(char));
}

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

Вы могли использовать двойной указатель для входа, как это:

void foobar(char **input, int newlength)
{
   *input = realloc(*input, newlength * sizeof(char));
}

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

Я думаю, что самое чистое решение здесь состоит в том, чтобы избегать использования перевыделения () при попытке изменить вход функциональной вызывающей стороны. Просто malloc () новый буфер, возвратите это и позвольте вызывающей стороне решить, освободить ли старый текст. Это обладает дополнительным преимуществом разрешения вызывающей стороне сохранить исходную строку!

11
ответ дан 1 December 2019 в 06:32
поделиться

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

input = realloc(input, strlen(input) + delta);
6
ответ дан 1 December 2019 в 06:32
поделиться

Это, кажется, работает;

char *strrep(char *string, const char *search, const char *replace) {
    char *p = strstr(string, search);

    if (p) {
        int occurrence = p - string;
        int stringlength = strlen(string);
        int searchlength = strlen(search);
        int replacelength = strlen(replace);

        if (replacelength > searchlength) {
            string = (char *) realloc(string, strlen(string) 
                + replacelength - searchlength + 1);
        }

        if (replacelength != searchlength) {
            memmove(string + occurrence + replacelength, 
                        string + occurrence + searchlength, 
                        stringlength - occurrence - searchlength + 1);
        }

        strncpy(string + occurrence, replace, replacelength);
    }

    return string;
}

Вздохните, там так или иначе к почтовому индексу без него всасывание?

3
ответ дан 1 December 2019 в 06:32
поделиться

Отметьте, попытайтесь отредактировать свой код для избавлений от управляющих кодов HTML.

Ну, хотя это было некоторое время, так как я использовал C/C++, перевыделение, которое растет только, снова использует значение указателя памяти, если существует комната в памяти после Вашего исходного блока.

Например, рассмотрите это:

(xxxxxxxxxx..........)

Если Ваш указатель указывает на первый x, и. местоположение свободной памяти средств, и Вы выращиваете емкость памяти, на которую указывает Ваша переменная на 5 байтов, это успешно выполнится. Это - конечно, упрощенный пример, поскольку блоки окружены к определенному размеру для выравнивания, но так или иначе.

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

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

Это значение указателя, однако, было освобождено.

В Вашем случае вход является преступником.

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

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

4
ответ дан 1 December 2019 в 06:32
поделиться

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

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

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

Каковы проблемы? Ну, Вы передаете буфер перевыделению (), и перевыделение () возвращает Вас новый указатель на область, которую необходимо использовать - и Вы игнорируете то возвращаемое значение. Следовательно, перевыделение (), вероятно, освободило исходную память, и затем Вы передаете его тот же указатель снова, и это жалуется, что Вы освобождаете ту же память дважды, потому что Вы передаете исходное значение ему снова. Это не только пропускает память, но и означает, что Вы продолжаете использовать исходное пространство - и выстрел в темноте John Downey указывает на неправильное использование перевыделения () но не подчеркивает, как сильно Вы делаете так. Существует также ошибка диапазона, потому что Вы не выделяете достаточно места для NUL '\0', который завершает строку.

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

Ваш код также не защищает от неопределенного роста - считают замену 'Noel' со 'Счастливого Рождества'. Каждый раз Вы добавили бы 7 символов, но Вы найдете другого Noel в замененном тексте и развернете его и т. д. и т. п. Мой fixup (ниже) не решает эту проблему - простое решение состоит в том, чтобы, вероятно, проверить, появляется ли строка поиска в строке замены; альтернатива должна перескочить через строку замены и продолжить поиск после него. Второе имеет некоторые нетривиальные проблемы кодирования для обращения.

Так, мой предложенный пересмотр Вашей вызванной функции:

char *strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while ((find = strstr(find, search)) != 0) {
        if (delta > 0) {
            input = realloc(input, strlen(input) + delta + 1);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) + 1 - (find - input));
        memmove(find, replace, replaceLen);
    }

    return(input);
}

Этот код не обнаруживает ошибки распределения памяти - и вероятно отказывает (но в противном случае пропускает память), если перевыделение () перестало работать. Посмотрите, что Steve Maguire 'Пишет Основательный Код' книга для обширного обсуждения проблем управления памятью.

6
ответ дан 1 December 2019 в 06:32
поделиться

Мои быстрые подсказки.

Вместо:
void strrep(char *input, char *search, char *replace)
попытка:
void strrep(char *&input, char *search, char *replace)

и, чем в теле:
input = realloc(input, strlen(input) + delta);

Обычно читайте о передаче аргументов функции как значения/ссылка и перевыделение () описание :).

0
ответ дан 1 December 2019 в 06:32
поделиться
Другие вопросы по тегам:

Похожие вопросы: