トップページ⇒tech
768コメント219KB

ポインタを上手に例えてみよう

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさんNGNG
名言求ム
0232デフォルトの名無しさんNGNG
>>231
ナゼカワロタ
0233デフォルトの名無しさんNGNG
ポインタの概念ごときが分からない糞プログラマが増えたのは困りもんだな。
ポインタと言う概念が分からない阿呆は痛い。
0234デフォルトの名無しさんNGNG
ポインタがわからない人が何故分からないのか分からない。
ポインタは、メモリ上にあるデータを、メモリ上のアドレスとしてみる、ってだけだろ?
っていうか、本当にポインタがわからないプログラマっているの?
0235デフォルトの名無しさんNGNG
>>234
てか、分かったつもりでいる奴もイパーイいるよ。
0236デフォルトの名無しさんNGNG
ポインタは短縮ダイアルです。
以上
0237デフォルトの名無しさんNGNG
>>234
> ポインタは、メモリ上にあるデータを、メモリ上のアドレスとしてみる、ってだけだろ?

プ
0238デフォルトの名無しさんNGNG
>>237
「メモリ上のアドレス」で良いと思うぞ。
ただ、それ一辺倒だとそのうちvtblがどうとかエラいことになりそうだけど。
0239ライター&出版社NGNG
>>237は神です。ありがとう。
0240デフォルトの名無しさんNGNG
でも
>ポインタは、メモリ上にあるデータを、メモリ上のアドレスとしてみる、ってだけだろ?
これで分かってると思ってるなら、まずい気がする・・・。
まあこんな所で演説ぶるのも嫌だから、簡潔(?)に書いたのかもしれんけど。
0241デフォルトの名無しさんNGNG
ポインタ って、あるものをさし示すモノ ってことでいいんじゃない?
0242デフォルトの名無しさんNGNG
>>241
それは単なる和訳
0243デフォルトの名無しさんNGNG
ポインタとは、ただの整数
命令語とは、ただの整数
データとは、ただの整数
ノイマンばんざぁい
0244デフォルトの名無しさんNGNG
ポインタの参照の違いは、整数として計算ができるかどうかの違いだね。
参照は比較(それが指す実体じゃないよ)できることもあるが、比較できないこともある。
足すことができることもあるが、できないこともある。
ポインタはあらゆる四則演算、比較が可能。
ただ、それをやることに意味がなかったり判かりにくくなったりするので、通常言語機構で制限が加えてある。
アセンブラになると、それが素の状態になる。CやC++だとキャストでなんとかできる。
判りやすさと引き換えに自由度を手に入れることができるのがポインタ。
というのはどう?
0245デフォルトの名無しさんNGNG
凡庸に_"番地、住所"_
よってポインタの計算とは

日本・大阪・高槻
日本・東京・三軒茶屋
の構造を利用して
青森の住所を算出するようなもん。
0246デフォルトの名無しさんNGNG
ポインタは中間管理職
0247デフォルトの名無しさんNGNG
>>246
せつねぇ〜
0248デフォルトの名無しさんNGNG
>>245
>の構造を利用して
>青森の住所を算出するようなもん。

