C言語入門|文字列を加工・生成する関数

ここからはいよいよ、
文字列を実際に書き換えたり、新しく作ったりする関数
を扱っていきます。

strlen や strcmp は「読むだけ」の関数でしたが、
今回登場する関数は メモリに書き込む という点で一段レベルが上がります。

便利になる反面、
使い方を間違えるとオーバーランに直結する
関数たちでもあります。

だからこそ、ここで大切なのは
「この関数は、どの領域に、どこまで書き込むのか」
を常にイメージすることです。

文字列を加工する関数の共通ルール

今回登場する関数には、共通した前提があります。

共通ルール内容
先頭アドレス渡し文字列は必ず先頭アドレスで受け渡す。
\0 前提\0 に到達するまでを文字列として扱う。
容量チェックはしない十分な領域があるかは呼び出し側の責任

特に最後の
容量チェックを自動では行わない
という点が重要です。

これらの関数は、
「あると信じて、あるだけ書く」
という、非常に正直な動作をします。

strcpy ― 文字列をまるごとコピーする

ある文字列を、別のメモリ領域にそのままコピーしたい。
そんなときに使うのが strcpy 関数です。

strcpy の書式

char* strcpy(char* dest, const char* src);
引数意味
destコピー先の先頭アドレス(十分な領域が必要)
srcコピー元文字列の先頭アドレス
戻り値dest と同じアドレス

strcpy は、

  • src の先頭から
  • \0 に到達するまで

1文字ずつ dest にコピーします。

重要な注意点

strcpy は、
dest の大きさを一切確認しません。

そのため、

  • src が長すぎる
  • dest の確保サイズが足りない

このどちらかが起きると、
即オーバーランです。

strcpy の動作を領域で考える

strcpy を安全に使うためには、
「3つの領域」の考え方がそのまま役立ちます。

領域意味
使用中コピーされる文字列部分
使用可能コピーしてよい領域
使用禁止触れてはいけない領域

dest の使用可能領域が、
src の文字列長 + 1(\0 分)
より小さい場合は、使ってはいけません。

strcat ― 文字列を後ろに連結する

既存の文字列の後ろに、
別の文字列をつなげたいときに使うのが strcat です。

strcat の書式

char* strcat(char* dest, const char* src);
引数意味
dest連結後の文字列が格納される先頭アドレス
src後ろに追加する文字列の先頭アドレス
戻り値dest と同じアドレス

strcat は、

  1. dest の \0 を探す
  2. その位置から src をコピー
  3. 最後に \0 を付け直す

という動作をします。

strcat は特に危険になりやすい

strcat は、
見た目以上に危険度が高い関数です。

なぜなら、

  • 現在の文字列長
  • これから追加する文字列長
  • 使用可能領域の残り

この3つをすべて把握していないと、
簡単にオーバーランしてしまうからです。

よくある落とし穴

char str[] = "hello";
strcat(str, "world");  // 危険

この場合、str は
必要最低限の6バイトしか確保されていません。

後ろに連結できる余裕はゼロです。

sprintf ― 文字列を「生成」する関数

sprintf は、
printf の仲間でありながら、
画面には何も表示しません。

代わりに、
指定したメモリ領域に文字列を書き込みます。

sprintf の書式

int sprintf(char* dest, const char* format, ...);
引数意味
dest書き込み先の先頭アドレス
formatprintf と同じ書式文字列
...書式に対応する値
戻り値書き込んだ文字数(\0 は含まない)

sprintf を使うと、

  • 数値と文字列を組み合わせる
  • 整形されたメッセージを作る

といった処理が、とても簡単になります。

sprintf も容量チェックはしない

sprintf も例外ではありません。

  • 書き込む文字数
  • dest の確保サイズ

この関係を考えずに使うと、
strcpy や strcat と同じくオーバーランします。

「printf の感覚で使うと危険」
という点は、必ず覚えておきましょう。

文字列加工関数を使うときの心得

最後に、この節の要点をまとめます。

心得内容
書き込み先の容量を把握する常に何バイトあるかを意識
\0 の存在を忘れない+1 バイトは必須
3つの領域を思い出す使用中・使用可能・使用禁止

これらを意識できていれば、
文字列を加工・生成する関数は
非常に心強い道具になります。