strdup()-Cで何をしますか?


302

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


44
strdupa()(GNU Cライブラリ内)もあります。これは、strdup()に似ていますが、スタックにメモリを割り当てます。strdup()の場合のように、プログラムはメモリを明示的に解放する必要はありません。strdupa()が呼び出された関数を終了すると、メモリは自動的に解放されます
dmityugov

11
strdupastrlen非常に小さいと判断していない限り、危険ですので使用しないでください。ただし、スタック上で固定サイズの配列を使用するだけで済みます。
R .. GitHub ICEの

4
@slacker google translateは役に立ちません... ポーランド語でstrdup/はstrdupaどういう意味ですか?
haneefmubarak 2015年

14
@haneefmubarak here
anatolyg

strdupとstrcpyの違いは次のとおりです。stackoverflow.com/questions/14020380/strcpy -
Siva Prakash

回答:


372

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. 割り当てが失敗した場合は、に設定さerrnoENOMEMNULLすぐに戻ります。設定errnoにはENOMEM何かであるmalloc私たちは、明示的に私たちにそれを行う必要はありませんので、POSIXでありませんstrdup。POSIXに準拠していない場合、ISO Cは実際にはの存在を義務付けていないENOMEMため、ここには含めません(b)

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

これは概念的な定義です。給料に見合うすべてのライブラリ作成者は、使用されている特定のプロセッサをターゲットにして、大幅に最適化されたコードを提供している可能性があります。


(a)ただし、strおよびで始まる関数は、将来の方向性のために規格によって予約されています。からC11 7.1.3 Reserved identifiers

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

の今後の方向性string.hC11 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
}

8
Paxのサンプル実装が意味するように、strdup(NULL)は未定義であり、予測可能な方法で動作すると予期できるものではないことに注意してください。
アンワインド

2
また、malloc()はerrnoを設定するので、自分で設定する必要はありません。おもう。
Chris Lutz、

5
@Alcot strdupは、文字列コピーにヒープメモリを割り当てる必要がある状況向けです。それ以外の場合は、自分で行う必要があります。あなたは既に場合は持って十分な大きさのバッファ(そうでmallocまたは)を、はい、使用strcpy
paxdiablo

2
@acgtyrant:標準でISO標準(実際のC標準)を意味する場合、いいえ、それはその一部ではありません。これ POSIX標準の一部です。ただし、ISO Cの正式な部分ではありませんが、それを提供するCの実装はたくさんあります。ただし、そうでない場合でも、この回答の5つの要素で十分です。
paxdiablo 2014

2
良い点、@ chux、ISOは{ EDOM, EILSEQ, ERANGE }必須のエラーコードとしてのみ義務付けています。これを説明するために回答を更新しました。
paxdiablo

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

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

たぶん、コードが少し速くよりもあるstrcpy()よう\0charが(それはすでにしていた再検索する必要はありませんstrlen())。


ありがとう。私の個人的な実装では、それを「さらに悪い」ものにします。割り当ての失敗return memcpy(malloc(len), s, len);ではなく、割り当てのクラッシュを好むので NULL
PatrickSchlüter

3
@tristopiaの逆参照NULLはクラッシュする必要はありません。未定義です。確実にクラッシュするようにしたい場合emallocabort、失敗時にコールするを記述します。
Dave

私はそれを知っていますが、私の実装はSolarisまたはLinuxでのみ動作することが保証されています(アプリの性質上)。
PatrickSchlüter、2011

@tristopia:最善の方法で物事を行う習慣をつけるのは良いことです。emallocSolarisやLinuxでは必要ない場合でも使用する習慣をつけて、将来他のプラットフォームでコードを作成するときに使用できるようにします。
ArtOfWarfare 2015

51

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


4
あるstrdup()ポータブル?いいえ、非POSIX環境では使用できません(とにかく簡単に実装できます)。しかし、POSIX関数が何でも実行できると言うのはかなり面倒です。POSIXは、Cと同じくらい優れた、さらに人気のあるもう1つの標準です。
PP

2
@BlueMoon要点は、POSIXに準拠していないと主張するCの実装でstrdupも、拡張機能として機能を提供できるということです。そのような実装では、それがstrdupPOSIX関数と同じように動作するという保証はありません。そのような実装については知りませんが、悪意のない正当な実装がchar *strdup(char *)歴史的な理由で提供され、を渡す試みを拒否する可能性がありますconst char *

C標準とPOSIXの違いは何ですか?C標準とは、C標準ライブラリには存在しないということですか?
Koray Tugay 2015年

@KorayTugayそれらは異なる標準です。特定のC関数の標準がPOSIX標準に準拠していること、およびコンパイラー/ライブラリーがその関数の標準に準拠していることがわかっている場合を除いて、それらを無関係として扱うことをお勧めします。
マシューは

17

strdup manから:

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


4

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
}

つまり、メモリを割り当てる必要なく、引数で指定された文字列と同じ別の文字列が得られます。しかし、後でそれを解放する必要があります。


3

渡された文字列のmallocおよびstrcpyを実行することにより、渡された文字列の複製コピーを作成します。mallocされたバッファーは呼び出し元に返されるため、戻り値で自由に実行する必要があります。


3

strdupおよびstrndupPOSIX準拠のシステムで次のように定義されます。

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

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

その後、ポインタは関数の引数として使用できますfree

メモリが不足している場合NULLはが返され、errnoに設定され ENOMEMます。

strndup()高々機能をコピーしlenた文字列から文字がstr常にコピーされた文字列をヌル。


1

それが行う最も価値のあることは、自分でメモリ(場所とサイズ)を割り当てる必要なく、最初の文字列と同じ別の文字列を与えることです。ただし、前述のように、まだ解放する必要があります(ただし、数量の計算も必要ありません)。


1

ステートメント:

strcpy(ptr2, ptr1);

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

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

一方:

ptr2 = strdup(ptr1);

以下と同等です。

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

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


0

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


1
への引数strdupは文字列定数である必要はありません。それはC文字列でなければなりませんchar
chqrlie
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.