2013-10-31 126 views
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); 

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

+0

您是否尝试过调试?也许会打印一些输出,比如每次调用'strtok_r()'后''指向'' – gnobal

+0

'我认为使用'strtok_r'没问题......或者是什么地方出错了? – PhillipD

+0

您需要为'data'和'key'分配内存。现在你正在附加一个空指针。 –

回答

1

您的代码会崩溃在这条线:

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

因为你从不为data预留了空间。 strcat会尝试写入一个NULL内存地址。

还有一点需要注意的是,您不应该依赖save来检查行的末尾。根据strtok的手册页:

的saveptr参数是一个指向一个char *变量由strtok_r使用0​​内部(),以保持该解析相同的字符串 连续调用之间的上下文。

依托saveptrstrtok_r断抽象层的价值,你不应该承担有关如何strtok使用saveptr什么。这是不好的做法。

稍好一点的方法是保留一个指向由strtok返回的前一个标记的指针,以及一个指向当前标记的指针。当strtok返回NULL时,意味着没有更多的标记,那么prev将指向最后一个标记,即您的key。下面是一些代码:我被声明为数组,而不是指针分配空间data

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[0] = '\0'; 

有确保strcat发现在第一次调用空终止字节。

您可以直接替换prev的使用key,我让它使代码更具可读性。

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

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

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)─([email protected])─(~/tmp/strtok) 
└─► gcc -o main main.c; echo "one two three four five" | ./main 
data=two 
data=three 
data=four 
key = five 
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_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;