web-dev-qa-db-ja.com

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

Cのstrdup()関数の目的は何ですか?

288
Manoj Doubts

あなたが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. 割り当てに失敗した場合は、errnoENOMEMに設定し、すぐにNULLを返します。 errnoENOMEMに設定することはPOSIXではmallocが行うことなので、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>にあります。

strmem、または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
}
351
paxdiablo
char * strdup(const char * s)
{
  size_t len = 1+strlen(s);
  char *p = malloc(len);

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

\0文字列を再度検索する必要がないため、コードがstrcpy()よりも少し高速になる可能性があります(既にstrlen()の場合)。

83

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

50
Chris

から strdup man

strdup()関数は、新しい文字列へのポインタを返します。これは、s1が指す文字列の複製です。返されたポインタはfree()に渡すことができます。新しい文字列を作成できない場合は、nullポインタが返されます。

17
VonC

strdup()は、終了文字 '\ 0'を含む文字配列に動的メモリ割り当てを行い、ヒープメモリのアドレスを返します。

char *strdup (const char *s)
{
    char *p = malloc (strlen (s) + 1);   // allocate memory
    if (p != NULL)
        strcpy (p,s);                    // copy string
    return p;                            // return the memory
}

それで、それは、メモリを割り当てる必要なしに、その引数によって与えられた文字列と同一の別の文字列を与えることです。しかし、後でそれを解放する必要があります。

4
Karshit

strdupstrndupはPOSIX準拠のシステムでは次のように定義されています。

char *strdup(const char *str);
char *strndup(const char *str, size_t len);

strdup()関数は、文字列strのコピーに十分なメモリを割り当て、そのコピーを実行して、そのポインタを返します。

ポインタは、その後関数freeへの引数として使用されるかもしれません。

利用可能なメモリが足りない場合は、NULLが返され、errnoENOMEMに設定されます。

strndup()関数は、文字列lenから最大str文字をコピーし、コピーされた文字列を終了させます。

3
Sujay Kumar

mallocおよびstrcpyを実行して、渡された文字列の複製を作成します。 mallocされたバッファは呼び出し側に返されるため、戻り値に対してfreeを実行する必要があります。

3
jussij

それがする最も貴重なことはあなたがあなた自身にメモリ(位置とサイズ)を割り当てることを要求せずにあなたに最初のものと同一の別のストリングを与えることです。しかし、述べたように、あなたはまだそれを解放する必要があります(しかし、これも量の計算を必要としません)。

1
dkretz

ステートメント

strcpy(ptr2, ptr1);

(これがポインタを変えるという事実を除いて)と同等です:

while(*ptr2++ = *ptr1++);

一方、

ptr2 = strdup(ptr1);

以下と同等です。

ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);

そのため、コピーした文字列を別の関数で使用する場合(ヒープセクションで作成されたとおり)、strdupを使用できます。それ以外の場合はstrcpyで十分です。

1

Strdup()関数は文字列複製の省略形で、文字列定数または文字列リテラルとしてパラメータを取り、文字列に十分なスペースを割り当て、割り当てられたスペースに対応する文字を書き込み、最後に割り当てられたアドレスを返します。呼び出し元ルーチンへのスペース。

0
AnkitSablok