简体   繁体   English

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

[英]C strtok() split string into tokens but keep old data unaltered

I have the following code:我有以下代码:

#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;
}

Execution output:执行 output:

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

Why can't I keep the old data nor in the str or oldstr , what am I doing wrong and how can I not alter the data or keep it?为什么我不能保留旧数据,也不能保留在stroldstr中,我做错了什么,我怎么能不更改或保留数据?

when you do strtok(NULL, "|") strtok() find token and put null on place ( replace token with \\0 ) and modify string.当您执行strtok(NULL, "|") strtok()查找标记并将null放在适当位置(\\0替换标记)并修改字符串时。

you str , becomes: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)

Consider the diagram is important because char '0' and 0 are diffident (in string 6270 are char in figure parenthesised by ' where for \\0 0 is as number)考虑图表很重要,因为 char '0'0是不同的(在字符串 6270 中,char 是由'括号括起来'数字,其中\\0 0 是数字)

when you print str using %s it print chars upto first \\0 that is John当您使用%s打印 str 时,它会将字符打印到第一个\\0 ,即John

To keep your original str unchanged you should fist copy str into some tempstr variable and then use that tempstr string in strtok() :要保持原始 str 不变,您应该先将 str 复制到某个 tempstr 变量中,然后在strtok()使用该tempstr字符串:

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

Now use this tempstr string in place of str in your code.现在在代码中使用这个tempstr字符串代替 str 。

Because oldstr is just a pointer, an assignment will not make a new copy of your string.因为oldstr只是一个指针,所以赋值不会创建字符串的新副本。

Copy it before passing str to the strtok :在将 str 传递给strtok之前复制它:

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

Your corrected version:您的修正版本:

#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;
}

EDIT:编辑:

As @CodeClown mentioned, in your case, it's better to use strncpy .正如@CodeClown 所提到的,在您的情况下,最好使用strncpy And instead of fixing the sizes of fname etc before hand, you can have pointers in their place and allocate the memory as is required not more and not less.而不是事先固定fname等的大小,您可以在它们的位置放置指针并根据需要分配内存,不多也不少。 That way you can avoid writing to the buffer out of bounds......这样你就可以避免越界写入缓冲区......

Another Idea: would be to assign the result of strtok to pointers *fname , *lname , etc.. instead of arrays.另一个想法:将strtok的结果分配给指针*fname*lname等。而不是数组。 It seems the strtok is designed to be used that way after seeing the accepted answer.在看到接受的答案后,似乎strtok旨在以这种方式使用。

Caution:In this way, if you change str further that would be reflected in fname , lname also.注意:这样,如果您进一步更改str将反映在fnamelname也。 Because, they just point to str data but not to new memory blocks.因为,它们只是指向str数据而不是新的内存块。 So, use oldstr for other manipulations.因此,请使用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 requires an writeable input string and it modifies the input string. strtok需要一个可写的输入字符串,它会修改输入字符串。 If you want to keep the input string you have to a make a copy of it first.如果要保留输入字符串,则必须先复制它。

For example:例如:

char str[] = "John|Doe|Melbourne|6270|AU";
char oldstr[32];

strcpy(oldstr, str);  // Use strncpy if you don't know
                      // the size of str

You just copy the pointer to the string, but not the string itself.您只需复制指向字符串的指针,而不是字符串本身。 Use strncpy() to create a copy.使用strncpy()创建副本。

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

The for() loop below shows how code calls strtok() at only one location.下面的for()循环显示了代码如何仅在一个位置调用strtok()

int separate( char *flds[], int size, char *fullStr ) {
    int count = 0;
    for( char *cp = fullStr; ( cp = strtok( cp, " " ) ) != NULL; cp = NULL ) {
        flds[ count ] = strdup( cp ); // must be free'd later!
        if( ++count == size )
            break;
    }
    return( count );
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM