📝

「ポインタ渡し」なんてものは存在しません!【C言語入門】

に公開3
2

C言語の解説には歴史的経緯からか、あまり良くない記述が散見されます。
その中でも特に良くないのが「ポインタ渡し」です。

C言語には「値渡し」しかない

プログラミング言語において、引数の渡し方は2種類あります。

  • 値渡し
    変数の値をコピーして渡します。
    関数内で値が編集されても元の変数の値に変更はありません。
  • 参照渡し
    変数を指し示す参照だけを渡し、変数として振舞わせます。
    関数内で値が編集されると元の変数の値が変更されます。

皆さんがC言語を書いている時に、「変数として振舞う参照」とやらを見たことはないと思います。

「ポインタ渡し」なんてものはない

「でも入門書で『ポインタ渡し』っていうの見たよ! 値渡しでもないし、参照渡しでもないならどうなるの!?」と思うかもしれません。

簡単です。

「ポインタ渡し」なんてものは、C言語の仕様には存在しません

そもそも、ないんです。

「ポインタ渡し」の正体

まず、ポインタというものについて思い出してみましょう[1]

ポインタは変数の場所を指し示す値でしたよね。
そして、ポインタ p* をつける(*p)ことで元の変数を間接参照できるんでした。

ここで、「ポインタ渡し」だと思っていたものを見てみましょう。
まず引数にポインタ p を渡して、関数内では引数として受け取ったポインタ p に、 * をつける(*p)ことで、元の変数を間接参照していました。

……ちょっと待て。ただ、ポインタを間接参照しているだけでは?

だとしたら。渡したのはポインタで、受け取ったのも同じポインタです。
これって、値渡しと何が違うんでしょうか。

ポインタの値渡し

そうです。

今まで「ポインタ渡し」と呼んできたものは「ポインタの値渡し」。
つまりはただ、変数の場所を指し示す値(ポインタ)をコピーして渡しているだけだったのです。

なので、最初に「C言語には『値渡し』しかない」と書いたわけですね。

整数値を「値渡し」するか、ポインタを「値渡し」するか、文字を「値渡し」するか。
C言語は常に「値渡し」しかしないのです。

あとがき

個人的には、初心者に「ポインタ渡し」という用語を使って説明するのは、やめた方がいいと思っています。

理由は簡単で、「ポインタを値渡しすれば元の変数を間接参照して読み書きできる」ということがわからないとしたら、それはポインタ自体を理解していないということに他ならず、逆にわかるのであれば、「ポインタの値渡し」と言うことで一発で過不足なく理解できるからです。

もしそれがわからないのであれば、ポインタについてきちんと理解を深めるべきであって、「ポインタ渡し」という新しい語を使ってごまかすべきではありません。
なぜなら、C言語の本質はメモリを操作すること[2]であり、その過程でポインタの理解と利用は不可欠であるためです。

わかっている人同士の間であれば、「ポインタの値渡し」なんてまどろっこしい言い方は面倒ですし、「ポインタ渡し」と言ってもよいと思います。
便宜上そういった用語が使われる、それ自体は悪いことではありません。

しかし、初心者に「ポインタ渡し」という用語を使うと、ポインタについて学ぶ機会を奪う上に、C言語の引数の仕組みについて間違った認識を植え付けてしまいます
私はこれでだいぶ無駄な時間を過ごす羽目になりました。

もし、今後C言語を誰かに教える機会があるかもしれない、そういった人が読んでくれているなら、なるべく「ポインタ渡し」という用語を避けてほしいな、と思います。

脚注
  1. ポインタ自体がよくわからないという方には、先に私が前に書いた「ポインタが怖くなくなる!C言語メモリ操作の基本概念」を読むことをおすすめします。 ↩︎

  2. それこそ「ポインタが怖くなくなる!C言語メモリ操作の基本概念」の冒頭で書いたことそのままですが…… ↩︎

2

Discussion

めんくりめんくり

トレンドに入った結果、品質の悪いコメントでコメント欄が埋め尽くされてしまったため再投稿しました
内容に変更はありません

関連記事

ポインタについて理解するのが難しいという場合は、

