C言語のsizeofとstrlenの違いとは?初心者が混乱しやすいポイントを徹底解説

目次

はじめに

C言語で文字列を扱っていると、次のようなコードが出てきます。

C
char str[] = "hello";

printf("%zu\n", sizeof(str));
printf("%zu\n", strlen(str));

実行結果:

6
5

初心者さん

えっ? "hello" は5文字なのに、なぜ6?

ここはC言語初心者がかなり混乱しやすいポイントです。

実際、この違いを理解していないと、

  • バッファサイズミス
  • メモリ破壊
  • 通信データ異常
  • 文字列処理バグ

につながることがあります。

この記事では、

  • sizeofとは何か
  • strlenとは何か
  • なぜ結果が違うのか
  • \0(終端文字)との関係
  • 配列とポインタでの違い
  • 関数引数でハマるポイント

を図付きで分かりやすく解説します。


C言語文法解説シリーズ

本記事は「C言語文法解説シリーズ」の1つです。
C言語の文法を、組み込み開発の視点も交えて解説しています。

C言語文法解説シリーズ一覧はこちら

C言語の文法を基礎から体系的に解説するシリーズです。

先に以下の記事を読むと理解しやすくなります。

👉 「文字列とは?」
👉 「char配列とポインタの違いとは?」


まず結論

まずは違いを整理します。

項目sizeofstrlen
意味メモリサイズ取得文字列長取得
単位byte文字数
\0 を含む?含む含まない
実行タイミングコンパイル時実行時
対象あらゆる型文字列専用

sizeofとは?

sizeof は、

👉 「変数や型のメモリサイズ」

を取得する演算子です。


C
int x;

printf("%zu\n", sizeof(x));

実行結果(32bit int環境):

4

つまり、

👉 int型は4byte

という意味です。


文字列で使うと?

C
char str1[] = "hello";

printf("%zu\n", sizeof(str1));

結果:

6

になります。

文字列についてはこちらの記事で解説しています。


なぜ6になる?

ここが重要です。

"hello" は内部的には:

h e l l o \0

だからです。


メモリ上のイメージ

文字列のメモリ上のイメージ

つまり6byte。

そのため、

C
sizeof(str1)

は:

6

になります。


strlenとは?

strlen は、

👉 「文字列長」

を取得する関数です。


C
char str1[] = "hello";

printf("%zu\n", strlen(str1));

結果:

5

になります。


なぜ5?

strlen() は、

👉 \0 が出るまで文字数を数える

関数だからです。

つまり:

h e l l o

までしか数えません。

\0 自体は含みません。


初心者さん

なるほど… sizeof はメモリサイズで、strlen は文字数なんですね

エンジニアくん

そう。\0 を含むかどうかが大きな違いなんだ


sizeofは演算子、strlenは関数

これも重要です。


sizeof

C
sizeof(str)

は演算子です。

コンパイル時にサイズが分かることが多いです。


strlen

C
strlen(str)

は関数です。

実行時に、

👉 1文字ずつ \0 を探して数える

処理をしています。


strlenの内部イメージ

イメージ的には:

C
count = 0;

while(str[count] != '\0') {
    count++;
}

のような処理です。


strlenは毎回走査する

つまり、

C
strlen(str)

は、

👉 毎回文字列を最後まで確認する

ということです。

長い文字列ではコストになります。


実務では注意

例えば:

C
for(i = 0; i < strlen(str); i++) {
    ...
}

これは毎回 strlen() を実行するため非効率です。


より良い書き方

C
size_t len = strlen(str);

for(i = 0; i < len; i++) {
    ...
}

こちらの方が効率的です。

組み込みでは特に重要です。


配列とポインタでsizeofは変わる

配列の場合

C
char str1[] = "hello";

printf("%zu\n", sizeof(str1));

結果:

6

ポインタの場合

C
char *str2 = "hello";

printf("%zu\n", sizeof(str2));

結果(64bit環境):

8

になることが多いです。


なぜ?

str2 は文字列そのものではなく、

👉 アドレスを保存しているポインタ変数

だからです。


メモリイメージ

文字列リテラルを指すポインタのメモリ上のイメージ

sizeof(str2) が見ているのは、

👉 ポインタ変数サイズ

です。

文字列長ではありません。

配列とポインタについてはこちらの記事で解説しています。


関数引数でハマる

一見すると配列

C
void func(char str[]) {
    printf("%zu\n", sizeof(str));
}

しかし実際には、

👉 ポインタ扱い

になります。


実行結果

64bit環境なら:

8

になることが多いです。


なぜ?

C言語では、

👉 配列を関数に渡すと先頭アドレスに変換される

からです。

これを「配列退化」と呼びます。


実務でよくあるバグ

例えば:

C
void func(char str[]) {
    memset(str, 0, sizeof(str));
}

一見正しそうですが、

👉 sizeof(str) は配列サイズではない

ため危険です。


初心者さん

関数に渡した瞬間、配列じゃなくなるんですか!?

エンジニアくん

そう。C言語ではかなり重要な仕様なんだ


strlenの危険性

strlen() は、

👉 \0 がある前提

で動きます。


\0 が無いと危険

例えば:

C
char str[5] = {'h','e','l','l','o'};

これは \0 がありません。


何が起きる?

C
strlen(str)

は、

👉 メモリ上を暴走して \0 を探す

可能性があります。

これは非常に危険です。


実務での使い分け


バッファサイズ確認

C
sizeof(buffer)

を使う。


文字数確認

C
strlen(str)

を使う。


通信処理では超重要

例えばUART送信:

C
send(str, strlen(str));

なら文字数。


配列初期化サイズ

C
char buf[sizeof(str)];

ならメモリサイズ。


まとめ

sizeofstrlen は似ていますが、意味は全く違います。

項目sizeofstrlen
取得するものメモリサイズ文字列長
\0含む含まない
配列配列サイズ取得文字数取得
ポインタポインタサイズ文字数取得

特に重要なのは:

  • sizeof はメモリサイズ
  • strlen は文字列長
  • \0 の扱いが違う
  • 関数引数では配列がポインタ化する

という点です。

ここを理解すると、

  • 文字列
  • 配列
  • ポインタ
  • メモリ
  • バッファ管理

の理解がかなり深まります。

この記事が参考になった方へ

文字列やポインタをさらに理解したい方は、こちらの記事もおすすめです。

配列とは?
ポインタとは?
文字列とは?

配列を含むC言語の基本文法をこちらの記事で整理しています。

エンジニアとして技術を学ぶことは重要ですが、
キャリアや副業についても同時に考える必要があります。

副業の現実や市場価値、今後のキャリア戦略については、
こちらの記事でまとめています。

技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。

小さなご相談からでもお気軽にご連絡ください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

組み込みソフトエンジニアとして働きながら、
C言語・メモリ・ポインタなどの基礎から実務まで解説しています。

副業・キャリアについても実体験ベースで発信中です。

X・Qiita・noteでも発信しています。
X:更新情報・日常
Qiita:技術発信
note:キャリア・副業

▼まずはここから読むのがおすすめ
C言語文法シリーズ
メモリ領域解説シリーズ
割り込み処理解説シリーズ
ソフトウェア設計解説シリーズ
キャリアと副業ロードマップ

コメント

コメントする


目次