Строка, выделенная в куче, повреждается при доступе за пределами функции C

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

В приведенном ниже коде у меня есть функция GetFileContents, которая извлекает содержимое файла с именем first_page.html в динамически выделяемую строку, а затем возвращает указанную строку. Эта функция работает правильно и не вызывает никаких проблем. StrReplaceSubstringFirstOccurance заменит указанную мной подстроку новой строкой, а также распечатает ее вывод и префикс Inside:. В операторе if, где я проверяю, больше ли строка, которую я заменяю, чем подстрока, у меня есть два разных подхода к изменению размера строки. Подход 2 использует realloc, а подход 1 предполагает выделение новой строки с помощью malloc, копирование содержимого исходной строки в новую строку, вызов free для исходной строки и затем создание указателя на исходную строку, указывающего на новую строку. Оба подхода создают одну и ту же проблему. Как вы можете видеть в выводе, первые два вызова StrReplaceSubstringFirstOccurance работают успешно, однако третий вызов функции (подстрока — [[to]], а строка, на которую нужно заменить — NOT CUSTOM!), внутри функции функция печатает правильную строку, однако, когда я пытаюсь распечатать строку вне функции, она показывает мусорные символы. При четвертом вызове функции функция распознает, что в исходной строке больше нет вхождений подстроки (поскольку исходная строка теперь содержит мусорные символы), и поэтому она просто выходит из функции, а мусорные символы в исходной строке все еще остаются. оставайся там.

Код:

static bool StrReplaceSubstringFirstOccurance(char* source, char* substring, char* replace) {
    char* substring_occurance = strstr(source, substring);
    if (substring_occurance == NULL) {
        printf("No substring: %s found.\n", substring);
        return false;
    }

    if (strlen(replace) > strlen(substring)) {
        size_t new_size = strlen(source) + (strlen(replace)-strlen(substring))+1;
        // Approach 1
        // char* temp = malloc(new_size);
        // memcpy(temp, source, strlen(source)+1);
        // free(source);
        // source = temp;

        // Approach 2
        source = realloc(source, new_size);
    }

    substring_occurance = strstr(source, substring);
    memmove(substring_occurance + strlen(replace),
            substring_occurance + strlen(substring),
            strlen(substring_occurance) - strlen(substring)+1);
        
    memcpy(substring_occurance, replace, strlen(replace));
    printf("\nInside: %s\n", source);
    return true;
}

int main(void) {
    char* first_page = GetFileContents("first_page.html");

    StrReplaceSubstringFirstOccurance(first_page, "[[say]]", "CUSTOM!");
    StrReplaceSubstringFirstOccurance(first_page, "[[say]]", "CUSTOM!");
    printf("\nFirst Print: %s\n", first_page);
    StrReplaceSubstringFirstOccurance(first_page, "[[to]]", "NOT CUSTOM!");
    printf("\nSecond Print: %s\n", first_page);
    StrReplaceSubstringFirstOccurance(first_page, "[[to]]", "NOT CUSTOM!");
    printf("\nThird Print: %s\n", first_page);

    printf("Reached the end!\n");
    return 0;
}

Выход:

Inside: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Inside: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

First Print: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Inside: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! NOT CUSTOM!</title>
  <body>
    CUSTOM!
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

Second Print: α#F^Ñ☻
No substring: [[to]] found.

Third Print: α#F^Ñ☻
Reached the end!

первая_страница.html

