У меня проблема с разделением содержимого строки, переданной функции. Функция вызывается с такой строкой:

ADD:Nathaniel:50

Где ADD будет именем протокола, Натаниэль будет ключом, а 50 будет значением, все разделены знаком :.

Мой код выглядит так:

bool add_to_list(char* buffer){

  char key[40];
  char value[40];
  int* token;

  char buffer_copy[1024];
  const char delim[2] = ":";

  strcpy(buffer_copy, buffer);

  token = strtok(NULL, delim);
  //strcpy(key, token);

  printf("%d",token);
  printf("%p",token);

  while(token != NULL){
    token = strtok (NULL, delim);
  }
  //strcpy(value, token);

  printf("%s", key);
  printf("%s", value);
  push(key, value);

  return true;
}

Я пытаюсь сохранить каждый ключ и значение в отдельной переменной, используя strtok(). Обратите внимание, что я пытаюсь сохранить второе и третье значения (Nathaniel и 50), а не первый бит (ADD).

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

РЕДАКТИРОВАТЬ: я изменил код, чтобы он выглядел так:

bool add_to_list(char* buffer){

char *key, *value, *token;

const char *delim = ":";

token = strtok(buffer, delim);

//printf("%d",token);
printf("%s",token);

key = strtok(NULL, delim);
value = strtok(NULL, delim);

printf("%s", key);
printf("%s", value);
//push(key, value);

return true;
}

Но я все еще получаю ту же ошибку сегментации (сброшено ядро)

1
Nathaniel Cutajar 23 Дек 2016 в 00:51
1
Вы никогда ничего не храните в key или value.
 – 
Barmar
23 Дек 2016 в 00:54
2
int* token; -> char *token;
 – 
BLUEPIXY
23 Дек 2016 в 01:08
1
const char[2] delim -> const char* delim
 – 
abligh
23 Дек 2016 в 01:20
И ради бога используйте strsep вместо ужасного strtok.
 – 
0andriy
23 Дек 2016 в 04:33

2 ответа

Первый вызов strtok() должен предоставить строку для сканирования. Вы используете NULL только для повторных вызовов, поэтому он продолжит обработку остальной части строки. ТАК первый вызов должен быть:

token = strtok(buffer_copy, delim);

Затем, когда вы хотите получить ключ и значение, вам нужно скопировать их в массивы:

token = strtok(NULL, delim);
key = strcpy(token);
token = strtok(NULL, delim);
value = strcpy(token);

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

На самом деле, вам не нужно объявлять key и value как массивы, вы можете использовать указатели:

char *key, *value;

Тогда вы сможете:

token = strtok(buffer_copy, delim);
key = strtok(NULL, delim);
value = strtok(NULL, delim);
4
Barmar 23 Дек 2016 в 00:57
Я получаю несколько предупреждений относительно: warning: присвоение несовместимого типа указателя [-Wincompatible-pointer-types] token = strtok (buffer_copy, delim); Что здесь происходит и как я могу удалить ошибку?
 – 
Nathaniel Cutajar
23 Дек 2016 в 03:18
1
token должно быть char*, а не int*.
 – 
Barmar
23 Дек 2016 в 03:18

Ваша основная проблема заключается в том, что при первом вызове strtok первым параметром должна быть строка, которую вы хотите проанализировать, а не:

strcpy(buffer_copy, buffer);
token = strtok(NULL, delim);

Но

strcpy(buffer_copy, buffer);
token = strtok(buffer_copy, delim);

Кроме того, когда вы обнаруживаете токены в цикле while, вы их выбрасываете. В этот момент вы хотите что-то сделать (или просто развернуть цикл и трижды вызвать strtok).

Также:

const char* delim = ":";

Было бы более традиционным способом гарантировать завершение строки NUL, чем:

const char delim[2] = ":";

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

1
abligh 23 Дек 2016 в 01:36
Не могли бы вы объяснить, как использовать функцию strtok_r? Я пытаюсь найти информацию об этом, но мне трудно понять. Кроме того, моя система будет похожа на небольшой сервер, поэтому у меня будет несколько потоков, поэтому я заинтригован использованием безопасной версии, а также ее хорошей этикой.
 – 
Nathaniel Cutajar
23 Дек 2016 в 03:14
По поводу strtok_r, справочная страница - полезный ресурс, но вот что вам следует сделать. Для каждой токенизации строки, которую вы хотите выполнить (например, один раз в приведенном здесь примере), добавьте char *save=NULL; перед первым использованием (технически инициализация не является обязательной), затем добавьте &save в качестве дополнительного параметра при каждом использовании strtok в этой токенизации и измените strtok на strtok_r. Это означает, что strtok_r будет сохранять свое состояние между вызовами в save, а не во внутреннем статическом буфере, поэтому у вас есть потокобезопасность.
 – 
abligh
23 Дек 2016 в 08:32