

c言語についての質問です。  
文字配列 char text[]="It is good to see you. Thank you for coming."; を宣言し、  
textの文字列を単語ことに分割して標準出力するというプログラムを作成しています。

ルールとして **スペースやピリオドは出力せず、出力する単語は一行に一単語ずつ '['と']'  
で囲んで出力する**というプログラムです。

また、 **単語間は必ず一文字分のスペースで区切られているという前提で作成してよいとする** 。  
**strtok等の文字列を分割する関数を用いずに作成する** 。外部プログラムの呼び出しもNG

という前提です。

### 発生している問題・エラーメッセージ

[code]

    str[0] : [It ]
    str[1] : [is ]
    str[2] : [good ]
    str[3] : [to ]
    str[4] : [see ]
    str[5] : [you. ]
    str[6] : [Thank ]
    str[7] : [you ]
    str[8] : [for ]
    str[9] : [coming.]
    続行するには何かキーを押してください . . .
    
[/code]

これは、プログラムを実行したときの実行結果です。

しかし、先生から スペースやピリオドを除いてください．ということでした。  
いろいろサイトを見て試してみたのですがどうしても回答に行きつきません。 どうしたらよいでしょうか？  
初めての質問なので不慣れな点があるかと思いますが、よろしくお願いします

[code]

    int main(void)
    {
        int i;
        char text[]="It is good to see you. Thank you for coming.";
        char str[10][256+1];
        char *s, *d;
    
        s = text;
        for(i=0; i<10;i++)
        {
            d = str[i];
    
             while ((*d++ = *s++) != _SPACE)
            {
            }
            *d = '\0';
        }
    
        for(i=0; i<10; i++)
        {
            printf("str[%d] : [%s]\n",i,str[i]);
        }
    }
    
[/code]

いろいろなサイトを見て、`#define _SPACE 0x20`を追加してみたもののうまくいきませんでした。


CC BY-SA 4.0
2019-07-05T20:38:30.170
56432
2019-07-06T16:37:15.607
2019-07-05T20:52:32.667
4236
34999
question
c
strtok等の文字列を分割する関数を用いずに文字を分割するプログラムについての質問


固定長の配列でパースをするのはむずかしいです。  
慣れると可変長のデータ構造のほうが楽だったりします。  
ポインタをループで回す時は範囲外アクセスを常に意識してください。  
それからテストを書くようにしましょう（書いたことが無ければ覚えましょう）。

[code]

    #include <stdio.h>
    #include <stdbool.h>
    #include <string.h>
    #include <ctype.h>
    #include <assert.h>
    
    // マジックナンバーを使うのはやめましょう
    enum {
        SPACE = ' ',
        PERIOD = '.',
        TOKENS_SIZE = 10,
        TOKEN_SIZE = 255,
    };
    
    // データ構造を表した正しい命名をしましょう
    static char tokens[TOKENS_SIZE][TOKEN_SIZE+1];
    
    /**
     * 文字がスキップ対象ならtrue, そうでなければfalseを返す
     */
    static bool
    is_skip_char(char ch) {
        return ch == SPACE || ch == PERIOD;
    }
    
    /**
     * スキップ対象の文字を読み飛ばす
     */
    static void
    skip(const char **pt) {
        for (; is_skip_char(**pt); ++*pt) {
        }
    }
    
    /**
     * 関数にコメントを書きましょう
     */
    static void
    split(const char *text) {
        // 状態を初期化
        for (int i = 0; i < TOKENS_SIZE; ++i) {
            tokens[i][0] = '\0';
        }
    
        const char *pt = text;
    
        skip(&pt); // 行頭のスキップ対象文字を読み飛ばす
    
        // ポインタの範囲外アクセスを意識してコードを書きましょう
        for (int i = 0; i < TOKENS_SIZE && *pt; ++i) {
            char *tok = tokens[i];
            char *tokend = tok + TOKEN_SIZE; // 範囲外アクセスを予防しましょう
    
            for (; tok < tokend && *pt; ) {
                if (is_skip_char(*pt)) {
                    break;
                }
    
                *tok++ = *pt++;
            }
    
            skip(&pt);
            *tok = '\0';
        }
    }
    
    /**
     * 解析と出力は別々にしましょう
     */
    static void
    show(void) {
        for(int i = 0; i < TOKENS_SIZE; ++i) {
            printf("tokens[%d] : [%s]\n", i, tokens[i]);
        }
    }
    
    /**
     * テストを書きましょう
     */
    static void
    test(void) {
        split("Hi Bob. Hi Michael");
        assert(!strcmp(tokens[0], "Hi"));
        assert(!strcmp(tokens[1], "Bob"));
        assert(!strcmp(tokens[2], "Hi"));
        assert(!strcmp(tokens[3], "Michael"));
    
        split("abc def..ghi jkl");
        assert(!strcmp(tokens[0], "abc"));
        assert(!strcmp(tokens[1], "def"));
        assert(!strcmp(tokens[2], "ghi"));
        assert(!strcmp(tokens[3], "jkl"));
    
        split("abcd");
        assert(!strcmp(tokens[0], "abcd"));
        assert(!strcmp(tokens[1], ""));
    
        split(" .abcd");
        assert(!strcmp(tokens[0], "abcd"));
        assert(!strcmp(tokens[1], ""));
    
        split("abcd. ");
        assert(!strcmp(tokens[0], "abcd"));
        assert(!strcmp(tokens[1], ""));
    
        split("    ");
        assert(!strcmp(tokens[0], ""));
        assert(!strcmp(tokens[1], ""));
    
        split("....");
        assert(!strcmp(tokens[0], ""));
        assert(!strcmp(tokens[1], ""));
    
        split(". . ");
        assert(!strcmp(tokens[0], ""));
        assert(!strcmp(tokens[1], ""));
    
        split(" . .");
        assert(!strcmp(tokens[0], ""));
        assert(!strcmp(tokens[1], ""));
    }
    
    int
    main(void) {
        // メイン関数に長いコードを書くのはやめましょう
        split("It is good to see you. Thank you for coming.");
        show();
    
        // テストをしましょう
        test();
    
        // returnを付けましょう
        return 0;
    }
    
    
[/code]


CC BY-SA 4.0
2019-07-06T15:21:21.773
56457
2019-07-06T16:37:15.607
2019-07-06T16:37:15.607
25852
25852
56432
answer