できるか!(笑
日本の幅は家一軒分しんかないんけ!
0249デフォルトの名無しさんNGNG
>>246
仕事の苦労が外部にわからないとこはあってる。
0250デフォルトの名無しさんNGNG
ポインタとはアドレスバス幅?
0251デフォルトの名無しさんNGNG
char *hunga[10];
とか書いてあると、もうわけわからん。
これのせいでプログラミング作法が読めない。
0252デフォルトの名無しさんNGNG
>>251
ポインタの配列
0253デフォルトの名無しさんNGNG
使うときのイメージで逆にたどっていけばいいでしょ。
(char) *(hunga[i])
(char pointer) hunga[i]
(char pointer array) hunga
0254デフォルトの名無しさんNGNG
* と [ ] の優先順位さえ解っていればいい
0255デフォルトの名無しさんNGNG
>>251 それはポインタが悪いんじゃなくて
Cのポインタ宣言の文法が腐ってるだけ。
0256デフォルトの名無しさんNGNG
>>255
別に腐ってないよ。簡潔に表現できる分にはあれで正解。
優先順位知ってれば混乱しない。
0257デフォルトの名無しさんNGNG
腐ってるとすれば、それは>>255の脳内。
0258デフォルトの名無しさんNGNG
しかし正直、関数ポインタが絡むと。。
0259デフォルトの名無しさんNGNG

syntax rotten
0260デフォルトの名無しさんNGNG
ポインタ配列(ダブルポインタ)
なんだけど、自分の場合文字列配列を
使うことが多いので、こんな感じで
ポインタを使ってデータにアクセスしてるのだけど、
この認識でいいかな? >>識者

int main(void){
 char a[10][1];
 char *pa[1];
 unsigned long int *ppa;

 pa[0] = &(a[10][0]);
 pa[1] = &(a[10][1]);
 pa[0] = "aaaa";
 pa[1] = "bbbb";
 ppa = (unsigned long int *)pa;

 printf("%s\n",(char *)*ppa);
 printf("%s\n",(char *)*(ppa + 1));
}
0261デフォルトの名無しさんNGNG
>>260
> ppa = (unsigned long int *)pa;
何したいのさ
0262デフォルトの名無しさんNGNG
>>260
std::vector使えと
0263デフォルトの名無しさんNGNG
>>261
ppa=pa
だと
paは char型へのポインタだから
一応ppaと型を合わせてキャストしただけ。
特にやらなくてもいいのかな。
となると、
pa[0] = (char *)&(a[10][0]);
pa[1] = (char *)&(a[10][1]);
としておくべきだったかな。
0264263NGNG
ゴメソ
>paは char型へのポインタだから
paは char型へのポインタのポインタだから
キャストは必要ないね。
逝ってきます。
0265デフォルトの名無しさんNGNG
識者じゃないけど
char a[10][2];
char *pa[2];
char **ppa;
こうでない?
0266263NGNG
>>265
多次元配列間違ってました。
後の指摘もそうっすね。
調べて今書こうと思ってました。
もう一回書きます。
int main(void){
 char a[1][10];
 char *pa[1];
 char **ppa;

 pa[0] = (char *)&(a[0][10]);
 pa[1] = (char *)&(a[1][10]);
 pa[0] = "aaaa";
 pa[1] = "bbbb";
 ppa = pa;

 printf("%s\n",(char *)*ppa);
 printf("%s\n",(char *)*(ppa + 1));
}
0267デフォルトの名無しさんNGNG
ふざけてるんですよね
0268sageNGNG
「ポインタとは」だけじゃいまや明確な定義は出来ないでしょう。
何におけるポインタの話をしたいのか言わない1は釣りしてるだけだよね。
0269whileNGNG
>>266
C++,C,(もしくはjava)
やり直しましょう…
入門書に書いてあると思います…

pa[0] = (char *)&(a[0][10]);
// ↓ たぶんこうしたいかと…
pa[0] = (char *)&(a[0][0]);

ppa = pa;
// ↓ たぶんこうしたいかと…
ppa = &pa;

printf("%s\n",(char *)*ppa);
printf("%s\n",(char *)*(ppa + 1));
// ↓こうしたほうが簡潔かと…
printf("%s\n", *ppa) );
printf("%s\n", *(ppa+1)) );

あと2,3箇所は
もっと突っ込んであげたほうがいいところはありますが…
そこまで善人では僕はありません。
…基礎からやり直しましょう…
0270デフォルトの名無しさんNGNG
さすが基礎の出来ている人は
漏れと違ってすごいですね。。
そういうなら
pa[0] = (char *)&(a[0][0]);
pa[1] = (char *)&(a[1][0]);
こっちの方が正しいのでは。

しかし、
pa[0] = (char *)&(a[0][10]);
pa[1] = (char *)&(a[1][10]);
でも269の
pa[0] = (char *)&(a[0][0]);
pa[1] = (char *)&(a[1][10]);
でも
きちんと
aaaa
bbbb

と表示できた。
基礎の出来ているなら何故
だか分かるのですよね?

あと、いくら何でもppa = &pa
ないでしょう。
コンパイラにも怒られましたよ。
0271デフォルトの名無しさんNGNG
 pa[0] = &(a[10][0]);
 pa[1] = &(a[10][1]);
 pa[0] = "aaaa";
 pa[1] = "bbbb";
上書きしてどうするの?っていうかネタでしょ。
0272デフォルトの名無しさんNGNG
ひょっとして、こう↓したかった?

