https://youtu.be/blIxGlMTgrY
\textcolor{pink}{四国めたん: }教師役ですわ
\textcolor{lime}{ずんだもん: }生徒役なのだ
\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです
\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ
\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう
\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ
\footnotesize \textcolor{pink}{四国めたん:} 前回はメモリ領域に対する操作についてお話ししましたわ
\footnotesize \textcolor{lime}{ずんだもん:} おぼえているのだ
\footnotesize \textcolor{pink}{四国めたん:} 今回は char型 の配列である文字列の操作を簡単にする関数を幾つか見ていきますわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ操作で十分ではないのか?
\footnotesize \textcolor{pink}{四国めたん:} 実際にはメモリ操作とおおむね同じですが、 char型 の配列に限定されているので、少し便利になっていますわ
\footnotesize \textcolor{lime}{ずんだもん:} 使い勝手がよさそうなのだ
\footnotesize \textcolor{lime}{ずんだもん:} ところで英語も日本語も操作できるのか?
\footnotesize \textcolor{pink}{四国めたん:} いいえ、今回は英語の文字列の操作のみですわ
\footnotesize \textcolor{lime}{ずんだもん:} 日本語についても教えてほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} 日本語は、結構、難しいので、後の回で少し触れますわ
\footnotesize \textcolor{lime}{ずんだもん:} 待っているのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、基本的な文字列操作の関数は、メモリ操作と同じく"string.h"で宣言されているので最初にインクルードしますわ
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
strncpy
\footnotesize \textcolor{pink}{四国めたん:} まず最初はstrncpy
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strncpy
?
\footnotesize \textcolor{pink}{四国めたん:} はい、指定した文字列をコピーする関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcpy
との違いはなんなのだ?
\footnotesize \textcolor{pink}{四国めたん:} おおむね同じですが、NUL終端をコピーしたら、コピーを終了しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 形式は同じなのか?
\footnotesize \textcolor{pink}{四国めたん:} 形式としてはchar* strncpy(char* dst, const char* src, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} memcpy
ではvoid*
となっている部分がchar*
となっているのだ
\footnotesize \textcolor{pink}{四国めたん:} 対象が文字列ですから
\footnotesize \textcolor{pink}{四国めたん:} ちなみに、古い形式でstrcpy
と云う関数がありますがセキュリティーの関係で使わない方が望ましいですわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、Visual Studioでは同様の関数としてerrno_t strcpy_s(char* dst, rsize_t num, const char* src)
が推奨されていますわね
\footnotesize \textcolor{lime}{ずんだもん:} 汎用性を考えたらstrncpy
の方が使いやすいのかな?
\footnotesize \textcolor{pink}{四国めたん:} そうですわね
\footnotesize \textcolor{lime}{ずんだもん:} ところで詳細について教えてほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} まず、コピー元のポインタをsrc
に、コピー先のポインタをdst
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} memcpy
と同じなのだ
\footnotesize \textcolor{pink}{四国めたん:} そしてnum
にはコピーする最大の文字数をセットしますわ
\footnotesize \textcolor{pink}{四国めたん:} 基本的にはdst
にセットしたメモリ領域のサイズをセットしますわね
\footnotesize \textcolor{lime}{ずんだもん:} コピーする文字数ではないのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、コピーはNULまでと決まっていますので、メモリ領域を超えてコピーしないようにしているのですわ
\footnotesize \textcolor{pink}{四国めたん:} ちなみにコピー先のメモリ領域のサイズは、最低でも(コピー元の文字数 + 1)バイトである必要がありますわ
\footnotesize \textcolor{lime}{ずんだもん:} (+ 1)?
\footnotesize \textcolor{pink}{四国めたん:} はい、終端のNULをセットするために追加で1バイトを必要としますわね
\footnotesize \textcolor{lime}{ずんだもん:} ところでmemset
と同じく、コピー元とコピー先のメモリ領域が重なっていてはいけないのか?
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{lime}{ずんだもん:} memmove
に相当する関数はないのか?
\footnotesize \textcolor{pink}{四国めたん:} ありませんわね
\footnotesize \textcolor{pink}{四国めたん:} メモリ領域が重なっている場合には、memmove
で代用して下さい
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
\footnotesize \textcolor{pink}{四国めたん:} 戻り値に関してはdst
にセットした値がそのまま返りますわ
\footnotesize \textcolor{pink}{四国めたん:} ではサンプルコードを見ていきましょう
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE (15)
void main() {
char c[] = "This is a pen."; // 14文字+NUL終端
char* p = (char*)malloc(SIZE);
if (p != NULL) {
strncpy(p, c, SIZE);
printf("%s\n", p);
}
free(p);
p = NULL;
}
\footnotesize \textcolor{lime}{ずんだもん:} 「This is a pen.」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、問題なく文字列がコピーされていますわね
\footnotesize \textcolor{lime}{ずんだもん:} 詳細を説明してほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{lime}{ずんだもん:} まず、#define _CRT_SECURE_NO_WARNINGS
は何をしているのだ?
\footnotesize \textcolor{pink}{四国めたん:} 実はVisual Studioではstrcpy_s
関数を推奨しているため、strncpy
関数はエラーの対象となっていますわ
\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、ですので、エラーの対象から外すために#define _CRT_SECURE_NO_WARNINGS
をファイルの最初に宣言しますわ
\footnotesize \textcolor{pink}{四国めたん:} とりあえず#define _CRT_SECURE_NO_WARNINGS
をコメントアウトしてみましょう
//#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE (15)
void main() {
char c[] = "This is a pen."; // 14文字+NUL終端
char* p = (char*)malloc(SIZE);
if (p != NULL) {
strncpy(p, c, SIZE);
printf("%s\n", p);
}
free(p);
p = NULL;
}
\footnotesize \textcolor{lime}{ずんだもん:} 「C4996 strncpy : This function or variable may be unsafe. ...」というエラーが出ているのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、ですので#define _CRT_SECURE_NO_WARNINGS
を使うのですわ
\footnotesize \textcolor{lime}{ずんだもん:} #define _CRT_SECURE_NO_WARNINGS
を宣言するとエラーにならないのか?
\footnotesize \textcolor{pink}{四国めたん:} おまじないだと思って、そのまま宣言してくださいね
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
\footnotesize \textcolor{pink}{四国めたん:} 次にコピー元の文字列c
は文字列の最後を示す終端文字を含めて15文字の配列ですわ
\footnotesize \textcolor{lime}{ずんだもん:} 終端文字、NULのことか...
\footnotesize \textcolor{pink}{四国めたん:} コピー先はmalloc
でメモリ領域を確保しておきますわ
\footnotesize \textcolor{lime}{ずんだもん:} 15文字分なのだ
\footnotesize \textcolor{pink}{四国めたん:} 最後にコピーした文字列を表示していますわ
strcpy_s
Visual Studioでは、strncpy
の代わりにstrcpy_s
の使用を推奨しています
形式としてはerrno_t strcpy_s(char* dst, rsize_t num, const char* src)
です
strncpy
と比べて、引数の順番と、戻り値がエラー番号になっているところが異なります
また、num
にはコピー先のメモリ領域のサイズをバイト単位で指定するようになっています
当然ですが、コピー先のメモリ領域のサイズは、コピー元のNUL終端を含めた文字列の文字数より大きい必要があります
なお errno_t型 は、エラーを表す整数の型です
0は正常であることを示します
その他の数値については、"errno.h"にエラーが定義されています
ただ、strcpy_s
は標準の関数ではなく、Visual Stdioでのみ使える関数ですので、汎用性としてはstrncpy
の方が勝っています
安全性についてはstrcpy_s
の方が勝っていますので、状況に応じて選択しましょう
strlen
\footnotesize \textcolor{pink}{四国めたん:} 次はstrlen
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strlen
?
\footnotesize \textcolor{pink}{四国めたん:} はい、文字列の長さを取得する関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ操作には無かった関数なのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはsize_t strlen(const char* str)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} まず、文字列の先頭のポインタをstr
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は文字列の長さか?
\footnotesize \textcolor{pink}{四国めたん:} その通り、NULまでの文字数を返しますわ
\footnotesize \textcolor{lime}{ずんだもん:} とりあえず、具体例をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE (20)
void main() {
char c[] = "This is a pen."; // 14文字+NUL終端
char* p = (char*)malloc(SIZE);
if (p != NULL) {
size_t len = 0;
strncpy(p, c, SIZE);
len = strlen(p);
printf("%sの長さは%llu\n", p, len);
}
free(p);
p = NULL;
}
\footnotesize \textcolor{lime}{ずんだもん:} 「This is a pen.の長さは14」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、なおstrlen
の戻り値はあくまでも文字列の長さですわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ領域のサイズ、20バイトとは関係がないのか
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} さらにsizeof
と異なり配列でもmalloc
で取得したメモリ領域でも文字列でさえあれば正しい値を取得できますわ
\footnotesize \textcolor{lime}{ずんだもん:} 使い勝手がいいのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみにstrlen
の戻り値が size_t型 ですので変数len
は size_t型 で宣言していますわ
\footnotesize \textcolor{lime}{ずんだもん:} ところでprintf
中の%llu
はなんなのだ?
\footnotesize \textcolor{pink}{四国めたん:} size_t型 の値をprintf
で出力する場合には、書式指定として"%llu"を使用しますわ
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
strnlen / strnlen_s
Visual Studioでは、strlen
の代わりにstrnlen
やstrnlen_s
の使用を推奨しています
形式としてはsize_t strnlen(const char* str, size_t num)
やsize_t strnlen_s(const char* str, size_t num)
です
strlen
と比べて、引数にstr
のメモリ領域のサイズnum
が追加されているところが異なります
num
には文字列のメモリ領域のサイズをバイト単位で指定するようになっています
文字列にNUL終端が存在しない場合に、num
バイト以上のオーバーランを起こさないようになっています
戻り値は文字列の文字数です
num
にセットした値が返った場合には、エラーです
strnlen
もstrnlen_s
も標準の関数ではなく、Visual Stdioでのみ使える関数ですので、汎用性としてはstrlen
の方が勝っています
安全性についてはstrnlen
やstrnlen_s
の方が勝っていますので、状況に応じて選択しましょう
strncat
\footnotesize \textcolor{pink}{四国めたん:} 次はstrncat
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strncat
?
\footnotesize \textcolor{pink}{四国めたん:} はい、文字列の後ろに、指定した文字列を連結する関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} 文字列の連結はよく使うのか?
\footnotesize \textcolor{pink}{四国めたん:} 意外に使いますわね
\footnotesize \textcolor{lime}{ずんだもん:} そうなのか...
\footnotesize \textcolor{pink}{四国めたん:} 形式としてはchar* strncat(char* dst, const char* src, size_t num)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} strncpy
と似ているのだ
\footnotesize \textcolor{pink}{四国めたん:} strncpy
では上書きしますが、strncat
では後ろに付け加えるのが特徴ですわ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに、古い形式でstrcat
と云う関数がありますが、セキュリティーの関係で使わない方が望ましいですわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、Visual Studioでは同様の関数としてerrno_t strcat_s(char* dst, size_t num, const char* src)
が推奨されていますわね
\footnotesize \textcolor{lime}{ずんだもん:} これもstrncpy
と同じなのだ
\footnotesize \textcolor{pink}{四国めたん:} そうですわね
\footnotesize \textcolor{lime}{ずんだもん:} ところで詳細について教えてほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} まず、連結元の文字列のポインタをsrc
に、連結先の文字列のポインタをdst
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} strncpy
と同じなのだ
\footnotesize \textcolor{pink}{四国めたん:} そして連結先にコピーする文字列の最大の文字数をnum
にセットしますわ
\footnotesize \textcolor{pink}{四国めたん:} 通常は連結先のメモリ領域を超えて文字がコピーされないような文字数としますわね
\footnotesize \textcolor{lime}{ずんだもん:} (連結先のメモリ領域のサイズ - 連結先の文字数)でいいのか?
\footnotesize \textcolor{pink}{四国めたん:} そうですわね
\footnotesize \textcolor{pink}{四国めたん:} ただ、終端のNULを考慮すれば、連結先のメモリ領域のサイズは、(連結先の文字数 + 連結元の文字数 + 1)バイト以上であることが必要ですわ
\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ
\footnotesize \textcolor{pink}{四国めたん:} なお、戻り値に関してはdst
にセットした値がそのまま返りますわ
\footnotesize \textcolor{pink}{四国めたん:} サンプルコードを見てみましょう
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#define SIZE (50)
void main() {
char c1[SIZE] = "This is a pen."; // 14文字+NUL終端
char c2[] = "This is an apple."; // 17文字+NUL終端
size_t len = SIZE - strlen(c1);
strncat(c1, c2, len);
printf("%s\n", c1);
}
\footnotesize \textcolor{lime}{ずんだもん:} 「This is a pen.This is an apple.」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、問題なく文字列が連結されていますわね
\footnotesize \textcolor{lime}{ずんだもん:} 詳細の説明をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、まずc1
を文字列として宣言、初期化していますわ
\footnotesize \textcolor{lime}{ずんだもん:} 配列のサイズをSIZE
として指定する必要があるのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、文字列を連結した後に必要なサイズの配列を確保する必要がありますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} 次にc2
を文字列として宣言、初期化していますわ
\footnotesize \textcolor{lime}{ずんだもん:} c2
は配列のサイズを指定しなくてもいいのか?
\footnotesize \textcolor{pink}{四国めたん:} 連結元の文字列は文字数分のサイズが確保されていればOKなので、サイズの指定は、いりませんわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} 引数num
にセットする長さlen
は、連結先のメモリサイズSIZE
からc1
の文字数をstrlen
で取得して引いていますわ
\footnotesize \textcolor{lime}{ずんだもん:} c2
の文字列のサイズ、(17文字 + 1)バイトには十分なサイズなのだ
\footnotesize \textcolor{pink}{四国めたん:} あとはstrncat
で文字列を連結した後、printf
で表示していますわ
strcat_s
Visual Studioでは、strncat
の代わりにstrcat_s
の使用を推奨しています
形式としてはerrno_t strcat_s(char* dst, size_t num, const char* src)
です
strncat
と比べて、引数の順番と、戻り値がエラー番号になっているところが異なります
また、num
には連結先のメモリ領域のサイズをバイト単位で指定するようになっています
strncat
と異なり、(連結先のメモリ領域のサイズ - 連結先の文字数)ではないことに注意が必要です
余計な計算をする必要がない分、strncat
よりも使い勝手は良いかもしれません
当然ですが、連結先のメモリ領域のサイズは、NUL終端を含めた、連結元の文字列と連結先の文字列の合計よりも大きい必要があります
なお errno_t型 は、エラーを表す整数の型です
0は正常であることを示します
その他の数値については、"errno.h"にエラーが定義されています
ただ、strcat_s
は標準の関数ではなく、Visual Stdioでのみ使える関数ですので、汎用性としてはstrncat
の方が勝っています
安全性についてはstrcat_s
の方が勝っていますので、状況に応じて選択しましょう
strcmp
\footnotesize \textcolor{pink}{四国めたん:} 次はstrcmp
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strcmp
?
\footnotesize \textcolor{pink}{四国めたん:} はい、指定した文字列を比較して同じかどうかをチェックする関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} memcmp
と同じ感じか?
\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはint strcmp(const char* str1, const char* str2)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} まず、比較する文字列へのポインタをstr1
とstr2
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は比較の結果か?
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} 完全に一致していれば0が、一致していなければ0以外が返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} とりあえず、具体例をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
#include <stdio.h>
#include <string.h>
void main() {
char c1[] = "This is a pen."; // 14文字+NUL終端
char c2[] = "This is an apple."; // 17文字+NUL終端
if (strcmp(c1, c2)) {
printf("c1とc2は異なる文字列です\n");
} else {
printf("c1とc2は同じ文字列です\n");
}
}
\footnotesize \textcolor{lime}{ずんだもん:} 「c1とc2は異なる文字列です」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、strcmp
は文字列が一致していないので0以外を返しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 0以外の整数ということは、真偽値ではtrue
と同じということか
\footnotesize \textcolor{pink}{四国めたん:} はい、ですのでprintf
では「c1とc2は異なる文字列です」が表示されますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに比較する文字列を変えて同じ内容にすれば、結果は「c1とc2は同じ文字列です」と表示されますわ
\footnotesize \textcolor{lime}{ずんだもん:} ところで#define _CRT_SECURE_NO_WARNINGS
は無くてもいいのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、strcmp
はセキュリティー上の問題はありませんので不必要ですわね
strstr
\footnotesize \textcolor{pink}{四国めたん:} 次はstrstr
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strstr
?
\footnotesize \textcolor{pink}{四国めたん:} はい、文字列から指定した文字列を検索しますわ
\footnotesize \textcolor{lime}{ずんだもん:} メモリ操作には無かった関数なのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはchar* strstr(const char* str1, const char* str2)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} まず、検索対象の文字列へのポインタをstr1
にセットしますわ
\footnotesize \textcolor{pink}{四国めたん:} そして検索する文字列へのポインタをstr2
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は char型 のポインタなのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、検索対象の文字列中に検索文字列が見つかった場合は、最初にヒットした文字列の先頭のポインタが返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} 検索文字列が見つからなかった場合にはどうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 検索文字列が見つからなかった場合にはNULL
が返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} サンプルコードを見てみましょう
#include <stdio.h>
#include <string.h>
void main() {
char c1[] = "This is a pen."; // 14文字+NUL終端
char c2[] = "pen";
char* p1 = strstr(c1, c2);
char* p2 = strstr(c1, "a");
if (p1 != NULL) {
printf("pen以下の文字列は\"%s\"です\n", p1);
}
if (p2 != NULL) {
printf("a以下の文字列は\"%s\"です\n", p2);
}
}
\footnotesize \textcolor{lime}{ずんだもん:} 「pen以下の文字列は"pen."です」、「a以下の文字列は"a pen."です」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、どちらもちゃんと検索できましたわね
\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、p1
には文字列c1
からc2
を検索していますわ
\footnotesize \textcolor{lime}{ずんだもん:} c1
にはc2
の"pen"が含まれているので、p1
には"p"へのポインタがセットされるのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、そしてp2
は1文字の文字列"a"をc1
から検索していますわ
\footnotesize \textcolor{lime}{ずんだもん:} c1
には"a"が含まれているので、p2
には"a"へのポインタがセットされるのだ
\footnotesize \textcolor{pink}{四国めたん:} そして得られたポインタからNUL終端までの文字列をprintf
で表示していますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{lime}{ずんだもん:} ところでstrstr(c1, 'a')
と、検索文字列に"a"の代わりに、文字'a'を使ってはいけないのか?
\footnotesize \textcolor{pink}{四国めたん:} 'a'は char型 で、ポインタ型ではありませんので、使えませんわね
\footnotesize \textcolor{pink}{四国めたん:} 無理に文字 a を検索文字列として指定すると警告が出ますし、実行するとエラーとなりますわね
\footnotesize \textcolor{lime}{ずんだもん:} 検索文字列に文字を使うのは止めておくのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに文字を検索する場合にはchar* strchr(const char* str, int character)
という別の関数があるので、そちらを使いますわ
\footnotesize \textcolor{lime}{ずんだもん:} 指定する文字は int型 だが問題ないのか?
\footnotesize \textcolor{pink}{四国めたん:} まぁ、 char型 は int型 に代入できるので、OKですわ
\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ
\footnotesize \textcolor{lime}{ずんだもん:} ところでstrstr
でも#define _CRT_SECURE_NO_WARNINGS
は無くてもいいのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、strstr
は多少セキュリティー上の問題はありますが、不必要ですわね
memchr
メモリ操作には、strchr
と同じ動作をするmemchr
という関数があります
形式はvoid* memchr(const void* p, int value, size_t num)
となります
なおp
はチェックするメモリ領域へのポインタ、num
はチェックするバイト数です
基本的にはメモリ領域のサイズを指定します
value
には検索する値をセットします
int型 ですが、検索する際には unsigned char型 として扱われます
検索はバイト単位で行われ、最初に見つかった値のアドレスが返ります
見つからなければNULL
が返ります
strtok
\footnotesize \textcolor{pink}{四国めたん:} 最後はstrtok
ですわ
\footnotesize \textcolor{lime}{ずんだもん:} strtok
?
\footnotesize \textcolor{pink}{四国めたん:} はい、この関数は少し変わった関数で、文字列を指定の区切り文字で分割しますわ
\footnotesize \textcolor{lime}{ずんだもん:} 変わった関数なのか?
\footnotesize \textcolor{pink}{四国めたん:} 通常の関数は1回だけ呼び出して終わりですが、この関数は複数回、連続して呼び出すことで完了する、珍しい関数ですわ
\footnotesize \textcolor{lime}{ずんだもん:} 確かに珍しいのだ
\footnotesize \textcolor{pink}{四国めたん:} 形式としてはchar* strtok(char* str, const char* delimiters)
となりますわ
\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ
\footnotesize \textcolor{pink}{四国めたん:} なお、Visual Studioでは同様の関数としてchar* strtok_s(char* str, const char* delimiters, char** context)
が推奨されていますわ
\footnotesize \textcolor{lime}{ずんだもん:} とりあえず詳細について教えてほしいのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、最初の呼び出しでは、分割する文字列へのポインタをstr
にセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} 最初の呼び出し?
\footnotesize \textcolor{pink}{四国めたん:} はい、strtok
は複数回、呼び出すことが前提ですので、最初の呼び出しと2回目以降の呼び出しは少し違いますわね
\footnotesize \textcolor{lime}{ずんだもん:} 2回目以降はどうするのだ?
\footnotesize \textcolor{pink}{四国めたん:} 2回目以降の呼び出しではstr
にNULL
をセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} 分割する文字列をセットするのは初回だけなのだな
\footnotesize \textcolor{pink}{四国めたん:} 次にdelimiters
には分割に使用する区切り文字を文字列としてセットしますわ
\footnotesize \textcolor{lime}{ずんだもん:} うん?区切り文字は1文字ではないのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、区切り文字は1文字ですが、複数の区切り文字を指定できますわ
\footnotesize \textcolor{lime}{ずんだもん:} それは便利なのだ
\footnotesize \textcolor{pink}{四国めたん:} そして戻り値には分割された文字列へのポインタが返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} 分割した文字列の全てが返るのか?
\footnotesize \textcolor{pink}{四国めたん:} 基本的に、分割された文字列は複数になりますが、戻り値は1つの文字列しか返せませんわね
\footnotesize \textcolor{pink}{四国めたん:} ですので、初回の呼び出しの戻り値には、分割された最初の文字列が返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} 2番目以降の分割された文字列は、どのように取得するのだ?
\footnotesize \textcolor{pink}{四国めたん:} 2番目以降の分割された文字列は、続けてstrtok
関数を呼び出すことで取得しますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほど、それが 複数回、呼び出すことが前提 の意味なのか
\footnotesize \textcolor{pink}{四国めたん:} その通りですわ
\footnotesize \textcolor{pink}{四国めたん:} 2番目以降の分割された文字列は、続けてstrtok
関数のstr
にNULL
をセットして呼び出すことで得られますわ
\footnotesize \textcolor{lime}{ずんだもん:} 分割された文字列が無くなった場合には、どうなるのだ?
\footnotesize \textcolor{pink}{四国めたん:} 分割された文字列を取得できない場合にはNULL
が戻り値として返りますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} ではサンプルコードを見ていきましょう
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
void main() {
char c[] = "This is a pen. This is an apple.";
char* p = strtok(c, " .");
while (p != NULL) {
printf("%s\n", p);
p = strtok(NULL, " .");
}
}
\footnotesize \textcolor{lime}{ずんだもん:} 「This」「is」「a」「pen」「This」「is」「an」「apple」と表示されたのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、しっかりと単語毎に文字列の取得ができていますわね
\footnotesize \textcolor{lime}{ずんだもん:} プログラムの解説をおねがいするのだ
\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ
\footnotesize \textcolor{pink}{四国めたん:} 最初のstrtok
関数のコールでは、分割する文字列c
と区切り文字として空白' 'とピリオド'.'を文字列にまとめて与えていますわ
\footnotesize \textcolor{lime}{ずんだもん:} 区切り文字は幾つでも指定できるのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、全ての区切り文字を文字列にまとめて指定しますわ
\footnotesize \textcolor{pink}{四国めたん:} その後はNULL
が返るまで繰り返しstrtok(NULL, " .")
を呼び出していますわ
\footnotesize \textcolor{lime}{ずんだもん:} p
には文字列へのアドレスが入るのか?
\footnotesize \textcolor{pink}{四国めたん:} はい、strtok
を呼び出す毎に区切り文字で区切られた文字列のアドレスが入りますわ
\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ
\footnotesize \textcolor{pink}{四国めたん:} ちなみに char型 の配列としてのc
はstrtok
呼び出し後には変更されてしまいますわね
\footnotesize \textcolor{pink}{四国めたん:} ですので、c
にはconst
キーワードを付けてはいけませんわ
\footnotesize \textcolor{lime}{ずんだもん:} strtok
関数が勝手に変更してしまうのか...
\footnotesize \textcolor{pink}{四国めたん:} まぁ、そういう意味でも珍しい関数ですわね
\footnotesize \textcolor{lime}{ずんだもん:} ところで#define _CRT_SECURE_NO_WARNINGS
をファイルの最初に宣言しているのだ
\footnotesize \textcolor{pink}{四国めたん:} はい、strtok
関数は、Visual Studioではエラーの対象なので必要ですわね
strtok_s
Visual Studioでは、strtok
の代わりにstrtok_s
の使用を推奨しています
形式としてはchar* strtok_s(char* str, const char* delimiters, char** context)
です
strtok
と比べてcontext
が追加されています
なお、context
の型であるchar**
は、 char型 のポインタのポインタです
char*
のポインタですね
context
は関数内部でのみ使用します
とりあえず char*型 の変数を宣言して、そのアドレスをセットします
具体的には以下のように使用します
#include <stdio.h>
#include <string.h>
void main() {
char c[] = "This is a pen. This is an apple.";
char* pcontext = NULL;
char* p = strtok_s(c, " .", &pcontext);
while (p != NULL) {
printf("%s\n", p);
p = strtok_s(NULL, " .", &pcontext);
}
}
strtok_s
は標準の関数ではなく、Visual Stdioでのみ使える関数ですので、汎用性としてはstrtok
の方が勝っています
安全性についてはstrtok_s
の方が勝っていますので、状況に応じて選択しましょう
まとめ
\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした
\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ
\footnotesize \textcolor{pink}{四国めたん:} 以上で 文字列操作 についての説明は終わりですわ
\footnotesize \textcolor{pink}{四国めたん:} 文字列操作 のための標準関数は他にもいろいろとあるので標準Cライブラリのページなどで確認して下さい。
Discussion