我有以下代码:
#include <stdio.h>
#include <string.h>
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
为什么我无法保留旧数据,也无法保留在
str
或oldstr
中,我做错了什么以及如何才能不更改数据或保留数据?
当您执行
strtok(NULL, "|")
strtok()
时,找到令牌并将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
是不同的(在字符串 6270 中是由 '
括起来的数字中的 char,其中 \0
0 是数字)
当您使用
%s
打印 str 时,它会打印第一个 \0
之前的字符,即 John
要保持原始 str 不变,您应该首先将 str 复制到某个 tempstr 变量中,然后在
tempstr
中使用该 strtok()
字符串:
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 <stdio.h>
#include <string.h>
#include<malloc.h>
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
,也会反映在fname
,lname
中。因为,它们只是指向 str
数据,而不是新的内存块。因此,请使用 oldstr
进行其他操作。
#include <stdio.h>
#include <string.h>
#include<malloc.h>
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!