Ниже я использую термин needle
, означающий аргумент sub
, переданный функции replace_str
.
unsigned long new_len = strlen(str) + (len_rep - len_sub) * count_substring(str, sub) + 1;
str = REALLOC(str, new_len, char);
len_rep
равен strlen("\n")
, поэтому 1
.
len_sub
равно strlen("\n\n")
, то есть 2
.
То есть (len_rep - len_sub)
равно -1
, поэтому оно равно:
unsigned long new_len = strlen(str) + (-1) * count_substring(str, sub) + 1;
Предполагается, что count_substring
делает то, что говоритда, вы realloc
делаете строку меньшего размера, даже не обращаясь к ней, поэтому вы аннулируете все байты после new_len
. Это означает, что если строка "\n\n\n\n\n\n\n\n\n\n"
, а needle - "\n\n"
, существует 5 таких последовательностей, вы просто перераспределяете строку на 6 байтов. Таким образом, результирующий массив составляет всего 6
байтов \n
: {'\n,'\n','\n','\n','\n','\n'}
. Все байты после индекса 5 являются недопустимыми, и доступ к ним является неопределенным поведением. Valgrind точно ошибается, когда вы обращаетесь к байтам после выделенной памяти:
==896== Address 0x522d096 is 0 bytes after a block of size 6 alloc'd
==896== at 0x4C31D2F: realloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
Что вы должны сделать, это если строка замены короче стрелки, переместить realloc после цикла. Если замена длиннее, чем стрелка, сделайте realloc перед циклом.
if (len_rep > len_sub) {
// WE NEED MORE PLACE
const size_t new_len = strlen(str) + (len_rep - len_sub) * count_substring(str, sub) + 1;
str = REALLOC(str, new_len, char);
if (str == NULL) abort();
}
while (strstr(str, needle)) {
// your loop is here
}
if (len_rep < len_sub) {
// WE NEED LESS PLACE
const size_t new_len = strlen(str) + (len_rep - len_sub) * count_substring(str, sub) + 1;
str = REALLOC(str, new_len, char);
if (str == NULL) abort();
}
Примечания:
- Не забудьте проверить наличие ошибок выделения.
- Objectразмер и длина строки представлены с использованием типа
size_t
. - Ваша функция работает странно. Нет необходимости делать
malloc
внутри while
, вам не нужна временная строка. Просто memove
части строки, которые вы должны сохранить. И memcpy
иголка внутри струны там, где она вам нужна. Прямо как while (str = strstr(str, needle), str) { memmove( <move str forth or back depending if len_rep is greater or smaller or equal to len_sub> ); memcpy(str, needle, strlen(needle)); str += strlen(needle); }
.