トップページ⇒tech
65コメント35KB

配列とポインタについて熱く論じてくれ。

■ このスレッドは過去ログ倉庫に格納されています
0001reroreroNGNG

int a[3]のとき、

配列名aは、式の中ではポインタと「みなされる。」


int a[3];

a[0]=10;
a[1]=20;
a[2]=30;
printf("%d\n",*a); 10が表示される
printf("%d\n",*(a+1)); 20が表示される
printf("%d\n",*(a+2)); 30が表示される


*aってのは、ポインタaが指している先の変数を
表す。

ってことから、aはポインタと解釈されていることがわかる。

ただ、aは「ポインタと解釈されている」のであって、
ポインタではない。

というのも、

配列の先頭要素のアドレスは
固定された値、すなわち「定数」であり、
定数にアドレスを代入することはできない。
それに対し、ポインタは「変数」である。



どうでしょね?




0002デフォルトの名無しさんNGNG
単発質問スレですか。
0003わかりませんNGNG

















































0004デフォルトの名無しさんNGNG
                                     ▄▄▄██████▄
     ███▀     █████████      ▄▄▄▄█████▀▀  ████▀▀
    ███▀ ██  ███▀ ▄███▀        ▀▀▀▀      ███▀
   ██▀ ▄███▀███▄▄▄███                ▄▄▄█▀
 ▄███▄▄██▀ █▀  ▀████                  ▀██▄
 ▀▀▀▀███▄      ▄██▀█▄▄                 ███
    ██▀ ███   ██▀  ▀███▄▄              ███
  ▄████▀▀██ ▄█▀▄▄   ▀█████▄▄           ███
  ▀█▀▀  █▄▄█▀   ████▄  ▀███▀▀▀         ███
▄   ███ ▀███      ▀▀▀                  ███
███  ███  ▀▀                           ███
 ███  ▀        ▀████▄             ▄▄▄▄████
  ▀              ▀████             ▀█████
                                     ▀██▀
0005デフォルトの名無しさんNGNG
                                     ▄▄▄██████▄
     ███▀     █████████      ▄▄▄▄█████▀▀  ████▀▀
    ███▀ ██  ███▀ ▄███▀        ▀▀▀▀      ███▀
   ██▀ ▄███▀███▄▄▄███                ▄▄▄█▀
 ▄███▄▄██▀ █▀  ▀████                  ▀██▄
 ▀▀▀▀███▄      ▄██▀█▄▄                 ███
    ██▀ ███   ██▀  ▀███▄▄              ███
  ▄████▀▀██ ▄█▀▄▄   ▀█████▄▄           ███
  ▀█▀▀  █▄▄█▀   ████▄  ▀███▀▀▀         ███
▄   ███ ▀███      ▀▀▀                  ███
███  ███  ▀▀                           ███
 ███  ▀        ▀████▄             ▄▄▄▄████
  ▀              ▀████             ▀█████
                                     ▀██▀
0006デフォルトの名無しさんNGNG
                                     ▄▄▄██████▄
     ███▀     █████████      ▄▄▄▄█████▀▀  ████▀▀
    ███▀ ██  ███▀ ▄███▀        ▀▀▀▀      ███▀
   ██▀ ▄███▀███▄▄▄███                ▄▄▄█▀
 ▄███▄▄██▀ █▀  ▀████                  ▀██▄
 ▀▀▀▀███▄      ▄██▀█▄▄                 ███
    ██▀ ███   ██▀  ▀███▄▄              ███
  ▄████▀▀██ ▄█▀▄▄   ▀█████▄▄           ███
  ▀█▀▀  █▄▄█▀   ████▄  ▀███▀▀▀         ███
▄   ███ ▀███      ▀▀▀                  ███
███  ███  ▀▀                           ███
 ███  ▀        ▀████▄             ▄▄▄▄████
  ▀              ▀████             ▀█████
                                     ▀██▀

0007デフォルトの名無しさんNGNG

                                     ▄▄▄██████▄
     ███▀     █████████      ▄▄▄▄█████▀▀  ████▀▀
    ███▀ ██  ███▀ ▄███▀        ▀▀▀▀      ███▀
   ██▀ ▄███▀███▄▄▄███                ▄▄▄█▀
 ▄███▄▄██▀ █▀  ▀████                  ▀██▄
 ▀▀▀▀███▄      ▄██▀█▄▄                 ███
    ██▀ ███   ██▀  ▀███▄▄              ███
  ▄████▀▀██ ▄█▀▄▄   ▀█████▄▄           ███
  ▀█▀▀  █▄▄█▀   ████▄  ▀███▀▀▀         ███
