Попытка использовать функцию strtok для создания подстрок и сохранения в массивы

Я хочу получить ввод из строки, затем пройтись по каждой строке и разобрать строку на подстроки, разделив их пробелами. У меня есть цикл while, вложенный в цикл while, чтобы попытаться выполнить эту работу. Когда я печатаю char* в цикле, я получаю ожидаемый результат, но после выхода из цикла и последующей печати другой позиции я получаю неожиданные значения.

while ((getline(&line, &len, fp)) != -1){
    //line is an array of characters
    //piece is a char pointer that stores the sub strings of a line
    //where a string is broken into sub strings by a space
    char *piece = strtok(line, " ");
    while(piece != NULL){
      tokens[j] = piece;
      printf("%s\n", tokens[j]);
      piece = strtok(NULL, " ");
      j++;
    }
  }
  printf("%s\n", tokens[0]);

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

Allan Wind 22.04.2022 20:31

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

nsilent22 22.04.2022 20:33

Это: tokens[j] = piece; присваивает элементу tokens адрес части line буфера. Но затем, в следующем внешнем цикле, вы перезаписываете этот буфер новыми входными данными, поэтому ваши ранее сохраненные указатели, хотя и ссылаются на то же место, указывают на другие данные, чем в предыдущем цикле.

Adrian Mole 22.04.2022 20:33

... что-то вроде tokens[j] = strdup(piece);, вероятно, сработает. Но тогда вам нужно будет просмотреть все жетоны и free() их, когда вы закончите. Но это дубликат, точно...

Adrian Mole 22.04.2022 20:35

Возможный обман: stackoverflow.com/q/61414715/10871073 (это тот, на который я ответил, и, возможно, он не самый лучший.)

Adrian Mole 22.04.2022 20:38

Что вы имеете в виду, говоря, что я «загружаю новые строки данных в тот же буфер, тем самым переопределяя предыдущие значения»?

Hayden Labrie 22.04.2022 20:41

Здесь: getline(&line, &len, fp).

Adrian Mole 22.04.2022 20:43

О, так получается, что getline() заставляет память, в которой находится мой массив токенов, изменять значения, которые хранятся в памяти?

Hayden Labrie 22.04.2022 20:49

Таким образом, в основном массив указывает на один и тот же адрес, но каждый раз, когда я вызываю getline(), я получаю новую информацию, которая заменяет предыдущую информацию в памяти?

Hayden Labrie 22.04.2022 20:57

Допустим, line="bob jane", поэтому, когда вы вызываете strtok() во второй раз, он возвращает &line[4], что является «джейн». Затем вы читаете новую строку, поэтому значение, хранящееся в массиве, меняется на line="michelle", и теперь ваш предыдущий &line[4] будет указывать на «elle», чего вы не ожидали.

Allan Wind 22.04.2022 20:58
3 метода стилизации элементов HTML
3 метода стилизации элементов HTML
Когда дело доходит до применения какого-либо стиля к нашему HTML, существует три подхода: встроенный, внутренний и внешний. Предпочтительным обычно...
Формы c голосовым вводом в React с помощью Speechly
Формы c голосовым вводом в React с помощью Speechly
Пытались ли вы когда-нибудь заполнить веб-форму в области электронной коммерции, которая требует много кликов и выбора? Вас попросят заполнить дату,...
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Стилизация и валидация html-формы без использования JavaScript (только HTML/CSS)
Будучи разработчиком веб-приложений, легко впасть в заблуждение, считая, что приложение без JavaScript не имеет права на жизнь. Нам становится удобно...
Flatpickr: простой модуль календаря для вашего приложения на React
Flatpickr: простой модуль календаря для вашего приложения на React
Если вы ищете пакет для быстрой интеграции календаря с выбором даты в ваше приложения, то библиотека Flatpickr отлично справится с этой задачей....
В чем разница между Promise и Observable?
В чем разница между Promise и Observable?
Разберитесь в этом вопросе, и вы значительно повысите уровень своей компетенции.
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Что такое cURL в PHP? Встроенные функции и пример GET запроса
Клиент для URL-адресов, cURL, позволяет взаимодействовать с множеством различных серверов по множеству различных протоколов с синтаксисом URL.
0
10
26
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Вам нужно либо не перезаписывать line (для @AdrianMole), например, на realloc(line, new_larger_size), чтобы он мог хранить весь ваш ввод, либо копировать каждый токен и впоследствии освобождать память, выделенную, например, strdup():

tokens[j] = strdup(piece);
...
// cleanup: assumes last tokens[i] is NULL.  If tokens itself is heap allocated you need to free it too
for(int i = 0; tokens[i]; i++) free(tokens[j]);

Вчера я ответил на несколько похожий вопрос: Как вернуть массив 2d char (двойной указатель char) в C?

Может быть, голосование за закрытие как дубликат лучше, чем «повторение» одного из ваших собственных ответов?

Adrian Mole 22.04.2022 20:41

@AdrianMole Подобно тому, как вы относитесь к своему ответу, это не точная копия.

Allan Wind 22.04.2022 20:42

Я понимаю. Но после закрытия можно найти лучшие дубликаты и отредактировать список в синем баннере.

Adrian Mole 22.04.2022 20:43

@AdrianMole Это хорошее разрешение. Кстати, как вы редактируете список дубликатов после его закрытия? Я не знал, что это вариант.

Allan Wind 22.04.2022 20:49

Вам нужен «золотой значок» в одном из тегов вопроса (или ромб модератора), чтобы иметь возможность редактировать список. Если вы (или кто-то еще, у кого нет такого доступа) найдете лучший дубликат, не стесняйтесь отправить мне @-пинг.

Adrian Mole 22.04.2022 20:52

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