int main(void){
char a[2][10] = {"aaaa","bbbb"};
char *pa[2] = {a[0], a[1]};
char **ppa = pa;
printf("%s\n",ppa[0]);
printf("%s\n",ppa[1]);
}
0273デフォルトの名無しさんNGNG
けっこう多次元配列とかわかってない人いるんだね
0274デフォルトの名無しさんNGNG
上書きってか、
pa[0] = (char *)&(a[0][0]);
pa[1] = (char *)&(a[1][0]);
でポインタとデータ部をリンクさせ、
pa[0] = "aaaa";
pa[1] = "bbbb";
そこに文字列代入しているんじゃないの?
0275デフォルトの名無しさんNGNG
>>273
多次元配列なんて使ったことないから問題ない
0276デフォルトの名無しさんNGNG
>>274
いつからアドレス操作が strcpy の代わりになるようになったのか小一時間
0277デフォルトの名無しさんNGNG
そうか、なるほど。
pa[0] = a[0];
pa[1] = a[1];
strcpy (pa[0],"aaaa");
strcpy (pa[1],"bbbb");
ってやりたかったんだな。

>>274
プ
0278whileNGNG
>>270
ppa = &pa
// ↓こうだった…これはミスでした…
ppa = &pa[0];

pa[0] = (char *)&(a[0][0]);
// ↓これは省略したんです(同じロジック何回も書くの嫌でしょう?)
pa[0] = &(a[0][0]);
pa[1] = &(a[0][1]);

0279whileNGNG
んじゃまあ、他のミスの件を…
1:データ領域の指定おかしい(確保していない領域も計算対象としている)
char a[1][10];
↑10個の配列を1個作成>10個の配列を2個の作成が正しいよって下記が正しい↓
char a[2][10];

char *pa[1];
↑1個の配列を作成>2個の配列を作成が正しいよって下記が正しい↓
char pa[2];

データ領域を指定した以上に使っているので…
このような小規模のプログラムでは問題ないでしょうが
ソフトウェアを作ろうと思えば、動作に不具合を発生させます。

2:なぜ表示されたのか?
pa[0] = "aaaa";
pa[1] = "bbbb";
↑ここで非明示のデータ領域に
指定されたデータを格納し
そのポインターのみを取得して
そのポインターを参照してデータを出力しているからです。

ですので、ためしに↓を実行してごらんなさい。
printf("%c\n",a[0][0]);printf("%c\n",a[0][1]);
printf("%c\n",a[1][0]);printf("%c\n",a[1][1]);
0280デフォルトの名無しさんNGNG
ちなみに、
pa[0] = a[0];
pa[1] = a[1];
と、
pa[0] = &a[0][0];
pa[1] = &a[1][0];
は同じ。
0281デフォルトの名無しさんNGNG
↓これなら、少しはおもしろい。
#include <string.h>
main () {
char a[2][10];
//char *pa[2] = {a[0], a[1]};
char *pa[2] = {&a[0][0], &a[1][0]};
char **ppa = pa;
strcpy (ppa[0], "aaaa");
strcpy (ppa[1], "bbbb");
printf ("%s\n", a[0]);
printf ("%s\n", a[1]);
}
0282whileNGNG
>>278
誤植したので修正します

