C 言語で文字列配列をコピーする
 
この記事では、C 言語で文字列配列をコピーする方法について、複数の方法を紹介します。
C 言語で文字列配列をコピーするには memcpy 関数を使用する
    
char 配列はおそらく C 言語のコードで操作される最も一般的なデータ構造であり、配列の内容をコピーすることはそのための中核的な操作の一つです。C 言語の文字列は char 配列と非常によく似ているので、配列の内容をコピーする方法は複数ある。次の例では、arr と arr2 という 2つの配列を宣言しています。前者は文字リスト記法で初期化され、後者は文字列リテラルで初期化されています。前者は文字リスト記法で初期化され、後者は文字列リテラルで初期化されます。arr オブジェクトはメモリ上では 7 文字ですが、arr2 は 17 文字と終端のヌルバイトを加えた 18 バイトのオブジェクトになります。したがって、第 2 引数に sizeof arr2 - 1 式の値を渡して配列の長さを表すことになります。一方、arr2 の配列の内容を printf 関数と %s 書式指定子を用いて出力することもできます。
char 配列を別の場所にコピーする場合も、同じことを考慮しなければなりません。関数 memcpy は、<string.h> ヘッダファイルで定義されている標準ライブラリの文字列ユーティリティの一部です。この関数は 3つのパラメータを持ち、最初のパラメータはコピー先のポインタで、配列の内容がコピーされます。2 番目のパラメータはコピー元の配列へのポインタであり、最後のパラメータはコピーするバイト数を指定します。演算子 sizeof は char 配列のオブジェクトサイズをバイト単位で返すことに注目してください。そこで、sizeof arr 式の値を渡して malloc を呼び出して動的メモリを確保します。返されたメモリ領域は arr の内容を保持するのに十分であり、バッファオーバーフローのバグを心配する必要はありません。ただし、malloc から返されたポインタは解放されている必要があることに注意してください。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printCharArray(char *arr, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    printf("%c, ", arr[i]);
  }
  printf("\n");
}
int main(int argc, char *argv[]) {
  char arr[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
  char arr2[] = "array initialized";
  printf("%lu\n", sizeof arr);
  printf("%lu\n", sizeof arr2);
  printCharArray(arr, sizeof arr);
  printCharArray(arr2, sizeof arr2 - 1);
  char *str = malloc(sizeof arr);
  memcpy(str, arr, sizeof arr);
  printf("str: ");
  printCharArray(str, sizeof arr);
  free(str);
  str = malloc(sizeof arr2);
  memcpy(str, arr2, sizeof arr2);
  printf("str: %s\n", str);
  free(str);
  exit(EXIT_SUCCESS);
}
出力:
7
18
a, b, c, d, e, f, g,
a, r, r, a, y,  , i, n, i, t, i, a, l, i, z, e, d,
str: a, b, c, d, e, f, g,
str: array initialized
関数 memove を用いて C 言語の文字列配列をコピーする
memove は、標準ライブラリの文字列ユーティリティのもう一つのメモリ領域コピー関数です。これは、コピー先とコピー元のメモリ領域が重複している場合に対応するために、より堅牢な関数として実装されています。memove のパラメータは memcpy と同じです。
arr2 の内容をコピーする際には、3 番目のパラメータとして sizeof arr2 式を渡すようにした。つまり、終端の NULL バイトもコピー先のポインタにコピーされたことになるが、結果として、printCharArray を使うよりも、printf を%s で呼び出して内容を出力することで、この動作を利用することになります。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void printCharArray(char *arr, size_t len) {
  for (size_t i = 0; i < len; ++i) {
    printf("%c, ", arr[i]);
  }
  printf("\n");
}
int main(int argc, char *argv[]) {
  char arr[] = {'a', 'b', 'c', 'd', 'e', 'f', 'g'};
  char arr2[] = "array initialized";
  char *str = malloc(sizeof arr);
  memmove(str, arr, sizeof arr);
  printf("str: ");
  printCharArray(str, sizeof arr);
  free(str);
  str = malloc(sizeof arr2);
  memmove(str, arr2, sizeof arr2);
  printf("str: %s\n", str);
  free(str);
  exit(EXIT_SUCCESS);
}
出力:
str: a, b, c, d, e, f, g,
str: array initialized
