strdup() - C で何をするのですか?

まさにそのように聞こえますが、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
}

つまり:

<オール> <リ>

古い文字列 (および文字列の終わりを示す '\0' 文字) を保持するのに十分なメモリを割り当てようとします。

<リ>

割り当てに失敗した場合は、errno を設定します ENOMEMまで NULL を返します すぐに。 errno の設定 ENOMEMmalloc のようなものです POSIX で行うので、strdup で明示的に行う必要はありません . そうでない場合 POSIX 準拠、ISO C は実際には ENOMEM の存在を義務付けていません そのため、ここには含めません (b) .

<リ>

それ以外の場合は割り当てが機能したため、古い文字列を新しい文字列にコピーします (c) 新しいアドレスを返します (呼び出し元は、ある時点で解放する責任があります)。

それが概念的な定義であることを覚えておいてください。給与に見合ったライブラリ ライターは、使用されている特定のプロセッサを対象として、大幅に最適化されたコードを提供している可能性があります。

(a) ただし、str で始まる関数 および小文字は、将来の指示のために標準で予約されています。 C11 7.1.3 Reserved identifiers から :

string.h の今後の方向性 C11 7.31.13 String handling <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
}

char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

  return p ? memcpy(p, s, len) : NULL;
}

コードは strcpy() よりも少し速いかもしれません \0 のように char を再度検索する必要はありません (既に strlen() で検索されていました) ).


他の回答を繰り返す意味はありませんが、strdup() に注意してください C標準の一部ではないため、Cの観点からは何でもできます。ただし、POSIX.1-2001 で定義されています。