HOWTO · C

C 言語で strdup 関数を使用する

strdup が C で文字列を複製する仕組み、割り当てられたコピーを確認して解放する方法、そして strndup や GNU の strdupa を使うべき場面を学びます。

このページの内容

strdup はC文字列を終端のヌル文字を含めて複製し、別途確保したメモリへのポインターを返します。使用する前に戻り値を確認し、複製に成功したら free で解放してください。コピーするバイト数を制限したい場合は strndup を使います。strdupa はGNU固有の代替関数で、メモリの有効期間が異なります。 (GNU C ライブラリ)

strdupの機能と利用できる環境

strdup の宣言は <string.h> にある char *strdup(const char *s); です。ヌル終端された文字列 s のバイト列を、終端のヌルバイトも含めて新たに確保した領域へコピーします。返されるポインターはその領域を指します。メモリの確保に失敗すると、関数は NULL を返します。

strdup はC標準ライブラリの一部ではありません。POSIXで規定されており、GNU C ライブラリなど、一般的なCライブラリで利用できます。厳格な言語モードでコンパイルする場合、宣言を有効にするために機能テストマクロが必要な環境もあります。POSIX以外のシステムへの移植性が重要な場合は、対象プラットフォームのドキュメントを確認してください。

strdupで文字列を複製する

プラットフォームがPOSIXの宣言を有効にするために必要とする場合は、ヘッダーをインクルードする前に _POSIX_C_SOURCE を定義します。この例では、複製した文字列を読み取る前に戻り値を確認し、使用後に複製を解放します。正常に実行されると、元の文字列と複製した文字列が表示されます。

次の例を実行してください。

#define _POSIX_C_SOURCE 200809L
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *source = "C strings";
    char *copy = strdup(source);

    if (copy == NULL) {
        puts("Could not duplicate the string.");
        return EXIT_FAILURE;
    }

    printf("Source: %s\nCopy: %s\n", source, copy);
    free(copy);
    return 0;
}
Source: C strings
Copy: C strings

strdup が NULL を返した場合、そのポインターを文字列関数に渡したり、free を呼び出したりしてはいけません。上の失敗時の分岐では、エラーを報告して正常に終了します。複製が不要になったら、free を一度だけ呼び出してください。元の文字列リテラルを解放したり、解放後の複製を使ったりすることはできません。

strndupで最大nバイトをコピーする

strndup もPOSIXで規定されており、<string.h> で宣言されています。宣言は char *strndup(const char *s, size_t n); です。s から最大 n バイトをコピーし、確保した結果の末尾には必ずヌルバイトを追加します。上限は文字数ではなくバイト数です。そのため、上限がマルチバイト文字の符号化の途中にあると、その文字が途中までしかコピーされない場合があります。

たとえば、strndup("C strings", 3) は文字列 "C s" を生成します。返される領域は動的に確保されるため、strdup と同様に、成功したか NULL で確認し、成功した結果は free で解放してください。上限が決めるのはコピーする量であり、結果の有効期間や所有権ではありません。

GNU固有の代替関数strdupaを理解する

strdupa はGNU C ライブラリの拡張機能であり、POSIXやC標準の関数ではありません。宣言を有効にするために必要な環境では、システムヘッダーをインクルードする前に _GNU_SOURCE を定義します。strdup と同様にヌル終端文字列を受け取って複製を作りますが、ヒープ領域を返すのではなく、現在の関数に関連付けられた自動記憶域を使います。

この領域が有効なのは、それを含む関数の実行中だけです。関数の終了後に使うためにポインターを返したり、free に渡したりしてはいけません。利用できるかどうかや実装はGNU環境に依存します。POSIXインターフェースが必要な場合や、free で有効期間を管理できる複製が必要な場合は、strdup を使ってください。ここではGNU環境に固有のため、strdupa の実行例は示していません。