C言語でstrcpy/strncpy/strcpy_s関数の使い方と自作関数を教えて!
こういった悩みにお答えします.
本記事の信頼性
- リアルタイムシステムの研究歴12年.
- 東大教員の時に,英語でOS(Linuxカーネル)の授業.
- 2012年9月~2013年8月にアメリカのノースカロライナ大学チャペルヒル校(UNC)コンピュータサイエンス学部で客員研究員として勤務.C言語でリアルタイムLinuxの研究開発.
- プログラミング歴15年以上,習得している言語: C/C++,Python,Solidity/Vyper,Java,Ruby,Go,Rust,D,HTML/CSS/JS/PHP,MATLAB,Verse(UEFN), Assembler (x64,ARM).
- 東大教員の時に,C++言語で開発した「LLVMコンパイラの拡張」,C言語で開発した独自のリアルタイムOS「Mcube Kernel」をGitHubにオープンソースとして公開.
- 2020年1月~現在はアメリカのノースカロライナ州チャペルヒルにあるGuarantee Happiness LLCのCTOとしてECサイト開発やWeb/SNSマーケティングの業務.2022年6月~現在はアメリカのノースカロライナ州チャペルヒルにあるJapanese Tar Heel, Inc.のCEO兼CTO.
- 最近は自然言語処理AIとイーサリアムに関する有益な情報発信に従事.
- (AI全般を含む)自然言語処理AIの論文の日本語訳や,AIチャットボット(ChatGPT,Auto-GPT,Gemini(旧Bard)など)の記事を50本以上執筆.アメリカのサンフランシスコ(広義のシリコンバレー)の会社でプロンプトエンジニア・マネージャー・Quality Assurance(QA)の業務委託の経験あり.
- (スマートコントラクトのプログラミングを含む)イーサリアムや仮想通貨全般の記事を200本以上執筆.イギリスのロンドンの会社で仮想通貨の英語の記事を日本語に翻訳する業務委託の経験あり.
こういった私から学べます.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!
目次
strcpy関数
1 |
char *strcpy(char *dest, const char *src); |
strcpy関数は,srcが指す文字列を末尾のヌルバイト('\0')も含めてdestが指すバッファにコピーします.
srcとdestの文字列のメモリ領域は重なってはいけません.(未定義の動作になります.)
destはsrcのコピーを受け取るのに十分な大きさが必要です.
strcpy関数の返り値は,destへのポインタです.
コピーするメモリ領域が重なる場合は,strcpy関数ではなくmemmove関数を利用しましょう.
memmove関数を学びたいあなたはこちらからどうぞ.
strcpy関数の使い方
strcpy関数を使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #define BUFSIZE 16 int main(void) { char dest[BUFSIZE], src[BUFSIZE]; printf("Please input a string: "); scanf("%s", src); strcpy(dest, src); printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc strcpy.c $ a.out Please input a string: abc s = abc t = abc |
strcpy関数の自作関数
strcpy関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define BUFSIZE 16 char *mystrcpy(char *dest, const char *src) { char *tmp = dest; while ((*dest++ = *src++)) { } return tmp; } int main(void) { char dest[BUFSIZE], src[BUFSIZE]; printf("Please input a string: "); scanf("%s", src); mystrcpy(dest, src); printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
実行結果は以下になります.
1 2 3 4 5 |
$ gcc mystrcpy.c $ a.out Please input a string: abc s = abc t = abc |
strcpy関数の注意点
strcpy関数は,バッファサイズより長い文字をコピーするとバッファオーバーフローが発生することに注意して下さい.
strcpy.cのコードで文字列に「abcdefghijklmnopqrstuvwxyz」を入力した結果は以下になります.
「abcdefghijklmnopqrstuvwxyz」 と'\0'の合計27文字を入力しましたが,BUFSIZEは16なので,以下の6行目でバッファオーバーフローが発生して「*** stack smashing detected ***: terminated」と表示されていることがわかります.
※strcpy.cでは,15行目のscanf関数と17行目のstrcpy関数でバッファオーバーフローが発生しています.
1 2 3 4 5 6 7 |
$ gcc strcpy.c $ a.out Please input a string: abcdefghijklmnopqrstuvwxyz src = qrstuvwxyz dest = abcdefghijklmnopqrstuvwxyz *** stack smashing detected ***: terminated abort (core dumped) a.out |
strncpy関数
1 |
char *strncpy(char *dest, const char *src, size_t n); |
strncpy関数はstrcpy関数と似ていますが,srcのうち最大でもnバイトしかコピーされない点が異なります.
ただし,srcの最初のnバイトの中にヌルバイトがない場合,destに格納される文字列はヌルで終端されない可能性があることに注意して下さい.
destのn + 1バイト目(配列の添字ではn)にヌルバイトがあればヌルで正常に終端します.
なので,strncpy関数でnバイトコピーした後に,n + 1バイト目にヌルバイトを代入する処理を入れましょう!
そうでなければ,printf関数等でdestを読み込んだ場合,未定義のデータが表示されたり,バッファオーバーリードが発生したりしてしまいます.
strncpy関数の返り値は,destへのポインタです.
strncpy関数の使い方
strncpy関数の使い方は以下になります.
20行目のstrncpy関数でsrcからnバイト分をdestにコピーした後に,21行目で「dest[n] = '\0';」とヌルバイトを代入しています.
nが15以下であれば,n + 1がdestのサイズの16以下になるので,正常にヌル終端します.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #define BUFSIZE 16 int main(void) { char dest[BUFSIZE], src[BUFSIZE]; size_t n; printf("Please input a string: "); scanf("%s", src); printf("Please input a byte: "); scanf("%zu", &n); strncpy(dest, src, n); dest[n] = '\0'; printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
実行結果は以下になります.
3行目に文字列abc,4行目に2を入力することでabcの先頭2バイトのabがdestにコピーされていることがわかります.
1 2 3 4 5 6 |
$ gcc strncpy.c $ a.out Please input a string: abc Please input a byte: 2 src = abc dest = ab |
strncpy関数の自作関数
strncpy関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #define BUFSIZE 16 char *mystrncpy(char *dest, const char *src, size_t n) { char *tmp = dest; while (n) { if ((*tmp = *src) != 0) { src++; } tmp++; n--; } return dest; } int main(void) { char dest[BUFSIZE], src[BUFSIZE]; size_t n; printf("Please input a string: "); scanf("%s", src); printf("Please input a byte: "); scanf("%zu", &n); mystrncpy(dest, src, n); dest[n] = '\0'; printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
実行結果は以下になります.
1 2 3 4 5 6 |
$ gcc mystrncpy.c $ a.out Please input a string: abc Please input a byte: 2 src = abc dest = ab |
strcpy_s関数
1 |
errno_t strcpy_s(char *dest, rsize_t dest_size, const char *src); |
strcpy_s関数は,srcが指す文字列を末尾のヌルバイトも含めてdestが指すバッファにコピーします.
strcpy関数とは異なり,strcpy_s関数はdestのサイズdest_sizeを第2引数に指定することで,srcをdestに正常にコピーできるかどうかチェックします.
もし正常にコピーできない場合は,abort関数を呼び出します.
strcpy_s関数の返り値は,正常に終了した場合は0,それ以外の場合はエラーになります.
strcpy_s関数はVisual Studioでは利用できますが,GCC/Clangでは利用できないことに注意して下さい.
strcpy_s関数の使い方
strcpy_s関数の使い方は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <string.h> #define BUFSIZE 16 int main(void) { char dest[BUFSIZE], src[BUFSIZE]; printf("Please input a string: "); scanf("%s", src); strcpy_s(dest, sizeof(dest), src); printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
Visual Studioでの実行結果は以下になります.
1 2 3 4 5 6 |
Please input a string: abc src = abc dest = abc *.exe (プロセス *) は、コード 0 で終 了しました。 このウィンドウを閉じるには、任意のキーを押してください... |
strcpy_s関数の自作関数
strcpy_s関数の自作関数は以下になります.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
/* * Author: Hiroyuki Chishiro * License: 2-Clause BSD */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <errno.h> #define BUFSIZE 16 errno_t mystrcpy_s(char *dest, rsize_t dest_size, const char *src) { if (dest == NULL) { abort(); return EINVAL; } else if (src == NULL) { dest[0] = '\0'; abort(); return EINVAL; } else if (dest_size <= strlen(src)) { dest[0] = '\0'; abort(); return ERANGE; } strcpy(dest, src); return 0; } int main(void) { char dest[BUFSIZE], src[BUFSIZE]; printf("Please input a string: "); scanf("%s", src); mystrcpy_s(dest, sizeof(dest), src); printf("src = %s\n", src); printf("dest = %s\n", dest); return 0; } |
実行結果は以下になります.同様です.
1 2 3 4 5 6 |
Please input a string: abc src = abc dest = abc *.exe (プロセス *) は、コード 0 で終 了しました。 このウィンドウを閉じるには、任意のキーを押してください... |
まとめ
C言語でstrcpy/strncpy/strcpy_s関数の使い方と自作関数を紹介しました.
strcpy/strncpy関数はGCC/Clang/Visual Studioで利用できますが,strcpy_s関数はVisual Studioしか利用できないことに注意して下さい.
文字列を追加するstrcat関数を学びたいあなたはこちらからどうぞ.
C言語を独学で習得することは難しいです.
私にC言語の無料相談をしたいあなたは,公式LINE「ChishiroのC言語」の友だち追加をお願い致します.
私のキャパシティもあり,一定数に達したら終了しますので,今すぐ追加しましょう!
独学が難しいあなたは,元東大教員がおすすめするC言語を学べるオンラインプログラミングスクール5社で自分に合うスクールを見つけましょう.後悔はさせません!