C字符串拆分问题

我正在写小型IRC Bot,我需要拆分传入的消息以便于处理。 我写了一个函数get_word ,它应该拆分字符串。 根据gdb和valgrind,问题是函数有时返回无效指针,并且程序在尝试释放该指针时失败。 这是代码:

 char **get_word(char *str) { char **res; char *token, *copy; int size = 1; for(int i = 0; str[i] != '\0'; i++) { if(str[i] == ' ') { while(str[i] == ' ') { i++; } size++; } } res = malloc((size + 1) * sizeof(char *)); copy = strdup(str); token = strtok(copy, " "); for(int i = 0; token != NULL; i++) { res[i] = strdup(token); token = strtok(NULL, " "); } free(copy); res[size] = NULL; return res; } 

我看到的一个问题是你的嵌套循环:

考虑这个输入: ' \0'

函数执行到达for循环, i == 0 。 然后还输入while循环。 在while循环结束while i == 1 。 现在执行for循环的增量语句, i == 2 。 接下来你将阅读字符串的结尾。

编辑

我知道size是输入中找到的单词数。 所以我会去做类似的事情:

 for (int i = 0; str[i] != '\0'; ++i) { if (str[i] != ' ' && (str[i + 1] == ' ' || str[i + 1] == '\0')) { // Counting endings of words size++; } } 
 #include  #include  #include  char **split (const char *str) { char **arr = NULL; size_t cnt=0; size_t pos, len; arr = malloc (sizeof *arr); for (pos = 0; str[pos]; pos += len) { char *dup; len = strspn(str+pos, " \t\r\n" ); if (len) continue; len = strcspn(str+pos, " \t\r\n" ); if (!len) break; arr = realloc (arr, (2+cnt) * sizeof *arr); dup = malloc (1+len); memcpy (dup, str+pos, len); dup [len] = 0; arr [cnt++] = dup; } arr[cnt] = NULL; return arr; } int main(int argc, char **argv) { char **zzz; for( zzz = split( argv[1] ); *zzz; zzz++) { printf( "->%s\n", *zzz ); } return 0; } 

重新分配有点笨拙(就像在OP中一样)并且改进它是留给读者的练习8-}

正如julkiewicz指出的那样,你计算单词的嵌套循环可能会错过str上的终止null。 另外,如果str以空格结尾,那么您当前的代码将计算一个额外的单词。

您可以替换此部分:

 int size = 1; for(int i = 0; str[i] != '\0'; i++) { if(str[i] == ' ') { while(str[i] == ' ') { i++; } size++; } } 

..这样的事情:

 while (*str == ' ') str++; // skip leading spaces on str /* count words */ int size = 0; char *s = str; do { if (*s && *s != ' ') { size++; // non-space group found while (*s && *s != ' ') s++; // skip to next space } while (*s == ' ') s++; // skip spaces after words } while (*s); 

..which计算非空格字符组的开始,而不是空间组,并监视内循环中的终止空值。

您可能还会考虑更改:

 for(int i = 0; token != NULL; i++) { 

..至:

 for(int i = 0; token && i < size; i++) { 

..只是一个略带偏执的警卫,以防strtok找到比你计算的更多的话(虽然它不应该)。

我认为gdb可能会抱怨你从不检查malloc (或strdup )的返回值以查看它是否为非NULL。