2017-01-13 254 views
0

我需要將一個句子(例如「Hello world」)複製到字符串列表中,意思是每個2個字由'\0'分隔的字符數組中。 請注意,單詞被定義爲沒有空格的行中的任意數量的字符。因此,無論何時我的程序檢測到任何數量的連續空白(包括只有一個空白),它都應該修改一個'\0'而不是一個'\0'C - 將字符串(句子)轉換爲字符串列表

問題是在我的target字符數組中第一次寫後,我無法再寫入它。我猜它是因爲'\0'意味着字符串結束,但在我的情況下,我試圖在字符數組內實現一個字符串列表,所以我必須在每兩個單詞之間有'\0'

基本上我的問題是我怎麼countinue寫入字符數組後?

這裏是我到目前爲止的代碼(你可以看到我也是在每次迭代檢查足夠的空間在traget但部分工作正常,那麼是不是真的野趣)

int strListFromWords(const char* source, char* target, int buffSize) 
{ 
    if (buffSize < 2) return -1; 
    char* sCurrentPointer = source; 
    char* tCurrentPointer = target; 
    int charsInTarget = 0; 
    while (*sCurrentPointer != '\0')   // While not end of string 
    { 
     if (charsInTarget + 2 < buffSize) // if there is enough space in target for current char 
     { 
      charsInTarget++; 
      if (!isspace(*sCurrentPointer))   // if current char isn't space 
      { 
       *tCurrentPointer = *sCurrentPointer; 
       sCurrentPointer++; 
       tCurrentPointer++; 
      } 
      else 
      { 
       *tCurrentPointer = '\0';   // PROBLEMATIC LINE put '\0' instead of spcace (in target) 

       sCurrentPointer++;     // goto next char in source 
       tCurrentPointer++;     // goto next position in target 
       while (isspace(*sCurrentPointer)) // while there are more spaces in a row 
       { 
        sCurrentPointer++;    // just skip them without messing with target 
       } 
      } 
     } 
     else 
      {         // Not enough space 
       emptyStrList(target); 
       return 0; 
      } 
     } 
    *tCurrentPointer = '\0'; 
    *(tCurrentPointer + 1) = '\0'; 
    return numStrsInList(target); 
    } 

謝謝

+2

