簡體   English   中英

已解決 - 我做錯了什么 strtok 在拆分字符串時做對了

[英]SOLVED-what am I doing wrong that strtok does right in splitting a string

上一個問題是:strtok 在拆分字符串時做對了,我做錯了什么。 突然將 strtok 分離到 function 也不會產生正確的結果?

這是我第一次在 stackoverflow 中提問,所以請原諒我是否冗長和不連貫。 問題的最后一部分在該問題正文的底部進行了詳細說明。

所以,我正在做我的大學分配的課程評估,其中一個問題是:

刪除重復的單詞並僅打印唯一的單詞

輸入:單個句子,其中每個單詞由空格分隔

Output:由空格分隔的唯一單詞[單詞順序應與輸入中的順序相同]

例子:

輸入:adc aftrr adc art

Output:adc aftrr 藝術

現在,我有了解決方案,即在空格上拆分字符串並將單詞添加到數組(集合)中(如果它尚不存在),但正是實現部分讓我費盡心機

#include <stdio.h>
#include <string.h>

#define MAX 20

int exists(char words[][MAX], int n, char *word){ // The existence check function
    for(int i=0;i < n;i++)
        if(strcmp(words[i],word) == 0) 
            return 1;
    return 0;
}

void removeDuplicateOld(char*);
void removeDuplicateNew(char*);

int main(){
    char sentence[MAX*50] = {0}; //arbitary length
    fgets(sentence,MAX*50,stdin);
    sentence[strcspn(sentence,"\n")]=0;
    
    printf("The Old One : \n");
    removeDuplicateOld(sentence);
    printf("\nThe New One : \n");
    removeDuplicateNew(sentence);
}

使用strtok分割字符串的函數:


void removeDuplicateNew(char *sentence){
    char words[10][MAX] = {0};
    int wi=0;
    char *token = strtok(sentence," ");
    
    while(token != NULL){
        if(exists(words,wi,token)==0) {
            strcpy(words[wi++],token);
        }
        token = strtok(NULL," ");
    }
    for(int i=0;i<wi;i++) printf("%s ",words[i]);
}

使用我的舊方法的舊 function(在我遇到空格之前構造一個詞):


void removeDuplicateOld(char *sentence){
    char objects[10][MAX] = {0}; //10 words with MAX letters
    char tword[MAX];
    int oi=0, si=0, ti=0;
    
    while(sentence[si]!='\0'){
        if(sentence[si] != ' ' && sentence[si+1] != '\0')
            tword[ti++] = sentence[si];
        else{
            if(sentence[si+1] == '\0')
                tword[ti++]=sentence[si];
                
            tword[ti]='\0';
            
            if(exists(objects,oi,tword) == 0){
                strcpy(objects[oi++],tword);
            }
            ti=0; // The buffer[tword] is made to be overwritten

        }
        si++;
    }
    for(int i=0;i<oi;i++)
        printf("%s ",objects[i]);
}

已解決:將 if(sentence[si+1] == '\0') 更改為 if(sentence[si+1] == '\0' && sentence[si]!=' ')


這是 output:

輸入:abc def ghi abc jkl ghi

舊一:

abc def ghi jkl

新的那一個:

abc def ghi jkl

請注意,輸入中的尾隨空格和 output 未被檢查,因為它們自己的驅動程序代碼未正確處理它們,而 strtok 方法可以並通過所有測試。


現在這兩種方法似乎產生了相同的結果,但它們確實根據測試用例產生了不同的輸出,並且在將 strtok 方法作為一個單獨的函數 [removeDuplicateNew] 的頂部,它在一個測試用例中失敗,而在 main 方法中編寫它本身通過了所有測試,看到這些結果:

舊方法測試用例結果

Strtok 方法作為單獨的 Function 測試用例結果

以下已移至單獨的問題線程

在 main 方法本身中編碼時:

int main(){
    char sentence[MAX*50] = {0}; //arbitary length
    fgets(sentence,MAX*50,stdin);
    sentence[strcspn(sentence,"\n")] = 0;
    
    char words[10][MAX] = {0};
    int wi=0;
    char *token = strtok(sentence," ");
    
    while(token != NULL){
        if(exists(words,wi,token)==0) {
            strcpy(words[wi++],token);
        }
        token = strtok(NULL," ");
    }
    for(int i=0;i<wi;i++) printf("%s ",words[i]);
}

Strtok 方法作為內聯代碼測試用例結果

作為記錄,它是放在 main 方法中的相同代碼,所以這里到底發生了什么,當我將它分離為 function 並將字符串作為參數傳遞時,它突然無法正常工作。

還有關於我的問題構建的任何建議,措辭表示贊賞。

你的代碼...

void removeDuplicateOld(char *sentence){
    char objects[10][MAX] = {0}; //10 words with MAX letters
    char tword[MAX];
    int oi=0, si=0, ti=0;
    
    while(sentence[si]!='\0'){
        if(sentence[si] != ' ' && sentence[si+1] != '\0')
            tword[ti++] = sentence[si];
        else{
            // right here have hit SP.
            // if SP followed by '\0'
            // then append SP to my word... wrong! <=====
            if(sentence[si+1] == '\0')
                tword[ti++]=sentence[si];
                
            tword[ti]='\0';

這就是庫 function strtok()hand rolled代碼更好用的原因。
它已經過測試並證明可以像它所說的那樣工作。


有更好的方法來使用strtok()

for( char *p = sentence; (p = strtok( p, " \n") ) != NULL; p = NULL )
    if( exists( words, wi, p ) == 0 )
        strcpy( words[wi++], p );

這就是你所需要的。 strtok() 甚至會為您修剪緩沖區中的 LF,無需額外付費。


最后的建議:您可以考慮可以輕松增長的鏈表 (LL),而不是固定大小的單詞指針數組。 function 將 append 一個新詞到列表的末尾,如果在遍歷到 append 到 LL 的末尾時發現它是重復的,則可以悄悄地吃掉這個詞。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM