• Xでシェア
  • LINEでシェア
  • このエントリーをはてなブックマークに追加

C言語 strncpyの使い方

この記事のポイント

  • strncpy関数の基本概念と主な用途
  • バッファオーバーフローを防ぐ安全な文字列操作
  • 文字列の部分コピーと長さ制限の実装テクニック
  • NULL終端が保証されない特性とその対処法
  • 実用的なコード例とエラーパターンの回避策

目次

C言語のstrncpyとは?

C言語のstrncpy関数は、文字列を安全にコピーするために設計された標準ライブラリ関数です。C言語の文字列コピー関数には、strcpy関数もあります。strncpy関数との違いは、strcpy関数ではコピーする文字数を明示的に指定できるため、バッファオーバーフローを防止する重要な役割を果せる点です。

strcpy関数は、プログラム内でソース文字列からデスティネーション文字列へ指定した文字数だけをコピーする動きをします。コピーする文字数を制限できることから、目的の配列サイズを超えてコピーされることを防ぐことも可能です。この特徴は、セキュリティが重要なアプリケーションや、ユーザー入力を扱うプログラムで非常に重要なポイントになります。

ただし、strncpyには注意点もあります。コピー元の文字列が指定した長さより短い場合、残りの領域はNULL文字('\0')で埋められます。

一方、コピー元のNULL終端が指定文字数内に収まらない場合、コピー先にNULL終端は追加されません。この仕様を理解し、必要に応じて明示的にNULL終端を追加することが重要です。

strncpy関数を使う際には、常にバッファサイズを考慮し、必要に応じて明示的にNULL終端を追加することが重要です。適切に使用すると、strncpyはメモリ破壊やセキュリティ脆弱性からアプリケーションを守る強力なツールとなります。

【関連】
C言語をもっと詳しく学ぶならpaizaラーニング

基本構文

strncpy関数の基本構文は、以下の通りです。

char *strncpy(char *dest, const char *src, size_t n);

上記の関数は、srcからdestへ最大n文字をコピーします。nはsize_t型で、コピーする最大文字数を表します。戻り値はdestポインタです。

strncpy関数を使用する際には、string.hヘッダーファイルをインクルードする必要があります。基本的な使用例は、以下のようになるでしょう。

#include <string.h> char destination[20]; const char *source = "Dog"; strncpy(destination, source, 19); destination[19] = '\0'; // NULL終端を明示的に保証

上記の例では、source文字列をdestination配列に最大19文字コピーし、最後の文字を明示的にNULL終端としています。このテクニックにより、バッファオーバーフローを防ぎながら、常に有効な文字列を維持できるでしょう。

実用例

このセクションでは、動物のシナリオを使ったわかりやすいコードパターンを見ながら、strncpy関数による文字列操作の基礎知識を解説しています。

初心者がこの関数の特徴を理解し、バッファオーバーフローの対策を習慣にするためには、このセクションのコードを自分のプログラムのなかで「何度も使ってみる経験」が必要です。

試行錯誤のなかで自分の失敗パターンなどが見えてくると、それを防ぐための対策も迅速に設置できるようになるでしょう。これはまさに「習うより慣れよ」です。

最初のうちはバッファオーバーフローを恐れることもあるかもしれませんが、多くの経験があってこそスキルアップにつながることを信じて、さまざまな文字列操作に挑戦してみてください。

基本的な文字列コピー操作

strncpy関数の最も基本的な使用例です。

以下のコードパターンでは、ソース文字列「Cat」をデスティネーション配列にコピーします。この操作で重要となるのは、コピー先のバッファサイズを考慮して、常に1バイト少なくコピーし、最後のバイトにNULL文字を明示的に追加している点です。

このテクニックにより、バッファオーバーフローを防ぎながら、有効な文字列としての整合性を維持できます。コード例では、sizeof演算子を使用してバッファサイズを動的に判断しており、これはコードのメンテナンス性を高める効果的な方法となるでしょう。

#include <stdio.h> #include <string.h> int main() { char src[] = "Cat"; char dest[10]; strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0'; printf("コピー後: %s\n", dest); return 0; }

出力結果:

コピー後: Cat

バッファオーバーフロー防止

strncpy関数の最大の利点は、バッファオーバーフローの防止機能があることです。

以下のコードパターンでは、デスティネーション配列(11バイト)より明らかに長いソース文字列「Giraffe is a very long-necked animal」をコピーしようとしています。通常のstrcpy関数を使用した場合、バッファオーバーフローが発生しメモリ破壊やセキュリティ脆弱性につながりますが、一方でこのコードで使われているstrncpy関数はコピーする文字数を制限するため安全です。

結果として、元の文字列の先頭部分だけがコピーされ、最後にNULL文字が追加されています。

#include <stdio.h> #include <string.h> int main() { char src[] = "Giraffe is a very long-necked animal"; char dest[11]; strncpy(dest, src, sizeof(dest) - 1); dest[sizeof(dest) - 1] = '\0'; printf("結果: %s\n", dest); return 0; }

出力結果:

結果: Giraffe is

NULL終端の保証

strncpy関数には、「自動的にNULL終端を追加しない」という重要な特性があります。

以下のコードパターンは、その動作をわかりやすく示すものです。最初に「Rabbit」をコピーしますが、文字数だけを指定してNULL終端を追加しないため、デスティネーション配列の残りの部分(「XXXXX」)が保持される形です。

次に、明示的にNULL終端を追加することで、正しい文字列として認識されるようになります。この動きを理解することは、strncpy関数をうまく活用するうえでとても大切でしょう。

