2011-10-27 15 views
2
function(char *a, char *b) 
{ 

    char newStr[100]; 

    strncpy(newStr, a, sizeof(newStr)); //Line 1 - copy no more than 100 bytes 

    strncat(newStr, b, (sizeof(newStr) - strlen(newStr))); //Line 2 - ? 

    newStr[99] = NULL; //Line 3 - null terminate string 

} 

ライン2:正しい私は100のバイトをコピーしないことを確実にするために何からコピーの100 バイトマイナスはstrlenを指定するには?方法:メモリを保護する - strncat()?

ありがとうございます。

+1

これはCで最も厄介な不満の一つでなければなりません - 'strncpy'は* *最後に書き込まれたバイト数またはポインタを返さないという事実が、むしろ最初のものへのポインタです(これは引数の1つなので、すでにわかっています)。 –

+0

文字列を自分自身でヌル終了する必要があったとしても、NULLを使うのは間違いです。これはnull *ポインタ*定数です。ヌル文字は ''\ 0' '(または単に' 0')です。 –

+0

@KerrekSB: 'strncpy'は、古くからの遺物で、' strcpy'の代わりに使われることは決してありませんでした。代わりに 'strlcpy'を使用してください。ただし、どこでも利用できません。 –

答えて

2

これはほぼ正しいです。まず、NUL終了ライン:

newStr[99] = NULL; 

が間違っています。

strncat常に3番目のパラメータはNULを含むではないを書き込む最大バイト数です。

仮に、strncatがNUL終了しなかった場合、実際の文字列がはるかに短くても、配列の最後の要素に常に書き込むという問題があります。 aとbが "Hello"と "world!"の場合、最終配列は次のようになります。

H | e | l | l | o |、|

ここで、gibberishは、それらの位置の配列の以前の内容を表します。これら初期化されていない残りの大部分の後の99で、NULが存在します。

EDIT:また、キースは約strncpyと正確です。彼の関数は部分的に正しいですが、2番目の関数はすでに存在している文字列を考慮しないため、バッファをオーバーフローさせる可能性があります。結合された2行は、199文字(NULを含む)を書くことができます。

また、NULを含む3番目のパラメータについては間違っていました。それは(キースさんから変更された)を私たちに残し:

void function(char *a, char *b) 
{ 
    char newStr[100]; 

    /* Make newStr an empty string so you can catenate onto it */ 
    newStr[0] = '\0'; 
    strncat(newStr, a, sizeof newStr - 1); 
    strncat(newStr, b, sizeof newStr - strlen(newStr) - 1); 

    /* Presumably you do something with newStr here */ 
} 
+0

ok、strncat()がnullを自動的に終了する必要がある理由について、あなたが何を言っているかを見ています。 strncat()のバイト数とstrlenを使って正しいバイト数を得るのは奇妙に思えますが、このシステムでは同じことになります。 –

+0

@Tommy、私の更新を参照してください。重要な修正がいくつかあります。 –

3

strncpy()は、おそらくそれがないと思う何をしません。

strncat()は、より安全なバージョンのstrcat()で、ターゲット配列のサイズを指定できます。

strncpy()は、ではなく、strcpy()の対応する「より安全な」バージョンです。ターゲット配列が大きすぎる場合、strncpy()はヌル文字で埋め込みます。文字列の末尾に1つの文字しか入力しない場合は、'\0'とするだけで99%の時間が不要です。さらに悪いことに、ターゲット配列が小さすぎる場合、strncpy()はできるだけ多くの文字をコピーし、をターゲットにして、末尾にのままにしておきます。

strncpy()は、初期のUnixシステムがファイル名を格納するために使用するあいまいなデータ構造のために設計されています。ファイル名は、ヌルバイトが埋め込まれた固定長の14バイトバッファに格納されていました。ファイル名が正確に14文字の長さだった場合、ヌルターミネーターはありません。 これは文字列ではありません

それはあなたが欲しいデータ構造のようなものだとしたら、strncpy()は単なるものです。それ以外の場合は、使用しないでください。ターゲットが十分に大きいことを確認してからstrcpy()を使用してください。ここで

は、私は、この関数を書くかもしれない方法は次のとおりです。

void function(char *a, char *b) 
{ 
    char newStr[100]; 

    /* Make newStr an empty string so you can concatenate onto it */ 
    newStr[0] = '\0'; 
    strncat(newStr, a, sizeof newStr - 1);     /* edited */ 
    strncat(newStr, b, sizeof newStr - strlen(newStr) - 1); /* edited */ 

    /* Presumably you do something with newStr here */ 
} 

注:

  1. 関数の戻り値の型を宣言します。明示的に宣言しないと、コンパイラはおそらくデフォルトでintになりますが、それはスタイルが悪くなり、古くなった言語機能です。
  2. strncat()を避けてください。
  3. 文字列をヌル終了させるために'\0'NULLではなく)を使用しました。 NULLはNULL ポインタ定数です。 NULL 文字を示すために使用しないでください。

かなりの非効率性がここにあります:strncat()第二は、newStrの先頭から再スキャンする必要があります。短い文字列の数が少ない場合は大したことではありませんが、多数の文字列が大きなターゲット配列に連結されると、深刻な減速を引き起こす可能性があります。この問題を回避する方法はありますが、非標準(strlcpy()strlcat())か不便です。

EDIT:私のコードでエラーを指摘してくれたMatthewに感謝します。私はだと思います。私はそれらを修正しました。私は、古いものを新しいものに置き換えれば、頭の中で私を殴ってくれる人に数えることができると確信しています。

選択肢は次のとおりです。

snprintf(newStr, sizeof newStr, "%s%s", a, b); 
+0

2番目のstrncat呼び出しが間違っています。これは、既存の文字列の後に100バイト*を書き込むためです。 –

+0

そして、最初のものは1つだけオフになっています(元の答えで同じミスを犯しました)。 –

+0

"%s%s%s%s"を指定することができ、繰り返しの 'strcat()' sの隠しO(n * m)を気にする必要がないので、 'snprintf'のために+1します – Dave