1

我被一件相当琐碎的事情难住了......所以,基本上我想要第一个和最后一个之间的“单词”去数据,最后一个去关键。

仅限 C-POSIX,请。

strtok_r 是要走的路还是我已经走了?还有什么?

char *key = NULL, *data=NULL, *save=NULL;
char comando[1024];
fgets(comando, 512, stdin);

strtok_r(comando, " ",&save);

while(strcmp(save,"\n")){
    strcat(data,strtok_r(NULL," ",&save));
}

key = strtok_r(NULL, "\n",&save);

PS:comando 是 1024,因为内存不是问题,而且比抱歉更安全。fgets 读取 512 '因为这是标准 unix 终端上的字符行限制。

4

3 回答 3

1

我建议用以下代码替换您的循环(printf() 仅用于测试):

strtok_r(comando, " ", &save);
char *res = NULL;
while (NULL != (res = strtok_r(NULL, " ", &save))) {
  if (key != NULL) {
    //strcat(data, key); // FIXME
    printf("data = %s\n", key);
  }
  key = res;
}
printf("key = %s\n", key);

此外 strcat() 不应与 NULL 参数一起使用 - 它会导致崩溃。所以数据指针应该指向某个数组。代码运行结果:

┌─(16:08:22)─(michael@lorry)─(~/tmp/strtok)
└─► gcc -o main main.c; echo "one two three four five" | ./main
data=two
data=three
data=four
key = five
于 2013-10-31T12:09:15.090 回答
1

您的代码将在此行崩溃:

strcat(data,strtok_r(NULL," ",&save));

因为你从来没有为data. strcat将尝试写入NULL内存地址。

另一件需要注意的是,您不应该依赖save检查行尾。根据strtok的手册页:

saveptr 参数是一个指向 char * 变量的指针,strtok_r() 内部使用该变量来维护解析相同字符串的连续调用之间的上下文。

依靠saveptroutside of的值strtok_r打破了抽象层,你不应该假设任何关于如何strtok使用saveptr. 这是不好的做法。

一个稍微好一点的方法是保留一个指向返回的前一个标记strtok的指针和一个指向当前标记的指针。当strtok返回 NULL 时,意味着没有更多的标记,那么prev将指向最后一个标记,即你的key. 这是一些代码:

char *key = NULL, *save=NULL;
char *prev, *curr;
char comando[1024];
char data[1024];

data[0] = '\0';
fgets(comando, 512, stdin);
prev = curr = strtok_r(comando, " ",&save);

while (curr != NULL) {
    prev = curr;
    curr = strtok_r(NULL, " ", &save);
    if (curr != NULL)
        strcat(data, prev);
}

key = prev;

请注意,我data通过将其声明为数组而不是指针来分配空间。该指令

data[0] = '\0';

是否可以确保strcat在第一次调用中找到空终止字节。

prev你可以直接用替换使用key,我这样保留是为了使代码更具可读性。

一个忠告:永远记住它strtok会破坏性地修改它的参数(你失去了分隔字节的标识),并且你不能用常量字符串调用它。

注意: data将包含连接的每个单词。你失去了空间。我不确定这是否是你想要的。如果不是,您可能想要使用比strcat(顺便说一句,这不是很有效)更好的东西。例如,您的代码用于使用前导空格sprintf将标记打印到data其中,并保留指向下一个空闲位置的指针data

于 2013-10-31T12:04:26.737 回答
1

你的代码有很多错误

char *key = NULL, *data=NULL, *save=NULL;

稍后,您正在使用strcat将字符串添加到,data但您没有为data. 这将导致分段错误。

fgets(comando, 512, stdin);

fgets最多会比传递给它的数字少一。因此,如果用户确实输入了 512 个字符,则该字符串将没有终止符\n。此外,检测错误或文件结尾的唯一方法是检查fgets. 如果它为 NULL,要么您已到达文件末尾(用户已按 ctrl-d),要么出现错误。无论哪种情况,缓冲区的内容都是不确定的。

while(strcmp(save,"\n"))

我认为您不能依赖save指针将指向未使用字符串的其余部分的假设。

strtok_r(comando, " ",&save);

strtok_rNULL通过返回一个指针来表示它已经到达数据的末尾。你不能不看就扔掉返回结果。此外,这将使用尾随\n作为最后一个令牌的一部分。

strcat(data,strtok_r(NULL," ",&save));

正如我之前所说,data是一个空指针。还strtok_r可以退货NULL

我会做更多类似的事情:

char* currentTok = strtok_r(commando, " \n", &save); // separator is space or \n
char* previousTok = NULL;
while (currentTok != NULL)
{
    if (previousTok != NULL)
    {
        // save previousTok in data unless its the first token
    }
    previousTok = currentTok;
    currentTok = strtok_r(NULL, " \n", &save);
}
char* key = previousTok;
于 2013-10-31T12:20:25.013 回答