コース一覧
    C言語基礎 ポインタ・構造体・ファイル
    scanfの&の正体

    C言語基礎 ポインタ・構造体・ファイル

    C言語のポインタ、構造体、ファイル操作を学び、データを扱う基礎を固めるコースです。

    1
    ポインタの入口
    01. アドレスとは15分
    02. ポインタの&と*15分
    03. scanfの&の正体15分
    04. 関数で値を書き換える15分
    05. 配列を関数に渡す15分
    06. つくる 入力処理の関数化15分
    07. 第7章クイズ10分
    2
    構造体とファイル
    01. 構造体15分
    02. メンバの読み書き15分
    03. 構造体配列15分
    04. 構造体と関数15分
    05. ファイルに書き込む15分
    06. ファイルを読み込む15分
    07. ファイルの失敗に備える15分
    08. つくる 保存機能15分
    09. 第8章クイズ10分
    3
    総合制作
    01. メニュー統合15分
    02. 自由拡張15分
    03. 完成と次のステップ10分

    scanfの&の正体

    おまじないを回収します

    第2章の「scanfで入力」で、こう書きました。

    c

    int score;
    scanf("%d", &score);

    このとき & については「scanf に変数を渡すときは前に付けると覚えてください、理由は第7章で分かります」と書いて、説明を先送りにしました。あわせて「なぜ printf には要らないのに scanf には要るのか」も宿題にしていました。ここまでで材料がそろったので、両方まとめて回収します。

    値を渡すだけでは書き換えられない

    第5章で、関数の引数は 値のコピー で渡ると学びました。呼び出された側は写しをもらうだけなので、その写しをいくら書き換えても、呼び出した側の変数は元のままです。

    scanf も普通の関数です。もし scanf("%d", score); と書いたら、scanf に渡るのは score の中身の写しだけです。scanf はキーボードから読んだ数値を「どこに」置けばよいのか分かりません。渡された写しに書いても、呼び出し元の score には届きません。

    そこで &score と書いて、値ではなく 番地 を渡していたのです。番地さえ受け取れば、scanf は前回学んだ * の要領で、その場所へ直接書き込めます。scanf の中では、おおよそ次のようなことが起きています。

    c

    /* scanf の内部のイメージ */
    int *p = 受け取った番地;
    *p = キーボードから読んだ値;

    つまり第2章の & は、scanf に「ここへ書き込んでください」と場所を教えるためのものでした。

    文字列に & を付けない理由

    第6章で名前を読むとき、& を付けませんでした。

    c

    char name[32];
    scanf("%31s", name);

    これは例外ではありません。配列名を式の中に書くと、先頭要素の番地に読み替えられます。つまり name はすでに番地なので、さらに & を付ける必要がないのです。逆に int や double のような普通の変数は番地ではないので、& が要ります。

    printf に & が要らない理由

    同じことを printf 側から見ると、区別がはっきりします。

    c

    printf("%d\n", score);   // & は付けない
    scanf("%d", &score);      // & を付ける

    printf は値を表示するだけで、score を書き換えません。読むだけなら写しをもらえば足りるので、番地は不要です。一方 scanf は書き込むので番地が要ります。読むだけなら値、書き換えてもらうなら番地 という区別が、この章を通した考え方の軸になります。

    付け忘れは最悪の事故

    & を忘れても、コンパイラは警告を出すだけで止まらないことがあります。実行すると、でたらめな番地に書き込むことになり、その場では動いているように見えて、あとから関係のない変数が壊れることさえあります。原因が見えにくい種類のバグなので、scanf を書いたら & の有無を必ず見直してください。

    では、scanf が本当に「教えた番地」へ書いていることを、ポインタで確かめてみましょう。

    要件

    1. 1行目で名前を、2行目で点数を読み込む
    2. 点数を読む前に int *p に score の番地を入れておく
    3. 名前を 「名前は佐藤です」 の形で表示する
    4. scanf のあとに *p で読んだ値を 「scanfが書いた値をpで読むと78点です」 の形で表示する
    5. p と &score が同じ番地かを判定して 「pとscanfに渡した番地は同じです」 と表示する

    ヒント

    名前は char name[32] に %31s で読み込みます。配列名なので & は付けません

    番地が同じかどうかは if (p == &score) で判定できます

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

    関連レッスン

    • 関数で値を書き換える

      ポインタを引数にして、呼び出し元の変数を書き換えられるようになります。

    • 配列を関数に渡す

      配列を引数に取る関数を書けるようになります。

    • つくる 入力処理の関数化

      入力処理をポインタ引数の関数として切り出せるようになります。

    • 第7章クイズ

      第7章の理解を確認します。

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

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

    • 変数データに名前をつけて参照する仕組み
    • 関数処理に名前を付けて再利用できる単位
    • 引数位置引数=順番で渡す。
    • 配列サイズ固定の同型データの集まり
    main.c
    エディタを読み込んでいます

    メモ

    scanfの&の正体

    ⌘S で保存