コース一覧
    C言語中級 文字列・構造体
    動的な文字列

    C言語中級 文字列・構造体

    C言語の文字列と構造体を学び、複数のデータを整理して扱うコースです。

    1
    文字列処理の実践
    01. strlenを自作する15分
    02. strcpyを自作する15分
    03. バッファオーバーフロー体験15分
    04. 文字列を分解する15分
    05. 動的な文字列15分
    06. つくる 名前入力の安全化15分
    07. 第3章クイズ10分
    2
    構造体とポインタ
    01. 構造体ポインタと->15分
    02. 構造体の動的確保15分
    03. 動的な構造体配列15分
    04. 関数ポインタ15分
    05. qsortで並べ替える15分
    06. つくる 動的Student完成15分
    07. 第4章クイズ10分

    動的な文字列

    64バイトの器はいつも無駄か足りないかのどちらか

    ここまでの回では、名前を受け取るのに char name[64] のような固定の器を使ってきました。この書き方には、いつも同じ悩みが付いてきます。"Ito" を入れるときは61バイトが遊び、それより長い名前が来たら切り詰めるしかありません。人数が増えるほど、無駄も切り詰めも積み上がります。

    第2章で覚えた malloc を使うと、長さが分かってからその長さぶんだけ確保できます。文字列の長さは strlen で分かるので、必要な量は計算できます。

    strlen + 1 の 1 は何か

    c

    char *p = malloc(my_strlen(s) + 1);

    + 1 は終端の '\0' の場所です。第1回で「見えている文字数と必要なバイト数は1ずれる」と書いたのが、ここで効いてきます。この + 1 を落とすと、文字は全部入るのに終端だけがはみ出す、という壊れ方をします。表示すると後ろのごみが続けて出るか、そのまま落ちます。

    写すときは終端まで含めて運びます。i <= len と、等号が入っているところが要点です。

    c

    for (int i = 0; i <= len; i++) {
        p[i] = s[i];
    }

    i < len にすると終端が写らないので、せっかく確保した1バイトが使われないまま終わります。

    確保したものは誰のものか

    malloc が返した領域は、free を呼ぶまで生き続けます。関数を抜けても消えません。これが char name[64] のようなローカル配列との決定的な違いです。第2章で「関数の中のローカル変数のアドレスを返してはいけない」と学びましたが、malloc した領域なら返して構いません。呼び出し元がそれを受け取り、そして 解放する責任も一緒に受け取ります。

    つまり my_strdup のような関数を書いたら、それは「使い終わったら free してください」という約束を呼び出し側に押し付ける関数だということです。標準ライブラリの説明で「返り値は free すること」と書かれているのは、この責任の受け渡しを言葉にしたものです。

    責任の所在があいまいなまま人数が増えると、解放漏れが静かに積もります。今回は確保した回数と解放した回数を自分で数えて、数字が一致することを目で確かめます。数が合っていれば、少なくとも数え漏らしはありません。

    解放したあとのポインタ

    free(p) を呼んでも、p の中身は消えません。手放したはずの番地がそのまま残ります。この状態のポインタを使うと、すでに他人のものになった領域を読み書きすることになります。落ちるとは限らず、しばらく普通に動いてから遠くで壊れるので、原因を追うのが非常に厄介です。

    対策は簡単で、free した直後に p = NULL; と入れておきます。NULL は誰も指していないことを表す特別な値なので、うっかり使えばその場で落ちます。静かに壊れるより、その場で落ちてくれるほうがずっと安全です。

    では、名前を必要な長さだけ確保して保持するプログラムを書いてみましょう。

    要件

    1. my_strdup という関数を書く。malloc で長さ+1バイト確保して写す
    2. 確保するたびに alloc_count を1増やす
    3. 各名前を Tanaka 6文字 の形で1行ずつ表示する
    4. 全部 free して、解放するたびに free_count を1増やす
    5. 最後に 確保3回 解放3回 の形で表示する

    ヒント

    確保するバイト数は my_strlen(s) + 1 です。+1 は終端のぶんです

    写すループの条件を i <= len にすると終端まで写ります

    free したあとの names[i] には NULL を入れておくと、うっかり使うのを防げます

    生田 陸人
    監修生田 陸人
    ゆめさくエンジニア / 現役ソフトウェアエンジニア監修者プロフィールを見る →
    編集 ゆめさく編集部·公開 2026/08/07

    関連レッスン

    • つくる 名前入力の安全化

      入力処理を、あふれない形に全面的に書き直せるようになります。

    • 第3章クイズ

      文字列の内部構造と安全な扱い方の理解を確認します。

    • 構造体ポインタと->

      アロー演算子でメンバを読み書きできるようになります。

    このレッスンに出てくる用語

    意味があいまいなまま進んだ語は、ここから読み直せます。

    • 関数処理に名前を付けて再利用できる単位
    • 配列サイズ固定の同型データの集まり
    • 変数データに名前をつけて参照する仕組み
    • 標準ライブラリPythonに同梱の公式モジュール群
    main.c
    エディタを読み込んでいます

    メモ

    動的な文字列

    ⌘S で保存