strdup()
C の関数の目的は何ですか?
ベストアンサー1
まさにその通りです。C や UNIX が単語を割り当てる省略形に慣れていると仮定すると、文字列が重複します:-)
これは実際には現在の (C17) 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
設定することはPOSIX で行われることなので、 で明示的に行う必要はありません。 POSIX に準拠していない場合、ISO C では の存在が実際には必須ではないため、ここでは含めていません(b)。errno
ENOMEM
malloc
strdup
ENOMEM
それ以外の場合は割り当てが成功したので、古い文字列を新しい文字列(c)にコピーし、新しいアドレスを返します (呼び出し元は、ある時点でこのアドレスを解放する責任があります)。
これは概念的な定義であることに留意してください。給料に値するライブラリ作成者であれば、使用されている特定のプロセッサをターゲットにして、高度に最適化されたコードを提供している可能性があります。
留意すべきもう 1 つの点は、ドキュメントのドラフトによると、これが現在、 とともに標準の C2x イテレーションに含まれる予定であるように見えることです。strndup
N2912
(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
}