pa[0] = (char *)&(a[0][0]);
// ↓これは省略したんです(同じロジック何回も書くの嫌でしょう?)
pa[0] = &(a[0][0]);
pa[1] = &(a[1][0]);
0283デフォルトの名無しさんNGNG
whileって人もかなり あ や し い
0284whileNGNG
>>280
それはその書き方が僕の好みだから…。
0285デフォルトの名無しさんNGNG
別の例:
#include <string.h>
main () {
char a[2][10];
char (*p)[][10] = &a; // 多次元配列へのポインタ
strcpy ((*p)[0], "aaaa");
strcpy ((*p)[1], "bbbb");
printf ("%s\n", a[0]);
printf ("%s\n", a[1]);
}
0286デフォルトの名無しさんNGNG
ポインタが難しいんじゃなくてC言語とかのポインタの文法と仕様がダメなんでしょ。
0287デフォルトの名無しさんNGNG
>>286
それは言えてるようで、言えてないようで。。。
教えられ方が下手なんだと思う。
0288281NGNG
そうか、この変数名がおかしいのか。
char **ppa = pa;
↓
char **pp = pa; // pa = char pointer array, pp = char pointer pointer
0289デフォルトの名無しさんNGNG
>>276-277
char *a;
a="aaa"
ができるのに
char *pa[1]
pa[0] = "aaa"
ができないということに
なるけど何故?
と思ったら、最初に宣言した配列
とは別のアドレス参照してしまう
ということですね。
上書きとはアドレスの上書き
だったのですね。
0290デフォルトの名無しさんNGNG
ネタにマジレスしてるよ…
2ちゃんねらーじゃないね〜whileってひと。
っていうかネタってわかれよ(藁
0291デフォルトの名無しさんNGNG
>>289
たぶんあってる。Cで文字列を扱うときは考え方を改めなければイケナイ
0292デフォルトの名無しさんNGNG
>>289
はぁ?
0293デフォルトの名無しさんNGNG
結論:whileっていう人+αが 釣 れ た
0294whileNGNG
>>289
そうです。

>>290
…悪かったです…反省してます…
0295デフォルトの名無しさんNGNG
↓この冒頭の一発を見逃した香具師は要注意

260 :デフォルトの名無しさん :02/09/11 15:31
ポインタ配列(ダブルポインタ)
なんだけど、…
0296whileNGNG
正確には
char *a;a="aaa";も
char *pa[1]; pa[0] = "aaa";も
できます。

↓これは正しい。
>上書きとはアドレスの上書き
>だったのですね。
0297デフォルトの名無しさんNGNG
こんなのも作ってみた。
#include <stdio.h>
#include <string.h>

int main(void){
 int i;
 char *a[1];
 char **pa;
 for(i = 0; i <= 1; i++)
  a[i] = (char *)malloc( 10 * sizeof(char) );
 strcpy(a[0],"aaaa");
 strcpy(a[1],"bbbb");

 pa = &a[0];
 printf("%s\n",*pa);
 printf("%s\n",*(pa + 1));
// for(i = 0; i <= 1; i++)
//  free(a[i]);
}
最後、freeしといた方がいいと思ったけど
コメントを外すと
aaaa
bbbb
の後セグメンテーションエラーが出る。
0298デフォルトの名無しさんNGNG
ポインタはギターでいうFコードみたいなやつ。
弾ける人には訳ないが、弾けない人には悩みの種。
0299デフォルトの名無しさんNGNG
sizeof(char)は無意味です
0300デフォルトの名無しさんNGNG
ちうか
>char *a[1];
> for(i = 0; i <= 1; i++)
>  a[i] = (char *)malloc( 10 * sizeof(char) );
> strcpy(a[0],"aaaa");
> strcpy(a[1],"bbbb");
逝って良し
0301whileNGNG
>297
こうでしょう…
#include <stdio.h>
#include <string.h>

void main( void ){
 int i;
 char *a[2];
 char **pa;
 for( i = 0; i < 2; i++ )
  a[i] = (char *)malloc( 10 * sizeof(char) );
 strcpy(a[0],"aaaa");
 strcpy(a[1],"bbbb");
 pa = &a[0];
 printf("%s\n",*pa);
 printf("%s\n",*(pa + 1));
 for( i = 0; i < 2; i++ )
  free(a[i]);
}
0302デフォルトの名無しさんNGNG
こんな間違いするのはVB厨だけ。
VB厨逝って良し。
0303デフォルトの名無しさんNGNG
そうね、charはどの環境でも
1バイトだね。

0304whileNGNG
>>301
malloc…つかわないなぁ…new使います。
0305デフォルトの名無しさんNGNG
>>304 唐突にC++か、おめでてーな
0306デフォルトの名無しさんNGNG
わけわからん。
ポインタって、「メモリ上のアドレスを参照する」という以外の解釈のされ方があるのか?
ポインタ変数の値は確かに演算可能だけど、この場合、その値は「ポインタ」としてはコンピュータが判断してないわけだろ?
演算するんだから、ポインタ変数に入っている値はポインタではない、っていえるんじゃない?
そもそも、コンピュータで扱うデータは、全て解釈の違いがあるだけだろ?
その解釈を分けて「整数」とか「浮動少数」とか言ってるんだから、
そういう解釈をすることを前提にして「ポインタ」も名づけてるんじゃないの?

0307デフォルトの名無しさんNGNG
VB全く知らないんだけど
VBだと a[1] で要素2個の配列ということになるの?
0308デフォルトの名無しさんNGNG
>>307
なるよ。
0309whileNGNG
>>306
>ポインタ変数の値は確かに演算可能だけど、
>この場合、その値は「ポインタ」としてはコンピュータが判断してないわけだろ?
そんなことはないですよ。
コンピュータは演算されていてもポインタとして扱います。

>>307
そうかもしれませんね…。
3年はBASIC読んでないので憶えていませんが。
0310デフォルトの名無しさんNGNG
あっそうか。
宣言は要素数なのか。
0311デフォルトの名無しさんNGNG
ttp://www.rakuten.co.jp/starkids/454773/484020/
0312デフォルトの名無しさんNGNG
>>309
そういう意味じゃあなくて、ポインタかどうかは、コンピュータがそれをどう扱ったか(判断したか)ではないのか?ということ。

そもそも、人間の思考能力や記憶力には限界があるから、変数に型があって、コンピュータに判断をまかせてるんじゃないの?
メモリ上では、そこに入っている値が何であるかなんて判断されないわけだし、そこにあるデータが「プログラム」なのか「データ」なのかも区別がないんだから。

つまり、コンピュータがそれを「どう判断したか」によって、ポインタなり整数なりが、定義されると考えたほうがいいんじゃないか?ッてことをいいたかった。

っていうか、俺が間違ってました、ごめんなさい。
0313デフォルトの名無しさんNGNG
>>309
必ずしもそうは言い切れないのでは。
int aaa (int p)
{
return p + 1;
}
char * aaa (char *p)
{
return p + 1;
}
.globl _aaa
.def_aaa;.scl2;.type32;.endef
_aaa:
movl 4(%esp),%eax
incl %eax
ret
どっちも同じコードになってるけど。
0314デフォルトの名無しさんNGNG
char *a;a + 1;
ではアドレスは1バイト進むし
intが4バイトなら
int *a;a + 1;
は*aは4バイト進む。

ポインタの実体はアドレス値だけど
型情報をもったアドレス値
という認識でいいのでは。
0315デフォルトの名無しさんNGNG
結論=whileは 知 っ た か ぶ り
0316デフォルトの名無しさんNGNG
間違い->
char *a;だと
*(a+1)は*aの1バイト先の値を参照するし
intが4バイトなら
int *a;a + 1;
*(a+1)は*aの4バイト先の値を参照する。
0317デフォルトの名無しさんNGNG
>>314
それ自体は型情報をもっていなくて、コンパイルした時点で+1が+4に置き換わっているとか、
コンピュータがそう判断して+1を+4と置き換えながら実行しているのでは?
っていうか、やっぱり、「コンピュータがそれをどう判断するか」だと思うンだけど、意見くれよ(;´Д`)
0318whileNGNG
>>314
それは↓かと
char *a;a++;
int *a;a++;
0319デフォルトの名無しさんNGNG
>>317
ネタ?
自分でコンパイルして確かめてみなよ。
0320whileNGNG
>>317
データであるかぎり
型情報はもっているとおもいますよ。

例え:void*のポインターであっても、
ポインターであるという点において
0321whileNGNG
>>313
たとえば、
ポインターを計算に用いて、
新しいポインターを生成したとします。
(その時点で演算している)

そのポインターはポインターといて扱われます。
0322デフォルトの名無しさんNGNG
>>317
char *とか
int *
といった時点で型情報を持った
アドレス値として扱うのでは。
ただ単にアドレスなら、
char a;unsigned long ad;ad=&a;
でいいのでは?
0323デフォルトの名無しさんNGNG
メモリは数バイト単位で区切られてて、同時に情報をもっているとはいえないのでは?
型情報は別の場所にあるんじゃないの?
0324デフォルトの名無しさんNGNG
>>318
説明するには
どっちでもいいじゃん。
0325デフォルトの名無しさんNGNG
>>322
それを型情報をもったアドレス値として扱うのは「誰」?
0326デフォルトの名無しさんNGNG
コンパイル時の型情報と、実行時の型情報だけは区別してほしいこのごろ
0327デフォルトの名無しさんNGNG
>>323
型情報は記憶装置にではなく、宣言やキャストで
この型として扱えと命令しているのではないのかな。
0328デフォルトの名無しさんNGNG
>>323
> 型情報は別の場所にあるんじゃないの?

ネタだよな ?
0329whileNGNG
アセンブルとC 1/2

int aaa (int p){return p + 1;}
push ebp
mov ebp,esp
mov eax,dword ptr [p]
add eax,1
pop ebp
ret

char * aaa (char *p){return p + 1;}
push ebp
mov ebp,esp
mov eax,dword ptr [p]
add eax,1
pop ebp
ret
0330デフォルトの名無しさんNGNG
>>328
おまえが、だろ?
0331デフォルトの名無しさんNGNG
cでは、ポインタの型情報はコードに落とすときコンパイラが
必要とするだけで実行時は型情報なんて存在しないんじゃないの。
■ このスレッドは過去ログ倉庫に格納されています