2017-01-13 39 views
0

"Hello world"などの文章を文字列リストにコピーする必要があります。つまり、2ワードごとに'\0'で区切られた文字配列にコピーする必要があります。 wordは、行内の任意の文字数として空白なしで定義されていることに注意してください。C - 文字列(文)を文字列リストに変換する

私のプログラムが行内の空白(1つの空白のみを含む)を検出すると、代わりに'\0'の1つを使用する必要があります。

問題は、私のtarget文字配列に初めて'\0'を書き込んだ後、もう書き込めません。私はそれが'\0'の文字列の終わりを意味するので私の推測ですが、私の場合は、文字配列内の文字列リストを実装しようとしているので、すべての2単語の間に'\0'を持っている必要があります。

基本的に私の質問は、'\0'を入れた後にchar配列に書き込むことができますか?ここで

これまでの私のコードです(私はまた、すべての反復でtragetに十分なスペースをチェックしますが、その部分はそう本当にのinterstingされていない正常に動作します見ることができるように)

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戦略を使用して、最終的に2つのnullcharsで仕上げることは実現可能ですが、あなた(このことを呼び出す者)はそれが計画であることをよく理解していました。伝統的に、*ポインタの配列*は文字列のリストを作成するために使用されます。単一のcharバッファではありません。 – WhozCraig

答えて

1

私は以下のコードを使用して機能をテストし、それが正しく単語数を返し

0過去を書くためにあなたを防ぐためには何もありません。ターゲットバッファには、終端された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; 
} 

Plsのノート、私がしたものだけを取り上げ尋ねた

+0

@Laszio言葉のカウントがうまくいけば、コードをテストしていただきありがとうございます。しかし、実行の最後に、ターゲット配列は '\ 0'で区切られたソースからのすべての単語を保持する必要があります。実行の最後に、ソースの最初の単語のみがターゲットになります。最初の '\ 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)です。これは、すべての空白のシーケンスを1つの区切り文字に置き換えながら、ソースからターゲットにコピーすることを示しています。

たとえば、文字「;」を区切り文字として選択すると、文"Hello world"の結果は"Hello;world"になります。結果を印刷することができます。 printf("%s", target)と入力し、アルゴリズムが正常に動作しているかどうかを確認できます。あなたは区切り文字として文字列の終端文字'\0'を選択した場合にのみ(ターゲットの残りの部分は、他の単語が含まれていますが)最初の単語が含まれているかのよう

しかし、結果は見えます:target\0立って"Hello\0world\0"だろう文字列終了文字。 printf("%s", target)でターゲットを印刷すると、出力はHello、つまり最初の文字列終了文字までのターゲットの内容になります。

したがって、署名int strListFromWords(const char* source, char* target, int buffSize)は、単一の統合された文字列を生成しますが、単語の「リスト」は生成しません。 「単語」は実際にはターゲットに含まれていますが、最初に各単語に直接アクセスできるデータ構造はありません。

ところで:あなたは、すなわち文字列"\0"へのポインタターゲット内の文字、ポインタ値である*tCurrentPointer

*tCurrentPointer = "\0"; 
*(tCurrentPointer + 1) = "\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'; 

しかし、離れて、あなたのコードは、それが期待されているものをしていることから、[OK]を修正するためのいくつかの問題が残っています。 ..終端'\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< 
関連する問題