ポインタについて考える

derok
記事: 51
登録日時: 12年前

ポインタについて考える

投稿記事 by derok » 9年前

C言語のポインタが何故難しいと言われいうのか、についての考察です。
結論から言えば「ポインタは難しいという意識」が最大の原因ではないかと思います。
正確には違いますか、ポインタ=ポインタ変数としときます。
で、ポインタはただの変数なのにも関わらず特別視するがゆえに分からなくなっているように思えます。
要するに難しく考えすぎなのでは?という話です。

ポインタを教える際アドレスという概念は必要なのか
正直ポインタを使う際、メモリー構造なんて滅多に意識しないでしょう。
今まで変数はただの箱と説明してきたのだから、その箱に間接的にアクセスできるものと説明しればいいと思います。
ここがわかりにくいのかと思いましたが、この概念はC#やJavaなど、多くの言語が持ってます。
C言語特有ではありません

CODE:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test_Cs {
    class Program {
        class A {
            public int key1;
            public int key2;
        }

        static void Main(string[] args) {
            A obj = new A();
            A obj1 = obj;
            obj.key1 = 100;
            obj1.key2 = 200;
            Console.Write("obj.key1={0}\n",obj.key1);
            Console.Write("obj.key2={0}\n", obj.key2);
            Console.Write("obj1.key1={0}\n", obj1.key1);
            Console.Write("obj1.key2={0}\n", obj1.key2);
        }
    }
}

CODE:

#include 
typedef struct {
	int key1;
	int key2;
} A;
int main() {
	A object;
	A*obj=&object;
	A*obj1=obj;
	obj->key1=100;
	obj1->key2=200;
	printf("obj->key1=%d\n",obj->key1);
	printf("obj->key2=%d\n", obj->key2);
	printf("obj1->key1=%d\n", obj1->key1);
	printf("obj1->key2=%d\n", obj1->key2);
	return 0;
}
以上の二つコードですが、変数の関係を図で表すとこうなります。
画像
画像
見てのとおりほとんど同じです。
C言語の場合ローカル変数の寿命に気を付ける必要がありますが、それはポインタの「理解」には関係のない話でしょう。
int型なども似たような感じです。

CODE:

#include 
int main() {
	int a=10;
	int*pa=&a;
	*pa=20;
	printf("a=%d\n",a);
	printf("*pa=%d\n",*pa);
}
要素数1の構造体だと考えれば、その要素の名前をkeyとしたとき*paはa->keyみたいなものだと思えば分かりやすいと思います。
ポインタはただの変数
ポインタはただの変数です。
代入のシステムは普通のint型と同じく何を指しているかをコピーしています。
intとint*は全く別の型です。&演算子と*演算子によって相互に変換できるだけです。
この相互に変換できる関係をA*型はA型のポインタと呼んでいるだけです。
C#のA[]型はAの配列と同じです。これは[]で変換できますね。

ダブルポインタも特別なことはありません。int**型はint*型のポインタ型です。int型とint*型、上記のA型とA*型の関係と同じです。
+や-はintやdoubleと違います。
ですが、C#での"aaa"+"bb"と1+2は違う処理ですが同じ演算子を使ってます。
それと同様、ポインタ型に対する+-が違う処理でもおかしくはないと思います。
違う型なんですから。
ポインタと配列
ポインタの分かりにくい性質をあげるならこれになるでしょう。
しかし、普通の変数とポインタの関係と配列変数とポインタの関係を同時に使う事なんて滅多にありません。
それぞれ分けて考えるべきだと思います。
文脈によって意味が変わるなんて日本語ではよくあることでしょう。
関数名や変数名をみればどちらかなんてわかると思います。
それにポインタ演算なんて使わくても問題ないと思います。
mallocとポインタ
これに関しては簡単です。
普通の変数

CODE:

型 * 変数名 = malloc(sizeof(型名));
配列

CODE:

型 * 配列名 = malloc(sizeof(型名)*要素数);
以上2パターンがmallocの使い方の全てといっても過言ではないと思います。
使わなくなったらfreeで解放する必要がありますが、これもポインタの理解には関係ないと思います。
総評
確かにC言語のポインタに分かりにくい要素はありますが、それはC#やJavaなどの多言語にもいえることです。
C#やJavaにはポインタがないとよく聞きますが、似たようなものがある以上かなり語弊のある言い方な気がします。
追記
すみませんC#にポインタがあるのを忘れてました。
最後に編集したユーザー derok on 2016年4月05日(火) 18:10 [ 編集 1 回目 ]

YuO
記事: 947
登録日時: 15年前

Re: ポインタについて考える

投稿記事 by YuO » 9年前

C#にはポインター型がありますよ。
unsafeオプション等が必須で,色々制約つきますが,System.Drawing.Bitmap.LockBitsで得たBitmapDataScan0をint *に変換して画像処理,などの時に使います。
オフトピック
System.Runtime.InteropServices.Marshal.CopyでManagedにコピーしながら使うのが通常の使い方ですが,昔使ったときはだいぶ速度差がでました。
それはともかく,「Javaにポインタがない」も昔は聞きましたが (たぶん,Java初期) さすがに最近は聞かないですね。
# Java VMの世界ではNullPointerExceptionですしね。CLIではNullReferenceExceptionですが。

CにあってJavaにないのはポインタ演算ですよね。
ポインタ演算を無視すると,Cのポインタもだいぶ簡単になるのですけれど……。
今どき,規格的な話を無視すればポインタ演算はそんなに必要でもないでしょうし。

derok
記事: 51
登録日時: 12年前

RE: ポインタについて考える

投稿記事 by derok » 9年前

YuO さんが書きました: C#にはポインター型がありますよ。
unsafeオプション等が必須で,色々制約つきますが,System.Drawing.Bitmap.LockBitsで得たBitmapDataのScan0をint *に変換して画像処理,などの時に使います。
すいません、すっかり忘れてました。
YuO さんが書きました: それはともかく,「Javaにポインタがない」も昔は聞きましたが (たぶん,Java初期) さすがに最近は聞かないですね。
自分は最近聞きました。全体的にはどうなのでしょうか。
YuO さんが書きました: CにあってJavaにないのはポインタ演算ですよね。
ポインタ演算を無視すると,Cのポインタもだいぶ簡単になるのですけれど……。
今どき,規格的な話を無視すればポインタ演算はそんなに必要でもないでしょうし
ですよね。ポインタは難しいとよく聞きますが(聞きますよね?)、難しく考えすぎているような印象を受けるのですよね。

ISLe
記事: 2650
登録日時: 15年前

RE: ポインタについて考える

投稿記事 by ISLe » 9年前

derok さんが書きました:
YuO さんが書きました: それはともかく,「Javaにポインタがない」も昔は聞きましたが (たぶん,Java初期) さすがに最近は聞かないですね。
自分は最近聞きました。全体的にはどうなのでしょうか。
Javaの言語仕様の参照型の項に、
「参照とはポインタである」
とはっきり書かれているんですよね。

「Javaにポインタはない」っていうのは、アンチCなJava信者の妄想だと思います。

derok
記事: 51
登録日時: 12年前

RE: ポインタについて考える

投稿記事 by derok » 9年前

ISLe さんが書きました: Javaの言語仕様の参照型の項に、
「参照とはポインタである」
とはっきり書かれているんですよね。

「Javaにポインタはない」っていうのは、アンチCなJava信者の妄想だと思います。
ですよね。参照とポインタがやっていることは同じ以上、参照が分かればポインタもわかると思うのですよ。