C字符串拆分问题

时间:2011-09-25 15:55:14

标签: c string

我正在编写小型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;
}

4 个答案:

答案 0 :(得分:3)

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

考虑这个输入:' \0'

函数执行到达for循环i == 0。然后还输入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++;
    }
}

答案 1 :(得分:0)

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

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 - }

答案 2 :(得分:0)

正如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);

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

您可能还会考虑更改:

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

..为:

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

..就像一个稍微偏执的警卫,如果strtok找到的词比你计算的多(尽管它不应该)。

答案 3 :(得分:-2)

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