Cの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
}
言い換えると:
古い文字列(および文字列の終わりを示すための '\ 0'文字)を保持するのに十分なメモリを割り当てようとします。
割り当てに失敗した場合は、errno
をENOMEM
に設定し、すぐにNULL
を返します。 errno
をENOMEM
に設定することはPOSIXではmalloc
が行うことなので、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>
にあります。
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
}
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()
の場合)。
他の答えを繰り返しても意味がありませんが、strdup()
はCの観点から望んだことは何でもできることに注意してください。これはC標準の一部ではないからです。しかしながらそれはPOSIX.1-2001によって定義されている。
から strdup man :
strdup()
関数は、新しい文字列へのポインタを返します。これは、s1
が指す文字列の複製です。返されたポインタはfree()
に渡すことができます。新しい文字列を作成できない場合は、nullポインタが返されます。
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
}
それで、それは、メモリを割り当てる必要なしに、その引数によって与えられた文字列と同一の別の文字列を与えることです。しかし、後でそれを解放する必要があります。
strdup
とstrndup
はPOSIX準拠のシステムでは次のように定義されています。
char *strdup(const char *str);
char *strndup(const char *str, size_t len);
strdup()関数は、文字列str
のコピーに十分なメモリを割り当て、そのコピーを実行して、そのポインタを返します。
ポインタは、その後関数free
への引数として使用されるかもしれません。
利用可能なメモリが足りない場合は、NULL
が返され、errno
はENOMEM
に設定されます。
strndup()関数は、文字列len
から最大str
文字をコピーし、コピーされた文字列を終了させます。
mallocおよびstrcpyを実行して、渡された文字列の複製を作成します。 mallocされたバッファは呼び出し側に返されるため、戻り値に対してfreeを実行する必要があります。
それがする最も貴重なことはあなたがあなた自身にメモリ(位置とサイズ)を割り当てることを要求せずにあなたに最初のものと同一の別のストリングを与えることです。しかし、述べたように、あなたはまだそれを解放する必要があります(しかし、これも量の計算を必要としません)。
ステートメント
strcpy(ptr2, ptr1);
(これがポインタを変えるという事実を除いて)と同等です:
while(*ptr2++ = *ptr1++);
一方、
ptr2 = strdup(ptr1);
以下と同等です。
ptr2 = malloc(strlen(ptr1) + 1);
if (ptr2 != NULL) strcpy(ptr2, ptr1);
そのため、コピーした文字列を別の関数で使用する場合(ヒープセクションで作成されたとおり)、strdup
を使用できます。それ以外の場合はstrcpy
で十分です。
Strdup()関数は文字列複製の省略形で、文字列定数または文字列リテラルとしてパラメータを取り、文字列に十分なスペースを割り当て、割り当てられたスペースに対応する文字を書き込み、最後に割り当てられたアドレスを返します。呼び出し元ルーチンへのスペース。