从字符串中获取元素

时间:2013-10-31 11:19:19

标签: c c-strings

我陷入了一件相当琐碎的事情...... 所以,基本上我希望第一个和最后一个之间的“单词”转到数据,最后一个转到键。

仅限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);

P.S:comando是1024,因为内存不是问题,比抱歉更安全。 fgets读取512'因为这是标准unix终端的char行限制。

3 个答案:

答案 0 :(得分:1)

您的代码将在此行崩溃:

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

因为您从未为data预留空间。 strcat将尝试写入NULL内存地址。

另外需要注意的是,您不应该依赖save来检查行尾。根据{{​​1}}的联系方式:

  

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

依赖于strtok之外saveptr的值会破坏抽象层,您不应该假设strtok_r如何使用strtok。这是不好的做法。

稍微好一点的方法是保留指向saveptr返回的前一个标记的指针,以及指向当前标记的指针。当strtok返回NULL时,意味着没有其他令牌,则strtok将指向最后一个令牌,即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中保留指向下一个空闲位置的指针。

答案 1 :(得分: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

答案 2 :(得分:1)

您的代码有问题

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

稍后,您使用strcatdata添加字符串,但您没有为data分配存储空间。这将导致分段错误。

fgets(comando, 512, stdin);

fgets最多读取的数字少于传递给它的数字。因此,如果用户输入512个字符,则该字符串将没有终止\n。此外,检测错误或文件结尾的唯一方法是检查fgets的返回结果。如果它为NULL,则表示您已到达文件末尾(用户已按下ctrl-d)或出现错误。在任何一种情况下,缓冲区的内容都是不确定的。

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

我认为你不能依赖于你的save指针将指向未消耗字符串的其余部分的假设。

strtok_r(comando, " ",&save);

strtok_r通过返回NULL指针表示它已到达数据末尾。你不能不看它就扔掉返回的结果。此外,这将使用尾随\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;