https://zenn.dev/menndouyukkuri/articles/d385dde3bd7174

をお読みいただければわかりやすくなるかと思いますので、参考にどうぞ

前の記事でのコメント

良いコメント

以下に前の記事でいただいた、良いコメントのスクリーンショットを貼っておきますので、ぜひ参考にどうぞ
旧記事の良コメント

問題のあるコメント

前の記事で繰り返し問題のあるコメントをしていたアカウントを、以下に列挙しておきます

これらのアカウントによるコメントが確認された場合は無視してください
確認し次第、非表示対応を行います

HIAHIA

後書きを読むまでは全く腹落ちしなかったけれど、後書きを読んだら納得。学生時代の自分に教えてあげたい。
後書きに書いてあることの一部を最初に書いたらすんなり読める人も増える気がしました。

藤田望藤田望

この記事の主張はタイトルにもある通り「「ポインタ渡し」なんてものは存在しません」ということだと思いますが、C言語では関数に引数としてポインタを渡しオブジェクトにアクセス許可を与えることは普通に行われ、それを「ポインタ渡し」とも呼ぶことも珍しいことではありません。この筆者の言っている「ポインタ渡し」とはC言語で使用されている引数の仕組みの「値渡し(call by value)」やC言語には機能として存在しない「参照渡し(call by reference)」と同列に「ポインタ渡し」という仕組みが存在するとしている主張に対してそれを否定しているものではないかと思うのですがどうでしょうか。「値渡し」と同列に「ポインタ渡し」という仕組みが存在するという主張が誰によってなされているという具体的な説明がないため一人相撲にも見えます。

「値渡し」と同列に「ポインタ渡し」という仕組みが存在するという説明を行ってる書籍等(探せばあるとは思います)について具体的に挙げ、その間違いを指摘することであれば有意義とは思いますが、この記事の問題はC言語では関数に引数としてポインタを渡しオブジェクトにアクセス許可を与える普通に行われるとこを「ポインタ渡し」と呼ぶこと自体を否定してしまっていることだと思います。多くの人は「ポインタ渡し」を誤解なく使用しておりコミュニケーション上の行き違いも生じてないですね。この記事の作者は

しかし、初心者に「ポインタ渡し」という用語を使うと、ポインタについて学ぶ機会を奪う上に、C言語の引数の仕組みについて間違った認識を植え付けてしまいます。
私はこれでだいぶ無駄な時間を過ごす羽目になりました。

過去の個人的な勘違いを原因として「ポインタ渡し」という呼び方を否定されているようですが、それはコミュニティの利益を奪うことにもなるのではないかと思っています。
『C言語には「値渡し」と「ポインタ渡し」があると思っていたがそうじゃなかった!』のようなタイトルで、自分の過去の勘違いとそれを訂正する体で記事を書かれたら良かったのではないかと思いました。

X 3010:2003 (ISO/IEC 9899:1999) (のドラフト)(https://kikakurui.com/x3/X3010-2003-01.html)では「6.5.2.2 関数呼出し」 の注釈で

(78) 関数は,その仮引数の値を変更してもよいが,これらの変更が実引数の値に影響を与えることはできない。一方,オブジェクトへのポインタを渡すことは可能であり,関数はそれによって指されるオブジェクトの値を変更してもよい。

とポインタを渡した場合の挙動について説明があり、ISO/IEC 9899:2024(のドラフト)(https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3220.pdf)の 6.5.3.3 Function calls の注釈にも

  1. A function can change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function can then change the value of the object pointed to.

と同じことが説明されています。
用語としては定義されていないが概念的には存在することを何と呼ぶかをコミュニティが共通認識として持っていたとして、それは一個人が否定できるものではないと思います。

「ポインタ渡し」という表現は値渡しとは別の仕組みと勘違いする人が出るので使うべきでないということであれば記事の中で使われている「ポインタの値渡し」という表現も有害な筈ですが筆者が記事の中で平気でその表現を行っていることは二重規範に見えます。また、規格に用語が定義されていないことでもなんらかの語を割り当てることが有用であることを証明しているのは皮肉とも思います。
https://gemini.google.com/share/1ebb154c0ed8

ログインするとコメントできます
2