C言語でポインタ変数を意味する*(アスタリスク)について悩んだことがあります


1209068_44079740


やはりポインタでつまづきました

C言語におけるポインタの*(アスタリスク)に関する話をします。僕は以前、はじめてC言語を勉強しているときにポインタでつまづきました。まあ、初心者がつまづく定番ポイントですが(笑)

具体的には、ポインタを勉強していると、やたらと出てくる*(アスタリスク)という記号をどう理解したら良いのか、悩みまくったことがあります。ポインタを理解している方からすれば、まるでバカみたいなことなんですが、まったくの初心者であった僕にとってはホントに大きな問題でした。ソフトウェアのエンジニアとしての人生が左右されるぐらい大きな問題だったかもしれません(笑)

理解するのに苦しんだ*

具体的にどんなことに悩んでいたかを話したいと思います。
すごくあたりまえな話ですが、ポインタを勉強中の初心者の方にはあたりまえではない方もいるかもしれないので。(最近はC言語から勉強する人って少ないのかな?)

以下のコードを例にとって話をします。

コードの(a)でint*型の変数を宣言しています。その後(b)のmallocでメモリ領域を確保。(c)で整数値100をセット、そして(d)のprintfで表示しているだけです。いたって簡単なコードです。

[※追記](b)のmallocによるメモリ確保について
mallocは指定バイト分、メモリ領域を確保する関数でvoid*型のポインタを返します。ここではint型の変数1個分のメモリ領域を確保したいのでmallocにはsizeof(int)*1を渡しています。intは通常4バイトなので、4*1(=4)バイトを明示的に指定しても良いのですが、処理系によっては2バイトの場合もあるので明示的に4*1とせずにsizeof(int)*1としています。こうしておけばintが2バイトの環境でも4バイトの環境でもint型1個分のメモリが正しく確保できます。
また、(int *)にてキャストしているのは、mallocはvoid*型のポインタを返すので明示的にint*型ポインタにキャストしてint*型のintValに格納しています。mallocを使ってメモリ領域を確保する場合、
(long *)malloc(sizeof(long)*確保したい個数)
(char *)malloc(sizeof(char)*確保したい個数)
(float *)malloc(sizeof(float)*確保したい個数)
(double *)malloc(sizeof(double)*確保したい個数)
のように確保したい変数の型(longとかcharとか)のサイズに確保したい個数を乗じてバイト数を指定し、確保したい変数のポインタ型(long*とかchar*とか)でキャストして使用することがお決まりな感じです。

当然、結果は
スクリーンショット 2013-05-15 10.31.39
と表示されます。

さて、最初にポインタを教わるときに「*を付けると、中身の変数を表示できる」とか「*を付けると、ポインタ変数が指し示している中身にアクセスできる」などと言われることが多いのではないかと思います。

これは別に間違ってはいません。だから(c)で中身に整数値をセットしたり、(d)で中身を見たりできます。

ここで問題です。(a)では*を付けているから

とすれば(c)と同じように中身に整数値100をセットできる。YESかNOか?

結果はNOです。

なぜでしょうか?

過去、初心者の人にC言語を教えたことがありますが、さっきの質問をするとYESと答える人がそこそこいます。NOと答えた人でも、「なんとなく」とか「そういうコードを見たことがないから」とか「エラーになるから」みたいな理由で、明確なイメージをもって説明できる人はいません。初心者だから当たり前なんですが(笑)

僕は、NOと答えるタイプ(というかそんな質問をされたことはありませんが)でしたが、理由は「なんとなく」みたいなカンジでしっくりいかないまま時が過ぎていきました。

演算子ではない*

で、理由なんですが、

そもそも、この中身にアクセスできる*は間接演算子と呼ばれたりしているもので「ポインタ変数として宣言された変数」の前に付けるとその「ポインタ変数に格納されているアドレス(番地)」のメモリ領域にアクセスできる機能を持っています。中身を引っ張り出したり、中身をつっこんだりできるわけです。つまり(c)とか(d)で使われている*はまさにそれです。

ただ(a)で使われている*は間接演算子としての機能を持った*ではありません。この*は演算子ではないです。ここでの*は「この変数はポインタ変数ですよー。アドレスが格納される特殊な変数なんですよー」とお知らせする単なる記号です。int*の場合は「intサイズのメモリ領域を指し示すアドレスが格納される変数」、つまりintポインタ型として宣言しているわけです。

だから、(a)では整数値100をセットすることはできないのです。

僕はこの*が(a)と(c)では別のものというイメージはなかったので悩んでしまったのです。誰かに教えてもらうにも、どう質問すれば良いのかがわからず泥沼にハマってしまい、体重が激減したのを覚えています。

以上です。

初心者でポインタを勉強している方はハマらないように。

→C言語を勉強中の方はこちらの記事も読んでみると良いかも「C言語 要点を最低限おさえながら適当にやってみる

シェアして頂けると嬉しいです

















チャーム本店



価格.com ブロードバンド

価格.com 自動車保険









■コメントはお気軽にどうぞ