bugfix> c > 投稿

主に、文字列を分離することになっている別の関数に文字列を渡し、各部分文字列を処理します。この場合、30文字の文字列を取得して、後で操作できるように、長さ7、5、5、7、および6の部分文字列に分ける必要があります。これは私が試し始めたものです:

void breakString(const char *lineStr) {
        char a[7] = " "; //I tried with them all initialized empty and without doing so.
        char b[5];       //Didn't seem to make a difference.
        char c[5];
        char d[7];
        char e[6];
        //sscanf(lineStr, "%7s", &a);     //tried sscanf at first, but didn't know how to 
        strncpy(a, lineStr, 7);           //scan the middle so i switched to strncpy
        strncpy(b, lineStr + 7, 5);
        //continue this pattern for c,d,e
        (rest of function here, where each substring is manipulated accordingly.)

部分文字列 a を印刷して最初のビットをテストしましたおよび b (また、 strcmp() それらを正しい出力に出力します)が、完全には機能しません。私は余分な意味不明な言葉を取得し続けます。たとえば、渡された完全な文字列が "abcdefghijklmnopqrstuvwxyz1234" の場合 、次に a "abcdefg" である必要があります 、 b "hijkl" である必要があります 、 等々。ただし、 a を印刷すると 、 "abcdefg^#@%^&" として出力されます各サブストリングの後にランダムな文字の組み合わせがあります。

私は何を間違えていますか?または、これを異なる方法で実装するより良い方法はありますか?

回答 3 件
  • I keep getting extra gibberish...

    これは、 strncpy()  ソースが渡されたサイズより長い場合、宛先の末尾に暗黙的にヌル文字を追加しません。 C言語の文字列は、ヌルで終わる文字の配列です。

    したがって、この後:

    strncpy(a, lineStr, 7);
    
    

    ソースが渡されたサイズよりも長い場合、次のように末尾にヌル文字を追加する必要があります。

    a[7] = '\0';
    
    

    バッファの最後のヌル文字に対応するには、バッファサイズを+1にする必要があります。

    char a[8];
    char b[6];      
    char c[6];
    char d[8];
    char e[7];
    
    

    strncpy() の使用を避けるようにしてください  ヌル文字を手動で追加する必要があるためです。代わりに、 snprintf() のように、常に宛先をヌルで終了することを保証するものを使用してください 。できるよ:

    char a[8];
    snprintf(a, 8, "%s", lineStr);
    
    

    終端のヌル文字を追加する必要はありません。書き込まれたコンテンツの後に自動的に追加されます。 snprintf() の詳細を読む  ここに


    追加:

    空の配列を初期化する方法は正しくありません:

    char a[7] = " ";
    
    

    これは空の配列ではありませんが、実際には配列 (a[0]) の最初の要素を初期化します  スペース文字を使用すると、残りの要素は 0 で初期化されます 。空の配列を初期化するには、次のようにします。

    char a[8] = {0};
    
    

    これにより、配列のすべての要素が 0 で初期化されます 。

  • あなたの問題は strncpy で解決できます 、しかし、その正確なセマンティクスは広く誤解されており、非常にエラーが発生しやすいため、この関数を使用しないでください。

    詳細については、https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/を参照してください。

    さらに、nullターミネーターのために配列に格納する予定の文字数より1バイト長い配列を作成する必要があります。

    ここにあなたの場合の簡単な解決策があります:

    #include <stdio.h>
    void breakString(const char *lineStr) {
        char a[7+1] = ""; /* destination strings must be initialized */
        char b[5+1] = ""; /* because the %c conversion specifier */
        char c[5+1] = ""; /* will set a null terminator. */
        char d[7+1] = "";
        char e[6+1] = "";
        if (strlen(lineStr) >= 7+5+5+7+6 &&
            sscanf(lineStr, "%7c%5c%5c%7c%6c", a, b, c, d, e) == 5) {
            /* string was long enough, fields correctly initialized */
            printf("a: %s\nb: %s\nc: %s\nd: %s\ne: %s\n", a, b, c, d, e);
        }
    }
    int main() {
        breakString("abcdefghijklmnopqrstuvwxyz0123456789");
        return 0;
    }
    
    

    出力:

    a: abcdefg
    b: hijkl
    c: mnopq
    d: rstuvwx
    e: yz0123
    
    

    このソリューションはシンプルで簡潔ですが、ユーティリティ機能を使用して別のアプローチを取ることをお勧めします。確かに sscanf  解決策は、ほとんどのプログラマーが眉を上げてそれを拒否する非常に珍しい変換指定子のセットを使用します。さらに、可変数の文字を適切なサイズのサブアレイに抽出するのに役立ちません。

    別のアプローチを次に示します。

    #include <stdio.h>
    size_t getchunk(char *dest, size_t n, const char *str) {
        size_t i;
        for (i = 0; i < n && *str; i++) {
            dest[i] = *str++;
        }
        dest[i] = '\0';
        return i;
    }
    void breakString(const char *lineStr) {
        char a[7+1];
        char b[5+1];
        char c[5+1];
        char d[7+1];
        char e[6+1];
        size_t pos = 0;
        pos += getchunk(a, 7, lineStr + pos);
        pos += getchunk(b, 5, lineStr + pos);
        pos += getchunk(c, 5, lineStr + pos);
        pos += getchunk(d, 7, lineStr + pos);
        pos += getchunk(e, 6, lineStr + pos);
        if (e[0] != '\0') {
            /* string was long enough, fields correctly initialized */
            printf("a: %s\nb: %s\nc: %s\nd: %s\ne: %s\n", a, b, c, d, e);
        }
    }
    int main() {
        breakString("abcdefghijklmnopqrstuvwxyz0123456789");
        return 0;
    }
    
    

  • 1)sscanf()

    sscanf() を使用 、あなたはできる

    sscanf(lineStr, "%7c%5c%5c%7c%6c", a, b, c, d, e);
    a[7]=b[5]=c[5]=d[7]=e[6]='\0';
    
    

    %c  1バイト以上の読み取りに使用できます。 %7c  7バイトまで読み取ります。しかし、 \0  自動的に追加されません。

    この方法をchqrlieに感謝します。

    あるいは単に

    sscanf(lineStr, "%7s%5s%5s%7s%6s", a, b, c, d, e);
    
    

    lineStr の場合  空白は含まれません。

    または多分

    sscanf(lineStr, "%7[^\n]%5[^\n]%5[^\n]%7[^\n]%6[^\n]", a, b, c, d, e);
    
    

    lineStr の場合   \n はありません  文字。

    ここで、フォーマット文字列の数字は、コピーされる部分文字列の幅を示します。

    この方法では、 \0 する必要はありません  文字列を手動で終了します。 sscanf()  それの世話をします。


    2)strncpy()

    `strncpy()を使用する必要がある場合、あなたは正しい軌道に乗っています。できる

    void breakString(const char *lineStr) {
        char a[8];
        char b[6];      
        char c[6];
        char d[8];
        char e[7];
        strncpy(a, lineStr, 7);
        a[7]='\0';
        lineStr+=7;
        strncpy(b, lineStr, 5);
        b[5]='\0';
        lineStr+=5;
        strncpy(c, lineStr, 5);
        c[5]='\0';
        lineStr+=5;
        strncpy(d, lineStr, 7);
        d[7]='\0';
        lineStr+=7;
        strncpy(e, lineStr, 6);
        e[6]='\0';
        //lineStr+=6;
    }
    
    

    \0 を保存するには余分な1バイトが必要であることに注意してください  文字列の文字。したがって、配列のサイズはそれに応じて変更されます。

あなたの答え