Ошибка сегментации при использовании strtok_r - PullRequest
16 голосов
/ 09 февраля 2010

Может кто-нибудь объяснить, почему я получаю ошибку сегментации в следующем примере?

#include <stdio.h>
#include <string.h>

int main(void) {
  char *hello = "Hello World, Let me live.";
  char *tokens[50];
  strtok_r(hello, " ,", tokens);
  int i = 0;
  while(i < 5) {
    printf("%s\n", tokens[i++]);
  }
}

Ответы [ 6 ]

24 голосов
/ 09 февраля 2010

Попробуйте это:

#include <stdio.h>
#include <string.h>

int main(void) {
        char hello[] = "Hello World, Let me live."; // make this a char array not a pointer to literal.
        char *rest; // to point to the rest of the string after token extraction.
        char *token; // to point to the actual token returned.
        char *ptr = hello; // make q point to start of hello.

        // loop till strtok_r returns NULL.
        while(token = strtok_r(ptr, " ,", &rest)) {

                printf("%s\n", token); // print the token returned.
                ptr = rest; // rest contains the left over part..assign it to ptr...and start tokenizing again.    
        }
}
/*
Output:
Hello
World
Let
me
live.
*/
16 голосов
/ 09 февраля 2010
  • Вам нужно позвонить strtok_r в цикле. В первый раз, когда вы даете ей строку для токенизации, вы даете ей NULL в качестве первого параметра.
  • strtok_r принимает char ** в качестве третьего параметра. tokens - это массив из 50 char * значений. Когда вы передаете tokens в strtok_r(), передается значение char **, которое указывает на первый элемент этого массива. Это нормально, но вы теряете 49 из значений, которые не используются вообще. Вы должны иметь char *last; и использовать &last в качестве третьего параметра для strtok_r().
  • strtok_r() изменяет свой первый аргумент, поэтому вы не можете передать ему то, что не может быть изменено. Строковые литералы в C доступны только для чтения, поэтому вам нужно что-то, что можно изменить: например, char hello[] = "Hello World, Let me live.";.
5 голосов
/ 09 февраля 2010

Куча неправильных вещей:

  1. hello указывает на строковый литерал, который должен рассматриваться как неизменяемый. (Он может находиться в памяти только для чтения.) Поскольку strtok_r изменяет строку аргумента, вы не можете использовать hello с ним.

  2. Вы вызываете strtok_r только один раз и не инициализируете массив tokens для указания на что-либо.

Попробуйте это:

#include <stdio.h>
#include <string.h>

int main(void) {
  char hello[] = "Hello World, Let me live.";
  char *p = hello;
  char *tokens[50];
  int i = 0;

  while (i < 50) {
     tokens[i] = strtok_r(p, " ,", &p);
     if (tokens[i] == NULL) {
        break;
     }
     i++;
  }

  i = 0;
  while (i < 5) {
    printf("%s\n", tokens[i++]);
  }

  return 0;
}
3 голосов
/ 09 февраля 2010

strtok_r пытается записать нулевые символы в hello (что недопустимо, потому что это константная строка)

2 голосов
/ 09 февраля 2010

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

И попробуйте и увидите это:

#include <stdio.h>
#include <string.h>    

int main(void)
{
    char hello[] = "Hello World, let me live.";

    char *tmp;
    char *token = NULL;
    for(token = strtok_r(hello, ", ", &tmp);
        token != NULL;
        token = strtok_r(NULL, ", ", &tmp))
    {
        printf("%s\n", token);
    }

    return 0;
}
0 голосов
/ 09 февраля 2010

Я думаю, это может быть char *tokens[50];, потому что вы объявляете его указателем, когда он уже является указателем. Массив уже является указателем при объявлении. Вы хотите сказать char tokens[50];. Это должно сработать.

...