Cをやると100人いたら100人躓くぽいんたー。
沙耶ですおはようございます。
あるところのとある記事にこんなソースコードが載っていました。タグのカッコ使えないから””にしちゃってるけど。
ZDNetのポインタの説明記事
#include “stdio.h”
int main( void ) {
int *n;
*n = 5; /* ポインタ変数nに値5を代入 */
printf( “%d\n”, *n ); /* ポインタ変数nが持つ値(5)の出力 */
return 0;
}
うへぇ。マジですか。いやーこれは知らなかったなぁ。
…冗談じゃすみません。これをマジに受けてプログラム書いたアホがいたらどう責任取るんですか。
ありえん。ていうかなんでこんなことになってんだ。ZDNetはコードのチェックもしないのか。
さて、わかる人は一目見ただけで愕然とするこのコード。何が起きるかやってみるといいでしょう。
PCが壊れても私は責任取りません。ZDNetに言ってください。
いまは一応訂正されていますが。
さて、ぽいんたーぽいんたー。ぽいんたーとは何者ぞや。
何者ってポイントするものですよ。ポイントって何かってお前レーザーポインターくらい知ってるだろう。
”指し示すもの”ですよ。
この前に変数って何かってのを理解してないとポインタには進めないわけです。
#include “stdio.h”
int main( void ) {
int n;
printf( “%d\n”, n );
return 0;
}
このときナニが出力されるかわかりますか。沙耶はわかりません。
int nによる変数が宣言された段階で、この変数にはまだなにも代入されていません。
int n;ってのはメモリ上にint分のメモリをデータの保存場所として確保しますよ、という命令ですね。
つまり、メモリのどっかにn用のデータ保存領域が確保されたわけです。
さて。メモリってのは使われたあと使わなくなったら解放することで他のプログラムや自分自身がそのメモリアドレスを再利用できます。
つまり、割り当てられたメモリは自分より前に実行された何かが使って、解放したメモリアドレスかもしれません。
メモリの中身をゼロクリアして開放するなんて普通はしませんから(開放すればいいだけ)、この中身は不定なわけです。
これをどんな中身にするか、ってのが初期化、とよばれる行為で、n=0;だとかint n=0;みたいに宣言します。
こうすると、そのメモリアドレスの中身をゼロという数値に書き換えてくれるわけです。
ここまでは普通バカでも知ってる。ていうかC/C++どころかその辺のLL言語ですら知ってなきゃいけない。LL言語は宣言と初期化を勝手にやってくれたりもするけどね。
じゃあ最初のコードを見てください。
int *n;ってのは、ポインタ変数nの宣言です。
ポインタ変数の中身は不定。初期化されていません。どこを指しているかは定まっていません。
ポインタ変数、というのも根っこの部分は変数同様です。ポインタというのは、アドレスを指し示すための変数であり、そのポインタがどのアドレスを指し示すか、というのを入れておく箱はメモリ上に確保されます。
つまり、この段階で*nはどこを指すか定かではありません。
その定かではないアドレスにいきなり5を代入しました。この5はどこに書き込まれるかわかりません。
こんぴーたーのメモリの中には、いろんな領域があります。
OSのカーネルのプログラムもまた、メモリ上に展開しています。
そのどっかが、フォーマット実行のトリガメモリであってもおかしくはないですね。もしかしたらそれはハードウェアとのインターフェースとのポート用に確保されている部分かもしれません。接続機器にいきなり5とかわけわからん数字が送られたらどうなるでしょう。
どっかのプログラムの一部がいきなり破壊されるかもしれません。
ポインタ変数。それは指し示すもの。
”どこを”指し示すかはまだ決まっていません。
int p=5;
int *n=&p;
*n=10;
これならわかりますよ? pをポインタ変数を介して10に書き換えてるだけですしね。
ソースのコメント通り、ポインタ変数nに5を代入するなら
*n=5ではなくてn=5です。
この場合の処理はたぶん処理系依存じゃないですかね。あんまやったことないですけど。アドレス直接記述になるかもしれませんが、ポインタの中身ってアドレスだけかね? C/C++だと型も記憶してるし、structureになってる気がしないでもないけど。コード読めば分かるだろw
ポインタ変数を宣言した時点で、このint型のポインタを記録しておくべき”ポインタ変数”のメモリ上の領域は確保されているので、そこの中身を書き変えることは問題ないかと思います。
しかし、*n=5はダメです。その中身がどこを指しているか定まっていないのに、突拍子もないとこを書き換えに行こうとするからです。
ポインタが危険とか言われちゃうのは、こういう阿呆なことをするとダメだからです。
まあ自分のプログラムコードとヒープエリアを超えて任意に操作できるというのが強みでもあり、たとえばメモリエディタのように、他のプログラムの実行領域をいじくり倒すためには必須ですね。
よくもまあこんなプログラムかけたなぁって思ったら、コメントで超指摘されまくってるのに、編集部はトンチンカンな回答ばかりを繰り返すという素敵なことをやっていました。
int *n;
scanf( “%d”, n ); /* *nの値をキーボードなどから入力(Enterで終了) */
printf( “%d\n”, *n ); /* nの値を出力 */
ほかにもこういう素敵なことが書かれていたり。
うわーこえーwwwwwwwwwwwwwwwwwwwwwwwwww
ポインタとは変数とアドレスの相互変換ではありませんwwwwwwwwwwwwwwwwwwwwww
変数とアドレスの相互変換は&ですw
ポインタはポインタであり独立した別モノです。
ていうか気持ちわりぃんだけどよくこんなコード提示できたなぉぃ…。
ポインタはCでの難解さの象徴のようにも言われますね。参照と同じようにとらえている人もいます。
リファレンスはオブジェクトを常に指し示し、オブジェクトから出ることができません。
ポインタはアドレスを指し示し、指し示す実体の外に平気で出ていけます。これは決定的な差で、危険性のすべてはここにあります。
もっともリファレンスとてオブジェクトを破棄すればリファレンスの指し示している先は実体がなくなっており、他のプログラムなどが利用する可能性もあるため、決して”絶対安全”ではありません。
しかし、いずれもその根底にある動作原理の部分ではかなり似ており、リファレンスがある程度きちんと理解できているならポインタとの違いも分からなければならないはずです。
っていうかそもそもこのレベルのが分からない人が他人に教えるとかおこがましいにも程というものがあります。
#プログラマ全員が知っておくべきだとまでは言いませんが、知っておいた方がいいことだと思います。
ていうか参照とポインタくらい理解しとけと…。
#プログラム書けます!って自信満々に言ってきて書くのがVBAってくらい泣けてくるな。
かがみんのブログだからねぇ…ある種の不確定性原理にでも支配されてるんじゃないの?(笑)
無能は箱の中の霧状態。ってか。
ってそれは誰も観測してねぇよばぁか!っていう悪口か貴様!!!!w
観測してなかったら「ぺたぺた」したりしないじゃん?www