['的strtok()'](http://pubs.opengroup.org/onlinepubs/ 9699919799/functions/strtok.html)完成你所描述的任務。你只需要「爲了學習目的而重新發明輪子」。 – pmg

+0

@pmg這正是我的目的 – Noam

+0

潛水前到如何做到這一點,也許問自己這個問題:你將如何**從在一個單一的目標僅僅'組成的「字符串列表」檢索**每個「單詞」 char'緩衝區?使用嵌入的nullchar策略是可行的,最後用兩個nullchar完成,但是你(這個東西的調用者)更好地理解這是該計劃。傳統上,*指針數組*用於構建字符串列表;不是一個字符緩衝區。 – WhozCraig

回答

1

沒有什麼能阻止你寫過去的0

我用下面的代碼段測試你的功能是,它WORD_COUNT正確返回。目標緩衝區將包含0個終止的字,並在最後加上一個額外的0。我想,那是意圖。

#include <conio.h> // for getch() 
#include <malloc.h> 
#include <string.h> 

int main() 
{ 
    char* source = " Hello World!\nThis is line number two.\n\n \n \n This is the last line"; 

    size_t buflen = strlen(source); 
    char* target = (char*)malloc(strlen(source)); 

    int word_count = strListFromWords(source, target, buflen); 
    printTarget(target); 

    free(target); 
    getch(); 
} 

此功能會告訴你整個目標緩衝區:

void printTarget(const char* target) { 
     char prev = ' '; 
     for (int i = 0;; i++) { 
      if (target[i]) 
      putch(target[i]); 
      else { 
      putch('\n'); 
      if (!prev) 
       break; 
      } 
      prev = target[i]; 
     } 
    } 

一些細微的變化是必要的,以使其編譯:

#include <stdio.h> 
#include <ctype.h> 

int strListFromWords(const char* source, char* target, int buffSize) 
{ 
    if (buffSize < 2) return -1; 
    char* sCurrentPointer = (char*)source; 
    char* tCurrentPointer = target; 
    int charsInTarget = 0; 
    int numStrsInList = 0; 

    while (*sCurrentPointer != '\0')   // While not end of string 
    { 
     if (charsInTarget + 2 < buffSize) // if there is enough space in target for current char 
     { 
     charsInTarget++; 
     if (!isspace(*sCurrentPointer))   // if current char isn't space 
     { 
      *tCurrentPointer = *sCurrentPointer; 
      sCurrentPointer++; 
      tCurrentPointer++; 
     } 
     else 
     { 
      *tCurrentPointer = '\0';   // PROBLEMATIC LINE put '\0' instead of spcace (in target) 
      numStrsInList++; 

      sCurrentPointer++;     // goto next char in source 
      tCurrentPointer++;     // goto next position in target 
      while (isspace(*sCurrentPointer)) // while there are more spaces in a row 
      { 
       sCurrentPointer++;    // just skip them without messing with target 
      } 
     } 
     } 
     else 
     {         // Not enough space 
     //emptyStrList(target); 
     return 0; 
     } 
    } 

    *tCurrentPointer = 0; 
    *(tCurrentPointer + 1) = 0; 
    return numStrsInList; 
} 

請注意,我只涉及什麼問。

+0

@Laszio感謝您測試代碼,正如您所說,單詞數很好。但是在運行結束時,目標數組應該包含所有源於'\ 0'的單詞並且不會發生 - 在運行結束時,只有來自源的第一個單詞處於目標中。當調試I看到在寫第一個'\ 0'到目標(源頭處有一個空白空間)之後,我無法再編寫更多字符來指向目標..問題是爲什麼以及如何解決它? – Noam

+0

是的,它的確如此。目標將包含「Hello \ 0World!\ 0 .. etc .. \ nline \ 0 \ 0」,但您的調試器將停止顯示目標,超過第一個'\ 0'。嘗試更新的源代碼。我添加了一個小函數來打印整個目標緩衝區 – Laszlo

+0

@Laszio非常感謝你。你是對的,你添加的功能很好。 – Noam

0
*tCurrentPointer = "\0"; 

*tCurrentPointer有型號char;您不能將一個數組(或自動轉換後的指針)分配給char。

我建議你打開所有的編譯器警告並留意它們。

1

我想主要的問題在於要求的制定。

如果需求是「將句子拆分爲單詞」,那麼結果應該是一個「單詞」數組,意思是一個字符串數組。如果這是要求,那麼函數應該有一個簽名,如char **getWordsArrayFromSentence(const char* sentence)。當你提出一個不同的簽名時,我認爲你的需求是不同的。

您的方法的簽名是int strListFromWords(const char* source, char* target, int buffSize),這表示它是從源複製到目標,同時用單個分隔符替換每個空白序列。

如果你選擇,例如,字符;作爲分隔符,則句子"Hello world"結果應該是"Hello;world";您可以打印結果,例如與printf("%s", target),並可以檢查你的算法是否正常工作。

不過,如果你選擇了串終止字符'\0'作爲分隔符,然後將結果看起來好像它僅有的第一個字(儘管目標的其餘部分將包含換句話說以及):target"Hello\0world\0"\0地位用於字符串終止字符。然後,當您用printf("%s", target)打印出目標時,則輸出爲Hello,即直到第一個字符串終止字符爲止的目標內容。

因此,簽名int strListFromWords(const char* source, char* target, int buffSize)產生單個合併的字符序列,但不是單詞的「列表」 「單詞」實際上包含在目標中,但您沒有可以讓您在開始時直接訪問每個單詞的數據結構。

順便說一句:注意,以下行是有問題的,

*tCurrentPointer = "\0"; 
*(tCurrentPointer + 1) = "\0"; 

因爲分配給*tCurrentPointer,這是目標內的一個字符,一個指針值,即指針串"\0";相反,你應該寫

*tCurrentPointer = '\0'; 
*(tCurrentPointer + 1) = '\0'; 

(注意單引號)。

+0

感謝您的回答,您的目標是將目標從源複製到目標,同時用單個分隔符替換每個空白序列,並且分隔符應該爲'\ 0'。與'\ 0'以外的任何分隔符都可以正常工作,問題僅在於'\ 0'。功能簽名是固定的,不能更改。在這些條件下 - 如何將單詞(全部)存儲到目標數組中?和你最後的評論 - 你的權利,將他們改爲單引號:) – Noam

1

你不是很遠。好吧還存在一些問題需要解決:

int strListFromWords(const char* source, char* target, int buffSize) 
{ 
    if (buffSize < 2) return -1; 
    //char* sCurrentPointer = source; lose const qualifier 
    const char* sCurrentPointer = source; // better! 

甚至更​​好:

int strListFromWords(const char* sCurrentPointer, char* target, int buffSize) 
{ 
    if (buffSize < 2) return -1; 
    char* tCurrentPointer = target; 

,並主要表現在:

/* *tCurrentPointer = "\0"; 
*(tCurrentPointer + 1) = "\0"; NO! "\0" is a char ARRAY */ 
*tCurrentPointer = '\0'; 
*(tCurrentPointer + 1) = '\0'; 

但除此之外,你的代碼做的事情是預料到了。終止不是數組。它只是標記了將要使用的字符串的結尾,但是所有的字符串函數都被使用了,但是如果你仍然在數組中,你可以寫入'\0'

可以與該代碼控制它:

int numStrsInList(char *target) { 
    int n = 0; 
    while (*target) { 
     target += strlen(target) + 1; // skip past the '\0' 
     n += 1; 
    } 
    return n; 
} 
int strListFromWords(const char* source, char* target, int buffSize) 
... 
int main() { 
    char target[32]; 
    char src[] = "Hello to the world"; 
    int n; 
    char *ix = target; 

    n = strListFromWords(src, target, sizeof(target)); 
    printf("%d words:", n); 
    while (*ix) { 
     printf(" >%s<", ix); 
     ix += strlen(ix) + 1; 
    } 
    putchar('\n'); 
    return 0; 
} 

該輸出作爲預期:

4 words: >Hello< >to< >the< >world<