strcpy は、string.hをインクルードすれば、利用できます。
しかし正しく利用するには、その関数がどのように作られたものかを理解する必要があります。
以下では、この関数の定義例と利用例を紹介します。
char a[10];
char *s = "abc";
a = s;
文字並びを記憶可能なaの配列があり、その配列に s が管理する文字列を記憶させる場合、上記の=演算子で可能でしょうか?
それは、できません!
できない理由は2つあります。
一つめの できない理由: aは配列名で変更対象にできない。(定数と同じ取り扱い)
二つめの できない理由: sは、"abc"と記憶される領域の先頭アドレスを表現して
いるだけで、仮に=の左が変更可能な対象であっても、アドレスという番地の値を代入するだけになる。
以上より、単純に=演算子で文字列記憶内容をコピーすることはできません。
そして、このような場合は、標準関数のstrcpy関数を使って、strcpy( a, s ); と実行させます。
この関数の中では、sの指し示す文字並びを、sが指し示す位置へ、
1文字ずつ=演算でコピーする処理が行なわれています。
この繰り返しは、'\0'のコードをコピーするまで行なわれます。
( s1[i] = s2[i] ) の1byte代入を'\0'が行なわれるまで、
iで位置をずらしながら繰り返す処理です。
なお、戻れ値は、第一引数と同じ値です。
#include <stdio.h> char * strcpy(char *s1, char *s2) { int i = 0; while( ( s1[i] = s2[i] ) != '\0' ){ i++; } return s1; } main() { char w[128]; /* 127byte分の文字を記憶できる配列 */ char a[3][6];/* 5byte分の文字を記憶できる配列を3個用意した */ int i; for(i = 0; i < 3 ; i++){ printf("文字列入力>" , a ); gets(w); /* 1行入力 */ strcpy( a[i] , w ); /* strcpy( & a[i][0] , w ); と書いてもよい */ } for(i = 0; i < 3 ; i++){ puts( a[i] ); /* puts( & a[i][0] ); と書いてもよい */ } }
strcpy定義を確認するため、mainで配列wへ入力し、その文字列を &a[i++][0]にコピーする繰り返しを
3回行なって、その後に表示する繰り返しを行なっています。
その実行例を以下に示します。
(なお、ここではstrcpyの戻り値を利用しませんでした。)
文字列入力>abc 文字列入力>1 234 文字列入力>wxyz abc 1 234 wxyz
なお、この入力で6文字以上の入力を行なうと、正しい結果が得られなくなります。
つまり、それは配列の範囲を超えたアクセスになるからです。
この関数も、関数定義例からもわかるように、
コピー元の文字列が記憶可能範囲を超えるサイズであっても、コピーしようとします。
つまり、
利用する方で正しく使わなければならない関数といえます。
上記strcpyと同じ機能を行なわせる別の定義例を、以下に示します。
ここでは、添え字用変数 i を使っていません。ポインタ引数の変数を変更することで、
コピーする文字コードを記憶する位置を変更しています。
■■■■ の記述を正しく直して完成くだささい。
([]の配列演算子を使わずに、*のポインタ演算子を使ってください。ポインタ変更は後置インクリメントを使ってください)
←編集 入力後に クリックください。
このようなポインタの変数を変更する方式は、C言語独特の作り方です。 なお、極端に省略して関数を定義すると次のようになります。(分かり難いと感じる人が多いので薦めませんが・・・)
#includechar * strcpy2(char *s1, char *s2) { char * startp = s1; while( *s1++ = *s2++ ) ; /* 空文の繰り返し */ return startp; }
*s1++ = *s2++の式の結果は、
s1のポインタを増やす前のs1が指し示す記憶域への代入値です。
(この代入操作が行う以外に、s1とs2のポインタは次の位置を指すように変更されます)
この代入値が0でなければ、条件判定が成立するので、文字列終端の0までコピーされます。