#include <stdio.h> #include <string.h> int main() { char src[] = "Rabbit"; char dest[20] = "XXXXXXXXX"; strncpy(dest, src, 4); printf("終端なし: %.9s\n", dest); dest[4] = '\0'; printf("終端あり: %s\n", dest); return 0; }

出力結果:

終端なし: RabbXXXXX
終端あり: Rabb

部分文字列のコピー

strncpy関数は、文字列の一部分だけをコピーする際にも役立ちます。

以下のコードパターンは、ソース文字列「ElephantGiraffePanda」の途中(「ntGiraffe」の部分)だけを抽出するものです。具体的には、ポインタ演算(src + 6)を使用して開始位置を指定し、9文字だけをコピーしています。それから、明示的にNULL終端を追加して有効な文字列とする形です。

この技法は、文字列の特定部分だけを処理したい場合や、パース処理で特定のトークンを抽出する場合などに役立つでしょう。

#include <stdio.h> #include <string.h> int main() { char src[] = "ElephantGiraffePanda"; char dest[10]; strncpy(dest, src + 6, 9); dest[9] = '\0'; printf("部分コピー: %s\n", dest); return 0; }

出力結果:

部分コピー: ntGiraffe

文字配列の初期化

strncpy関数は、文字配列を特定のパターンで初期化する場合にも使用可能です。以下のコードパターンでは、配列全体を「A」文字で埋めています。strncpy関数は、コピー先の配列サイズ(10バイト)まで文字をコピーしますが、そこで重要とのは最後のバイトにNULL文字を明示的に設定している点です。

この動きにより、文字配列が有効な文字列として扱えるようになります。この初期化パターンは、固定長のフィールドを特定の文字(スペースや0など)で埋める場合に役立つでしょう。

#include <stdio.h> #include <string.h> int main() { char buffer[10]; strncpy(buffer, "AAAAAAAAAAA", sizeof(buffer)); buffer[sizeof(buffer) - 1] = '\0'; printf("初期化: %s\n", buffer); return 0; }

出力結果:

初期化: AAAAAAAAA

メモリブロックのクリア

strncpy関数におけるもう一つの便利機能は、メモリブロック全体をクリア(ゼロ埋め)することです。

以下のコードパターンでは、最初に「Lion」という文字列が格納されている配列を、空文字列("")をコピーすることでクリアしています。コピー元の文字列よりもコピー先のサイズが大きい場合、残りのスペースはNULL文字(値が0のバイト)で埋められることは、strncpy関数の大きな特性です。

このテクニックは、セキュリティ上の理由で機密データを含むバッファをクリアする場合などに役立ちます。

#include <stdio.h> #include <string.h> int main() { char buffer[10] = "Lion"; printf("クリア前: %s\n", buffer); strncpy(buffer, "", sizeof(buffer)); printf("クリア後: %s\n", buffer); return 0; }

出力結果:

クリア前: Lion
クリア後: 

固定長フィールドへのコピー

固定長フィールドを持つ構造体にデータをコピーする場合も、strncpy関数はとても役立ちます。

以下のコードパターンでは、動物名を格納するための固定長フィールド(13バイト)を持つ構造体に「Zebra」をコピーしています。バッファオーバーフローを防ぐために、サイズから1を引いた長さだけコピーし、最後のバイトに明示的にNULL終端を追加しています。

このテクニックは、ファイル入出力や通信プロトコルで固定長レコードを扱ううえで特に役立つものです。

#include <stdio.h> #include <string.h> int main() { struct { char animal[13]; char habitat[8]; } record; strncpy(record.animal, "Zebra", sizeof(record.animal) - 1); record.animal[sizeof(record.animal) - 1] = '\0'; printf("Animal: %s\n", record.animal); return 0; }

出力結果:

Animal: Zebra

複数の文字列操作の組み合わせ

実際のプログラムでは、複数の文字列操作を組み合わせるケースが多くあります。

以下のコードパターンでは、最初に「Penguin」をバッファにコピーし、安全にNULL終端を追加しています。複数の文字列を連結したり、文字列を段階的に構築したりするうえでは、このようなアプローチが必要です。

また、以下のコードパターンでは、バッファサイズを常に考慮しており、これは安全なプログラミングの基本となります。実際の応用では、このあとに文字列連結などの操作を追加して、複数の動物名を一つの文字列にまとめるといった処理もできるでしょう。

#include <stdio.h> #include <string.h> int main() { char buffer[15], animal1[] = "Penguin"; strncpy(buffer, animal1, sizeof(buffer) - 1); buffer[sizeof(buffer) - 1] = '\0'; printf("結果: %s\n", buffer); return 0; }

出力結果:

結果: Penguin

まとめ

C言語のstrncpy関数は、バッファオーバーフローを防止しながら文字列をコピーするための重要ツールです。通常使われるstrcpy関数とは異なり、コピーする文字数を明示的に制限できる特徴があります。適切に使うことで、メモリ破壊やセキュリティ脆弱性からプログラムを保護できるでしょう。

ただし、NULL終端が保証されない特性には十分注意する必要があります。そのため、バッファの最後に明示的にNULL文字を追加することが安全なプログラミング作成の基本となります。

この関数を理解し適切に活用することで、より堅牢なC言語プログラムを開発できるようになるでしょう。

レベルを更に上げたい方はpaizaプログラミングスキルチェックへ

  1. paizaラーニングトップ
  2. リファレンス
  3. C言語のリファレンス記事一覧
  4. C言語 strncpyの使い方