C言語で文字列の長さを取得する: strlen, wcslen
目次
C言語で文字列の長さを取得する
C言語では文字列を扱えます。
この記事ではC言語の文字列の長さを取得する方法を解説します。
文字列の長さは標準ライブラリのstrlen()
関数やwcslen()
関数を使います。
これらの関数はC言語では非常によく使われる関数です。
C言語に限らずプログラミングでは文字列の長さを得るシーンは多いと言えます。
C言語で文字列の長さを得る方法を押さえておくのはとても有用と言えるでしょう。
この記事では具体的に↓を見ていきます。
普通の文字列(マルチバイト文字列)の長さを取得する
ワイド文字列の長さを取得する
関連記事
C言語の文字列の使い方: 文字配列と文字列定数
C言語のchar型の配列(文字列)の使い方
C言語のatoi関数の使い方: 文字列を整数に変換する
普通の文字列(マルチバイト文字列)の長さを取得する
C言語の一般的な文字列は「マルチバイト文字列」と呼ばれる文字列です。
これはchar
型の文字列です。
このマルチバイト文字列の長さを取得するにはどうすればいいのでしょうか?
結論から言うとマルチバイト文字列の長さを得るにはstrlen()
関数を使います。
strlen()
関数の使い方を解説していきます。
strlen()関数の使い方
strlen()関数は引数の文字列の長さを返す関数です。
#include <string.h> size_t strlen(const char *s);
strlen()
関数を使うにはstring.h
をインクルードする必要があります。
厳密に言うとstring.h
をインクルードしなくても使えますが、インクルードしないとコンパイラが警告を出力します。
strlen()
関数は引数s
の長さを計算してsize_t
型でその長さを返します。
↓のように使います。
#include <stdio.h> #include <string.h> int main(void) { const char *s = "Hello"; size_t len = strlen(s); printf("%d\n", len); // 5 return 0; }
↑の場合、文字列はs
で内容は「Hello」になっています。
「Hello」の長さは5文字です。
strlen()
にs
を渡すとその文字列の長さが計算されて返ってきます。
その長さはlen
というsize_t
型の変数に保存されます。
printf()
でこのlen
という変数の値を出力すると結果は「5」になります。
strlen()に不正な文字列を渡すとどうなる?
strlen()
に不正な文字列を渡すとどうなるのでしょうか?
不正な文字列とはたとえばNULLポインタがそうです。
実際にやってみたいと思います。
strlen()にNULLポインタを渡す
↓のようにstrlen()
にNULLポインタを渡してみます。
#include <stdio.h> #include <string.h> int main(void) { size_t len = strlen(NULL); printf("%d\n", len); return 0; }
筆者の環境のコンパイラはGCCを使っていますが、GCCでは↑のコードをコンパイルして実行すると結果は「Segmentation fault」になります。
いわゆるセグフォというやつです。
この状態はプログラムがクラッシュしている状態です。
筆者の環境では↑のコードでセグフォになりましたが、環境によってはセグフォにならないこともあるので注意が必要です。
ここら辺はC言語のこわいところです。
(^ _ ^) | C言語こわい |
(・ v ・) | まんじゅうこわい |
strlen()にナル終端されていない文字列を渡す
次にナル終端されていない文字列をstrlen()
に渡してみます。
ナル終端されていない文字列とは、文字列の末尾にナル文字が付加されていない状態の文字列です。
この文字列はC言語では文字列として機能しません。
#include <stdio.h> #include <string.h> int main(void) { char s[] = {'H', 'e', 'l', 'l', 'o'}; size_t len = strlen(s); printf("%d\n", len); return 0; }
↑の場合、s
が文字列です。
s
には「Hello」が代入されていますが、ナル文字は代入されていません。
このような宣言の文字列はナル文字が自動で付加されません。
↑のコードを実行すると、筆者の環境では結果は「5」となってちゃんと出力されます。
しかし、メモリチェックツール(valgrindなど)で実行をチェックするとエラーが発生しているのがわかります。
つまり見た感じはちゃんと文字列の長さを取得できているように見えるのですが、メモリチェックツールでチェックすると隠れたバグが発生しているということになります。
メモリチェックツールを使わないとこの手のバグは検出できないので、非常にタチの悪いバグと言えます。
また筆者の環境ではたまたま「5」という結果が得られましたが、環境によってはこの「5」という結果も違うものになるでしょう。
おそらくスタックセグメントで確保されているs
の次のメモリ領域がたまたま0クリアされていただけだと思います。
strlen()
がその領域の値の「0」を検出して走査を終了したのでしょう。
(ただの想像ですが)
(^ _ ^) | 適当なこと言ってら |
自作my_strlen()関数を作る
strlen()
関数の簡易的な実装をやってみます。
ここではstrlen()
を自作してmy_strlen()
関数を作ってみたいと思います。
#include <stdio.h> /** * 自作のstrlen()関数 * 引数sの文字列の長さをsize_tで返す * * @param[in] s 文字列 * * @return 文字列の長さ */ size_t my_strlen(const char *s) { const char *p = s; for (; *p; p += 1) { } return p - s; } int main(void) { printf("%d\n", my_strlen("Hello")); // 5 return 0; }
↑のmy_strlen()
ではまずp
というポインタに引数のs
を代入します。
そしてfor
文でポインタのp
を回します。
終了条件は「*p
がナル文字じゃない間」です。
p += 1
でポインタ変数の持つアドレスがインクリメントされて、次のアドレスに進みます。
p
がナル文字に達したらループを終了します。
最後にp
とs
を引き算して進んだ個数を算出します。
その個数が文字列の長さになります。
my_strlen()の実装は正しいか?
今回実装したmy_strlen()
ですが、処理系の実装とはだいぶ違っています。
GCCの標準ライブラリであるglibcなどの実装ではもうちょっと凝ったことをやっています。
glibcのstrlen()
の実装ではロングワードが持つ「ビットの穴」への対処がしてあります。
その「ビットの穴」を考慮した文字列の長さを返すようにしているのがstrlen()
です。
今回自作したmy_strlen()
はその「ビットの穴」には対応していません。
そのため標準ライブラリよりは劣る実装になっています。
ワイド文字列の長さを取得する
次にワイド文字列の長さを得る方法を解説します。
C言語ではワイド文字列はwchar_t
型の文字列になります。
日本語の文字を1文字として扱いたい場合などにこのワイド文字列が使われます。
ワイド文字列の長さを得るにはそれ専用の関数を使います。
それがwcslen()関数です。
この関数を使うとワイド文字列の長さを取得することができます。
wcslen()関数の使い方
wcslen()
関数は引数のワイド文字列の長さを計算してsize_t
型で返します。
#include <wchar.h> size_t wcslen(const wchar_t *s);
wcslen()
を使うにはwchar.h
をインクルードしておく必要があります。
wcslen()
は↓のように使います。
#include <stdio.h> #include <wchar.h> int main(void) { const wchar_t *ws = L"こんにちは"; size_t len = wcslen(ws); printf("%d\n", len); // 5 return 0; }
↑の場合、ws
がワイド文字列の変数です。
その値は「こんにちは」になります。
これの長さは5文字です。
wcslen()
にws
を渡すとワイド文字列の長さが計算されます。
その結果はsize_t
型の変数len
に保存されます。
これをprintf()
で出力すると結果は「5」になります。
wcslen()に不正な文字列を渡すとどうなる?
strlen()
と同様にwcslen()
にも不正な文字列を渡したらどうなるのでしょうか?
結論から言うと結果はstrlen()
と同様です。
NULLポインタを渡したらセグフォになる場合がありますし、ナル終端されていない文字列を渡したらバグになります。
wcslen()
でも不正な文字列を渡さないように気をつけましょう。
自作my_wcslen()関数を作る
wcslen()
関数の簡易的な実装をやってみます。
ここではmy_wcslen()
という関数を作ります。
↓のようなコードになります。
#include <stdio.h> #include <wchar.h> /** * 自作のwcslen()関数 * 引数wsの文字列の長さを計算してsize_tで返す * * @param[in] ws ワイド文字列 * * @return ワイド文字列の長さ */ size_t my_wcslen(const wchar_t *ws) { const wchar_t *p = ws; for (; *p; p += 1) { } return p - ws; } int main(void) { const wchar_t *ws = L"こんにちは"; size_t len = my_wcslen(ws); printf("%d\n", len); // 5 return 0; }
実装的にはmy_strlen()
とほぼ同じです。
引数のws
の型がchar
からwchar_t
になっているのが違う点です。
実装の詳細についてはmy_strlen()
の解説をご覧ください。
引数のws
がNULLポインタかどうかチェックするコードを追加してもいいかもしれませんね。
(^ _ ^) | めざせ自作string.h |
(・ v ・) | 果たしてそれは正しいのか |
おわりに
今回はC言語の文字列の長さを取得する方法につて解説しました。
文字列の長さの取得はプログラミングではよく行われる処理です。
C言語の文字列の長さを取得する方法を覚えておくのは非常に有用と言えるでしょう。
この記事があなたのなにかの参考になれば幸いです。
(^ _ ^) | 文字列の長さをゲット |
(・ v ・) | ゲット! |