2010-02-09 7 views
14

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

#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++]); 
    } 
} 

ответ

22

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

#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. 
*/ 
+0

Спасибо тонну. :) –

+0

Этот пример дает мне segfault на линии printf. gdb print token показывает 0xffffffffffffdad0 <Адрес 0xffffffffffffdad0 за пределами границ> Также получите эти два предупреждения при компиляции proj1.c: 33: 2: warning: неявное объявление функции 'strtok_r' [-Wimplicit-function-declaration] proj1.c: 33: 14: warning: присваивание делает указатель из целого без cast [включен по умолчанию] – schwiz

+1

Извините, что я новичок, почему он не должен быть 'char * ptr = Hello;' с капиталом H? Кроме того, ответ Алока говорит, что первый раз, когда первый параметр должен быть «токенизирован», а затем последующие вызовы, он должен быть NULL, но, похоже, ваш пример просто называет его одним способом в цикле while? Спасибо за код btw –

0

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

+1

Ваше понимание C кажется даже слабее меня ... –

3

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

+0

Я пробовал 'char hello [50]'. Ошибка сегментации исчезла, но теперь проблема заключается в том, что 'printf' просто печатает печальные пустые строки. :( –

2

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

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

#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; 
} 
5

кучу вещей неправильно:

  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; 
} 
+0

Спасибо за ответ. Я хотел бы, чтобы SO разрешило несколько вариантов ответов несколько правильно. :) –

14
  • Вы должны вызвать 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.";.
+1

Спасибо за ответ. Я хотел бы, чтобы SO разрешило несколько вариантов ответов несколько правильно. :) –

+0

+1, Лучший ответ. –

+0

@Scrub: рад помочь. Убедитесь, что вы поняли мой второй пункт выше (о 'char * tokens [50];' эквивалентно 'char **' при передаче функции). –

Смежные вопросы