Как правильно использовать strtok в C, чтобы не было утечки памяти? - PullRequest
11 голосов
/ 15 февраля 2011

Меня несколько смущает то, что происходит, когда вы вызываете strtok для указателя на символ в C. Я знаю, что он изменяет содержимое строки, поэтому, если я вызову strtok для переменной с именем 'line', ее содержимое изменится. Предположим, я следую нижеприведенному подходу:

void function myFunc(char* line) {

    // get a pointer to the original memory block
    char* garbageLine = line;

    // Do some work
    // Call strtok on 'line' multiple times until it returns NULL
    // Do more work

    free(garbageLine);
}

Далее предположим, что строка lineloced перед передачей в myFunc. Должен ли я освободить исходную строку после использования strtok или она нам подходит? Кроме того, что произойдет, если строка 'line' не является неправильной, и я попытаюсь использовать вышеуказанную функцию? Вместо этого безопаснее делать следующее? (Предположим, что программист не будет звонить бесплатно, если он знает, что строка не является неправильной)

Воззвание

char* garbageLine = line;
myFunc(line);
free(garbageLine);

Определение функции

void function myFunc(char* line) {
    // Do some work
    // Call strtok on 'line' multiple times until it returns NULL
    // Do more work
}

Ответы [ 5 ]

9 голосов
/ 15 февраля 2011

strtok () ничего не освободит, так как не знает, где хранится строка. Это могло быть в стеке или куче, это не знает или не заботится! :)

Безопаснее ли делать следующее?

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

Дальнейшее чтение: strtok ()

4 голосов
/ 15 февраля 2011

В комментарии к вашему вопросу вы говорите, что вы "вызываете strtok на 'line' несколько раз, пока он не вернет NULL" Это звучит так, как будто вы используете strtok неправильно. В первый раз, когда вы вызываете это, вы должны вызывать это с 'line' в качестве аргумента; при последующих вызовах вы должны передать его NULL. В качестве примера возьмем следующее:

void function myFunc(char* line) {
  char *segment; // This will point at each delimited substring in turn.

  segment = strtok(line, " ");

  // Do something with segment.

  segment = strtok(NULL, " ");

  // Do something with the new segment.

  free(line);
}

Однако, как сказал DrTwox, ваш второй пример лучше - «строка» должна быть освобождена тем же контекстом, который неправильно ее (или нет), так что вызов free () не принадлежит этой функции. И вам лучше зацикливаться - что-то вроде:

void function myFunc(char* line) {
  char *segment;

  segment = strtok(line, " ");

  while (segment != NULL) {
    // Do something with segment.

    segment = strtok(NULL, " ");
  }
}

Вызов такой:

char *line = malloc(20*sizeof(char));

// Check that malloc succeeded here.
// Put some data into 'line'.

myFunc(line);

free(line);

// No 'garbageLine' required.

Способ работы strtok немного сложен для объяснения, но у вас есть важные части - он не выделяет и не освобождает память. Вместо этого он работает путем изменения строки, которую вы ему передали.

1 голос
/ 12 апреля 2019

Стоит объяснить, что strtok выполняет свою работу:

  1. возвращение указателей, которые указывают на исходную строку; и

  2. замена каждого символа разделителя, который он находит, на NULL.

Таким образом, все на месте, и ему не нужно выделять память.

1 голос
/ 15 февраля 2011

strtok освобождает память не больше, чем strlen.Почему вы ожидаете этого?Какую память это освободит?Возможно, вы думаете, что strtok нужно освободить память, потому что она хранит NUL, но содержимое памяти не имеет значения.Когда вы выделяете память, распределитель отслеживает размер выделенного блока, и весь блок освобождается при его освобождении.

0 голосов
/ 15 февраля 2011

Какое это имеет отношение к strtok()? Если вы выделяете память, вам нужно освободить ее. Где ваше приложение решает выделить и освободить память, зависит от вас. Но если вы передаете память в strtok(), это не имеет значения, если или когда память выделена или освобождена.

...