簡體   English   中英

C strtok() 將字符串拆分為標記,但保持舊數據不變

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

我有以下代碼:

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

執行 output:

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

為什么我不能保留舊數據,也不能保留在stroldstr中,我做錯了什么,我怎么能不更改或保留數據?

當您執行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 變量中,然后在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 <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將反映在fnamelname也。 因為,它們只是指向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!

下面的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