我正在编写小型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 :(得分: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。