▄   ███ ▀███      ▀▀▀                  ███
███  ███  ▀▀                           ███
 ███  ▀        ▀████▄             ▄▄▄▄████
  ▀              ▀████             ▀█████
                                     ▀██▀


0008デフォルトの名無しさんNGNG
>>3-4
なんか大迫力
0009デフォルトの名無しさんNGNG
>配列の先頭要素のアドレスは
>固定された値、すなわち「定数」であり、
これ、間違ってんじゃない?
0010デフォルトの名無しさんNGNG
良スレの予感だったのに
0011デフォルトの名無しさんNGNG
>>10
>>1 ですか?
0012デフォルトの名無しさんNGNG
小まとめ
ポインタ=C言語でアドレスを操作しやすいように作った「変数」
ポインタが表すのは実際のアドレスでない(バイト数等を意識しなくてよい)
ポインタ*aのアドレスaは、その変数が占めるバイト数に係わらず、必ず占有するメモリの先頭を指す
int a[20]; とした場合 20個のint型のメモリのかたまりと、1つのアドレスを入れるメモリの位置が確保される
a[0]は、*aで参照出来る
C言語ではポインタと配列変数は全く同じものとして扱われるため、
int *a;int a[20];
という宣言はエラーとなる。
またC言語には、”配列で宣言したもは、特別な必要が無い限り配列として扱う”という原則がある。
配列セグメントの先頭アドレスになるようなポインタに違う値を代入したら指してる配列があるメモリのかたまりと違う所に行って
オフセットもクソもなくなるし要素のバイト数とかもあるからポインタ変数にムチャクチャなアドレス入れて使うのと同じくらいやらない事なのでは?
0013デフォルトの名無しさんNGNG
前橋のポインタ完全制覇でも読め。
0014デフォルトの名無しさんNGNG
煽りを装った前橋信者の宣伝活動か?
0015デフォルトの名無しさんNGNG
>14
それを読んだから講釈垂れたかったんだろ1は。
0016reroreroNGNG
ちがうんよ(藁
その本を読んだらおかしくなってきたんよ。
講釈をたれたいんでなく、この本のせいで
またドキュソになっちまった自分と舞えはしに
むかついてんだよ。
舞え端は、はっきりいって異端者だ。

ところで、


>int *a;int a[20];
>という宣言はエラーとなる

ってのはわかる。

だが、

aは、先頭要素のアドレス&a[0]をもっている。
つまり、a[0]を指してるんだよな。

やっぱポインタとして解釈されてる
とおもっていいのでは?

そうでないなら、なんでエラーにはならんのだ?


0017reroreroNGNG
舞えはしがいうには
a[0]は、*(a+0)の簡便記法らしい。
まあ、それはよいとして、

「aはa[0]を指している」

ってのは許されんのか?

この考え方でつきすすんでいって障害は別に
なかった。

0018デフォルトの名無しさんNGNG
配列の先頭はポインタ変数と同じだが配列は配列として使えっていってんだよC言語は
0019前橋信者NGNG
我が尊師を「舞えはし」などと冒涜する奴はオレが許さん
0020デフォルトの名無しさんNGNG
まつもと(Ruby!) >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 前橋


http://member.nifty.ne.jp/maebashi/seiha/hosoku001.html
0021デフォルトの名無しさんNGNG
>>12
>int a[20]; とした場合 20個のint型のメモリのかたまりと、1つのアドレスを入れるメモリの位置が確保される

これは配列と配列を指す事実上のポインタがあるってことだと思うが
規格は知らんものの実際にそんな実装になっちゃいないと思う。
それと、ポインタと配列の違いとして sizeof の適用結果の違いも忘れるべからず。
0022reroreroNGNG
>配列は配列として使えっていってんだよC言語

は承知

何度もわるいな。

舞えはしがいうには、

配列をあたかもポインタのようにしてつかうことができる。

int d[]={
1111,2222,3333
};

このとき、
配列の第1要素の値 *d
配列の第2要素の値 *(d+1)
配列の第3要素の値 *(d+2)

とはかいているものの、

配列名dは、先頭要素をさすポインタ
である。

とはかいていないのだ。

これにむかついてんだよ、おれは。
さんざん、K&Rを批判しておきながら、
曖昧にしてる点がおおいんだよ。
あっちこちはなしとんでるしよ。


0023デフォルトの名無しさんNGNG
>>22
>配列名dは、先頭要素をさすポインタである。

これは、式中において配列変数はポインタとして評価される、とだけ言うべきだろう。
あくまでもポインタと見なすだけであって配列とポインタは別々のもの。
これは >>1 で自分が書いたとおりの話。
それを前橋式には「配列(変数)を(式中においては)あたかもポインタのようにしてつかうことができる」と書いてるだけじゃないの?
目くじら立てるようなもんじゃないと思うがなぁ。
0024デフォルトの名無しさんNGNG
>>21
>規格は知らんものの実際にそんな実装になっちゃいないと思う。
できれば理由書いて欲しかったんですが
0025デフォルトの名無しさんNGNG
>>1 配列とポインタが同じに見えてきたらpascalとか一度触った方がいい
0026reroreroNGNG
#include <stdio.h>

void sub(int **,int);

int main(void)
{
int *p[3];

int a=10;
int b=11;
int c=12;

p[0]=&a;
p[1]=&b;
p[2]=&c;

sub(p,3);

return 0;
}

void sub(int **x,int n)
{
int i;
for(i=0;i<n;i++){
printf("%d\n",*x[i]);
}
}


int *a[]と int **a

は同じだってやつだけど、


pはp[0]をさすポインタとみなされる。
p[0]はint型をさすポインタである。
つまり、
pは、"int型をさすポインタ"へのポインタである。

ゆえに、受け取り側の仮引数は

int **a

とすればよい。

このような考え方はいいのだろうか。


0027デフォルトの名無しさんNGNG
>22
つまりdはintの配列(データ領域)を指すポインタ値を保持するものであって、
d自体だけで言えば、int const *dとして考えても差し支えないのではないか、ってことか?

文章の解釈間違ってたらスマソ。
0028デフォルトの名無しさんNGNG
3214というリテラルがあったとき3214は式の中では「int」とみなされる。
3214 + 22;
3214 + 41324;
などのなかでは3214はintであるかのようにふるまう。しかし3214はintではない。これは
3214 = 1;
がエラーになることからもわかるだろう。
つまり int a[3]のときの配列名aは「ポインタ値」だが「ポインタ変数」ではない。

どうでしょうね?
0029reroreroNGNG

>23

親切にありがとな。


>配列名dは、先頭要素をさすポインタ
>である

悪い。まちがえた。

式の中で、配列名dは先頭要素を指すポインタと解釈される。

ドキュソなおれも、

配列とポインタは全く違うものってのはわかる。

>1で自分で説明してるくらいだから大丈夫だ(藁

ただ、

「式の中で、配列名dは先頭要素を指すポインタと解釈される。」

っていう考えはゆるされるんだよな。

前橋がいうには

>[ ]ってのは単なる演算子だ。

うむ。配列要素にアクセス(参照)する際に用いるんだな。

でも、* は演算子とはいってないだろ?

これはあくまで、ポインタが指す先の変数を表す。
ってことは、*aのaはまぎれもなくポインタではないのか?

なんかおれみおとしたか?

*も演算子か?

んなわけないよな。
0030reroreroNGNG
>22

おれがドキュソはみとめる。

わるいね。

おれがたしかめたいのは、

配列名は、先頭要素を「指している」
のか?

ということなんだ。

0031デフォルトの名無しさんNGNG
>>30
……>>1 でほぼ正解じゃん ……
0032デフォルトの名無しさんNGNG
あちゃー
0033デフォルトの名無しさんNGNG
宿題は自分でヤレ。
0034デフォルトの名無しさんNGNG
とりあえず動けばよし!
理屈はあとからついてくる。
0035デフォルトの名無しさんNGNG
配列は配列、ポインタはポインタ
ただ、式中では等価と見なされる場合が多いだけ。
両者は本質的に異なる。
0036デフォルトの名無しさんNGNG
double *a;としたとき
aはdouble型を指す為のポインタ型変数である(double型変数が持つ複数バイト中の先頭バイトのアドレス)
宣言時、「*」は「ポインタ変数型」という意味である。型によって違うバイト数を認識する為 *a; ではなく 型 *a; と表す必要がある。
代入時は a=&b; としたとき *a の参照と b の参照は同じになる( *(&b) )
「*」は右の値(ポインタ)が表す変数への参照演算子のようなもの
arr(*a+1)としたとき、ポインタが指すアドレスは+1されるわけではなく、バイト数に応じた数が加えられる
0037デフォルトの名無しさんNGNG
「単項演算子*は間接演算を意味する。」
「《Tの配列》型の式はその配列の最初の要素へのポインタに(暗黙のうちに)変換できる。」
だから、配列名自体はポインタではない。
0038デフォルトの名無しさんNGNG
35さんのいうとおりだよ。
コンパイラさんは、式の中で配列がポインタだと思って
解釈しようとするだけでしょ。
概念が異なっていても、内部的に同じような状態になることは多いと思う。
003936NGNG
一個間違えた 見てわかると思うから直して解釈してくらさい
0040reroreroNGNG
36 >
>「*」は右の値(ポインタ)が表す変数への参照演算子のようなもの

演算子はいいとして、
やっぱ、"右の値(ポインタ)"・・・ポインタだろ?
な?

配列名はポインタしてるんだよ。やっぱ。

「指している」

んだよな。

何度もいうが、俺は、

「配列名 = ポインタ」

とはおもってない。それは1でのべた。

そしてなんどもいうが、

配列名は、先頭要素を「指している」
のか?

Yes か No で

こたえてくれ。

そしてその理由とな。


>37

親切にありがとな。
でも、それは、前橋の本で理解できてるんだ。

ただ、あの本には、小さな穴がある。


それが

配列名は、先頭要素を「指している」
のか?

なんだ。

*をつかえば、各配列要素にアクセスできることはわかる。

*aをオフセット(基準にして)、型サイズ*nでインクリメント
できる

ってのもわかる。






0041デフォルトの名無しさんNGNG
行間あけすぎだ
0042reroreroNGNG
>37

悪い。みおとしてた。

>「《Tの配列》型の式はその配列の最初の要素へのポインタに(暗黙のうちに)変換できる

そうだよな?!

これを確認したかったんだ。

おれは

配列名は、式の中でポインタと「みなされる」

と何度も書いてる。これは理解できるんだ。

確認したかったのは、じゃ、配列名はどこを指してるんだ?
といったら、先頭要素だろ?

ありがとう。



でも、これは憶測だろうか?
確証がとれたものなのだろうか?

K&Rが、こういうことをしっかりと論じてくれないから
ドキュソがさらにドキュソになるんだよな。

0043デフォルトの名無しさんNGNG
あれだ。
ドラゴンボールを7つ集めると
配列からポインタが出てくんだよ。
0044UNKOMANNGNG
printf("%d\n",*(0[a])); 10が表示される
printf("%d\n",*(1[a])); 20が表示される
printf("%d\n",*(2[a])); 30が表示される

a[x] は *(a+x) として解釈されるため。
0045デフォルトの名無しさんNGNG
1の最初の2−3行しかこのスレ読んでないけど

int *a;
int **b;
int *c[10];
int (*d)[10];
int (*e)(int f);
これぐらいが分かればいいんじゃない?ポインタは。
0046デフォルトの名無しさんNGNG
> 配列名は、先頭要素を「指している」
> のか?
> Yes か No で
> こたえてくれ。
No
配列は「存在している」だけ
0047デフォルトの名無しさんNGNG
>確認したかったのは、じゃ、配列名はどこを指してるんだ?
>といったら、先頭要素だろ?

配列名が指すものは「配列」だよ。sizeofを考えてみたら?
0048デフォルトの名無しさんNGNG
1>>の為に表を作る(失敗したらゴメソ
  アドレス ポインタ 配列(3byte)  参照
          __________
  0x1001 = a ←|__   __|
  0x1002    |_ a[0] __| > *a
  0x1003    |_________|
参照  a[0] は *a と等価
配列名 a は a[0] を指すポインタと等価にみなされるってことか
0049デフォルトの名無しさんNGNG
>>44
printf("%d\n",0[a]); 10が表示される
printf("%d\n",1[a]); 20が表示される
printf("%d\n",2[a]); 30が表示される
な。
0050デフォルトの名無しさんNGNG
俺のティンポは君を指し示すゼ!
0051reroreroNGNG
>47
じゃ、

これためしてみな。

#include <stdio.h>


int main(void)
{
int p[3]={1,2,3};

printf("%p\n",p);
printf("%p\n",&p[0]);

return 0;
}

0xbffffab0
0xbffffab0


おなじアドレスだ。

つまり、配列名は先頭要素のアドレスもってるんだ。
ってことは、配列名は、”あたかもポインタのように”
先頭要素を指してるんだ。

>47

配列名が指すものは「配列」だよ

それは

(*a)[3]ってなやつだろ?

このとき、aは、

要素数3の配列をさすポインタだ。

このばあい、aは確かに配列全体をさすよ。





0052reroreroNGNG
1>>の為に表を作る(失敗したらゴメソ
  アドレス ポインタ 配列(3byte)  参照
          __________
  0x1001 = a ←|__   __|
  0x1002    |_ a[0] __| > *a
  0x1003    |_________|
参照  a[0] は *a と等価
配列名 a は a[0] を指すポインタと等価にみなされるってことか

うむ。

メモリ
|
a +----------
a----->| a[0] | *a
a+1 +----------
| a[1] | *(a+1)
a+2 +----------
| a[2] | *(a+2)
----------

だろ?


aが配列全体をさすっていうやつは、

*aで表示されるのはなんなのかこたえてくれ?
0053デフォルトの名無しさんNGNG
「式中の配列名はポインタである」
0054デフォルトの名無しさんNGNG
>>50
漏れ?ワセリン塗って待ってる。


0055reroreroNGNG
|
a +----------
a----->| a[0] | *a
a+1 +----------
| a[1] | *(a+1)
a+2 +----------
| a[2] | *(a+2)

みずらい(藁

005648NGNG
>>55 半角スペースは連続してると1つにされる(らしい)よ
0057reroreroNGNG
どうするんだ?(藁
TABもだめか?
|
a +----------
a----->| a[0] | *a
a+1 +----------
| a[1] | *(a+1)
a+2 +----------
| a[2] | *(a+2)
----------


0058reroreroNGNG
だめだ(藁

アスキーアートつぶしか?(藁
005948NGNG
全角スペースがイイよ
0060デフォルトの名無しさんNGNG
>>1
What you see is not always what you get.
0061デフォルトの名無しさんNGNG
>>51
お前、頭悪いな。用語は、ちゃんと使え。

> おなじアドレスだ。
> つまり、配列名は先頭要素のアドレスもってるんだ。
> ってことは、配列名は、”あたかもポインタのように”
> 先頭要素を指してるんだ。

と、「配列名」とか言っておきながら...

> 配列名が指すものは「配列」だよ
> それは、
> (*a)[3]ってなやつだろ?
> このとき、aは、
> 要素数3の配列をさすポインタだ。

とか言ってるけど、この「a」ってなんだよ。誰が、配列を指すポインタなんか議
論してんだ ?

ちなみに、>>47 の言う「sizeofを考えてみたら?」って言うのは、理解してん
のか ?
0062WYSIWYG!!NGNG
#include <stdio.h>
int main(void)
{
int p[3]={1,2,3};

printf("%p\n",p);
printf("%p\n",&p[0]);
printf("%p\n",&*(&p[0]));
printf("%p\n",&(&p[0])[0]);
return 0;
}

全て同じっと。
0063デフォルトの名無しさんNGNG
>>52
>aが配列全体をさすっていうやつは、
>*aで表示されるのはなんなのかこたえてくれ?
*aの値としてはa[0]だろ。単項演算子*はオペランドにポインタを必要とするから、
配列名からポインタに暗黙に変換されるんだよ。
明示的に書くと *(&a[0]) ってなる。
0064デフォルトの名無しさんNGNG
間接参照演算子は便利だぞ。
右辺値でも型情報があれば参照できる。
*(char*)0x000000
とかな。
0065デフォルトの名無しさんNGNG
結局本家に逝っちゃったのね。
■ このスレッドは過去ログ倉庫に格納されています