C strtok()将字符串拆分为标记但保持旧数据不变

我有以下代码:

#include  #include  int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = str; strcpy(fname, strtok(str, "|")); strcpy(lname, strtok(NULL, "|")); strcpy(city, strtok(NULL, "|")); strcpy(zip, strtok(NULL, "|")); strcpy(country, strtok(NULL, "|")); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); return 0; } 

执行输出:

 $ ./str Firstname: John Lastname: Doe City: Melbourne Zip: 6270 Country: AU STR: John OLDSTR: John 

为什么我不能保留旧数据,也不能保存在stroldstr ,我做错了什么以及如何不改变数据或保留数据?

当你执行strtok(NULL, "|") strtock查找标记并将null放在原位( \0替换标记 )并修改字符串。

str ,变成:

 char str[] = John0Doe0Melbourne062700AU; Str array in memory +------------------------------------------------------------------------------------------------+ |'J'|'o'|'h'|'n'|0|'D'|'o'|'e'|0|'M'|'e'|'l'|'b'|'o'|'u'|'r'|'n'|'e'|0|'6'|'2'|'7'|'0'|0|'A'|'U'|0| +------------------------------------------------------------------------------------------------+ ^ replace | with \0 (ASCII value is 0) 

考虑该图是重要的,因为char’0 '0'0是diffident(在字符串6270中是字符中的char括号'其中\0 0是数字)

当你使用%s打印str时,它会打印字符到第一个\0John

要保持原始str不变,你应该将str复制到某个tempstr变量中,然后在strtok()使用该tempstr字符串:

 char str[] = "John|Doe|Melbourne|6270|AU"; char* tempstr = calloc(strlen(str)+1, sizeof(char)); strcpy(tempstr, str); 

现在使用此tempstr字符串代替代码中的str。

因为oldstr只是一个指针,所以赋值不会生成字符串的新副本。

在将str传递给strtok之前复制它:

  char *oldstr=malloc(sizeof(str)); strcpy(oldstr,str); 

您的更正版本:

 #include  #include  #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char fname[32], lname[32], city[32], zip[32], country[32]; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); ................... free(oldstr); return 0; } 

编辑:

正如@CodeClown所提到的,在你的情况下,最好使用strncpy 。 而不是事先修复fname等的大小,你可以在它们的位置有指针并根据需要分配内存而不是更多而不是更少。 这样你就可以避免写入缓冲区了……

另一个想法:将strtok的结果分配给指针*fname*lname等,而不是数组。 似乎strtok被设计为在看到接受的答案后以这种方式使用。

警告:这样,如果你进一步改变str ,这将反映在fnamelname 。 因为,他们只是指向str数据而不指向新的内存块。 因此,使用oldstr进行其他操作。

 #include  #include  #include int main (void) { char str[] = "John|Doe|Melbourne|6270|AU"; char *fname, *lname, *city, *zip, *country; char *oldstr = malloc(sizeof(str)); strcpy(oldstr,str); fname=strtok(str,"|"); lname=strtok(NULL,"|"); city=strtok(NULL, "|"); zip=strtok(NULL, "|"); country=strtok(NULL, "|"); printf("Firstname: %s\n", fname); printf("Lastname: %s\n", lname); printf("City: %s\n", city); printf("Zip: %s\n", zip); printf("Country: %s\n", country); printf("STR: %s\n", str); printf("OLDSTR: %s\n", oldstr); free(oldstr); return 0; } 

strtok需要一个可写的输入字符串,它会修改输入字符串。 如果你想保留输入字符串,你必须首先复制它。

例如:

 char str[] = "John|Doe|Melbourne|6270|AU"; char oldstr[32]; strcpy(oldstr, str); // Use strncpy if you don't know // the size of str 

您只需将指针复制到字符串,而不是字符串本身。 使用strncpy()创建副本。

 char *oldstr = str; // just copy of the address not the string itself!