<!DOCTYPE html>
<html lang = "en-US">
  <title>[[say]] [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
  </body>
</html>

вам нужно static bool StrReplaceSubstringFirstOccurance(char** source, ..., чтобы перераспределенный source отразился в main() ... и, конечно, измените на StrReplaceSubstringFirstOccurance(&first_page, "[[say]]", "CUSTOM!"); внутри main()

pmg 21.07.2024 20:25

Спасибо, это сработало! Я передал &first_page вместо first_page в StrReplaceSubstringFirstOccurance, а затем разыменовал source на один уровень всякий раз, когда использовал его в функции. Не могли бы вы написать более подробный ответ, почему это работает, поскольку я не могу понять это. Поскольку в этом случае first_page и source указывают на одну и ту же память, почему функция работает только тогда, когда я передаю в нее указатель на first_page (т. е. &first_page), а не просто передаю first_page в нее напрямую.

Ali Awan 21.07.2024 20:36

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

pmg 21.07.2024 20:41

Без дополнительной косвенности, когда вы меняете source внутри своей функции (с помощью realloc())... переменная first_page в main() не меняется. Они начинаются одинаково, но в какой-то момент могут стать разными.

pmg 21.07.2024 20:43

Тогда почему first_page изменился правильно после первых двух вызовов StrReplaceSubstringFirstOccurance?

Ali Awan 21.07.2024 21:03

Вероятно, Realloc не изменил адрес source. Память можно увеличить, но базу оставить на том же месте.

pmg 21.07.2024 21:05

Спасибо, есть ли у вас рекомендуемые ресурсы, где я могу узнать об этом?

Ali Awan 21.07.2024 21:18

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

pmg 21.07.2024 21:26

Давайте продолжим обсуждение в чате.

Ali Awan 22.07.2024 13:24
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Введение в CSS
Введение в CSS
CSS является неотъемлемой частью трех основных составляющих front-end веб-разработки.
Как выровнять Div по центру?
Как выровнять Div по центру?
Чтобы выровнять элемент <div>по горизонтали и вертикали с помощью CSS, можно использовать комбинацию свойств и значений CSS. Вот несколько методов,...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Ангулярный шаблон для бронирования путешествий
Toor - Travel Booking Angular Template один из лучших Travel & Tour booking template in the world. 30+ валидированных HTML5 страниц, которые помогут...
2
9
73
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Мне удалось это исправить, следуя комментариям pmg. Я передал указатель на переменную file_path в функцию StrReplaceSubstringFirstOccurance. Новый код выглядит следующим образом:

static bool StrReplaceSubstringFirstOccurance(char** source, char* substring, char* replace) {
    char* substring_occurance = strstr(*source, substring);
    if (substring_occurance == NULL) {
        printf("No substring: %s found.\n", substring);
        return false;
    }

    if (strlen(replace) > strlen(substring)) {
        size_t new_size = strlen(*source) + (strlen(replace)-strlen(substring))+1;
        *source = realloc(*source, new_size);
    }

    substring_occurance = strstr(*source, substring);
    memmove(substring_occurance + strlen(replace),
            substring_occurance + strlen(substring),
            strlen(substring_occurance) - strlen(substring)+1);
        
    memcpy(substring_occurance, replace, strlen(replace));
    printf("\nInside: %s\n", *source);
    return true;
}

int main(void) {
    char* first_page = GetFileContents("first_page.html");
    StrReplaceSubstringFirstOccurance(&first_page, "[[say]]", "CUSTOM!");
    printf("\nFirst Print: %s\n", first_page);
    StrReplaceSubstringFirstOccurance(&first_page, "[[to]]", "NOT CUSTOM!");
    printf("\nThird Print: %s\n", first_page);

    printf("Reached the end!\n");
    return 0;
}

И результат:

Inside: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
      [[say]][[to]]
  </body>
</html>

First Print: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! [[to]]</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
      [[say]][[to]]
  </body>
</html>

Inside: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! NOT CUSTOM!</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
      [[say]][[to]]
  </body>
</html>

Third Print: <!DOCTYPE html>
<html lang = "en-US">
  <title>CUSTOM! NOT CUSTOM!</title>
  <body>
    [[say]]
      <h1>This is a header!</h1>
      [[to]]
      [[say]][[to]]
  </body>
</html>
Reached the end!

Рад, что смог помочь. Это выглядит мило.

pmg 22.07.2024 14:47

Другие вопросы по теме