1. ホーム
  2. c

[解決済み】 strdup() - Cでは何をするのですか?

2022-03-28 01:58:48

質問

の目的は何ですか? strdup() という関数があります。

どのように解決するのですか?

CとUNIXが単語を割り当てる省略方法に慣れていると仮定すれば、まさにその通りです、それは 文字列の重複 :-)

実はISO C規格の一部ではないことに留意してください。 (a) (POSIXのものです)、事実上、以下のコードと同じことを行っています。

char *strdup(const char *src) {
    char *dst = malloc(strlen (src) + 1);  // Space for length plus nul
    if (dst == NULL) return NULL;          // No memory
    strcpy(dst, src);                      // Copy the characters
    return dst;                            // Return the new string
}

言い換えれば

  1. 古い文字列を格納するのに十分なメモリを確保しようとします(さらに、文字列の終わりを示す '∕0' 文字を追加します)。

  2. 割り当てに失敗した場合は errno から ENOMEM を返し NULL をすぐに実行します。の設定 errno から ENOMEM は何か malloc はPOSIXで行われていることなので、明示的に strdup . もし、あなたが ではなく POSIX準拠の場合、ISO Cは実際には ENOMEM ということで、ここには入れていません。 (b) .

  3. そうでなければ、アロケーションがうまくいったので、古い文字列を新しい文字列にコピーします。 (c) そして新しいアドレスを返します (呼び出し元はある時点でこれを解放する責任があります)。

これは概念的な定義であることに留意してください。ライブラリ作者であれば、使用するプロセッサに合わせて最適化されたコードを提供できるはずです。


(a) ただし str と小文字は、将来の方向性のために規格で予約されています。から C11 7.1.3 Reserved identifiers :

各ヘッダーは、関連するサブセクションにリストされたすべての識別子を宣言または定義し、*オプションで、関連する将来のライブラリ方向サブセクションにリストされた識別子を宣言または定義します**。

の今後の方向性は string.h には C11 7.31.13 String handling <string.h> :

で始まる関数名 str , mem または wcs の宣言に小文字を加えてもよい。 <string.h> ヘッダを作成します。

だから、安全を期すなら別の呼び方をしたほうがいい。


(b) この変更は、基本的には、次のように置き換えることになります。 if (d == NULL) return NULL; を使っています。

if (d == NULL) {
    errno = ENOMEM;
    return NULL;
}


(c) なお、私は strcpy というのは、その意図を明確に示しているからです。実装によっては、(すでに長さがわかっているため)より早く memcpy なぜなら、より大きなチャンクで転送したり、並列に転送したりすることができるからです。あるいは、そうでない場合もあります :-) 最適化のマントラその1:「測って、当てずっぽうにしない」。

いずれにせよ、その道を歩むことになった場合、次のようなことをすることになります。

char *strdup(const char *src) {
    size_t len = strlen(src) + 1;       // String plus '\0'
    char *dst = malloc(len);            // Allocate space
    if (dst == NULL) return NULL;       // No memory
    memcpy (dst, src, len);             // Copy the block
    return dst;                         // Return the new string
}