掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.26200

ポインタと[]について
投稿者---あきき(2006/02/20 00:55:06)


仮に下のようなプログラムがあるとします。(ポインタ完全制覇より)

#include <stdio.h>

int main(void)
{
    int i, array[5], *p;

    for(i=0;i<5;i++)
    {
        array[i]=i;
    }

    p = array;

    for(i=0;i<5;i++)
    {
        printf("[%d]\n", *(p+i));// *(p+i)に注目
    }

    return 0;
}

そして、*(p+i)を、*p[i]に変更しても結果は同じです。
pについては変更がされていないので、p[i]は&array[i]のアドレスを
更新して、表示しているような気がします。実際の所はどうなんでしょうか?


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:ポインタと[]について 26201 ぽへぇ 2006/02/20 01:05:01
<子記事> Re:ポインタと[]について 26292 まい 2006/02/28 05:48:43


No.26201

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/20 01:05:01)



>そして、*(p+i)を、*p[i]に変更しても結果は同じです。
違います。コンパイルエラーになりませんでしたか?



この投稿にコメントする

削除パスワード

No.26206

Re:ポインタと[]について
投稿者---あきき(2006/02/20 07:42:03)


>
>>そして、*(p+i)を、*p[i]に変更しても結果は同じです。
>違います。コンパイルエラーになりませんでしたか?

p[i]のタイプミスでした。
ですが、pはarrayの先頭アドレスを指し、p[i]はポインタの
配列の様に思えるのですが、実際は、&p[i]がアドレスです。
そこの所が整理できないのです。



この投稿にコメントする

削除パスワード

No.26207

Re:ポインタと[]について
投稿者---iijima(2006/02/20 10:49:34)


>そこの所が整理できないのです。

p[i]が*(p+i)と同じものであるというのは、文法上の決まり事です。
整理するとかいう問題でなく、そのようなものだと覚えるしかありません。




この投稿にコメントする

削除パスワード

No.26208

Re:ポインタと[]について
投稿者---RiSK(2006/02/20 11:11:04)


>pはarrayの先頭アドレスを指し、

正確ではありません。
p=array;
で,pへ(暗黙の型変換により)arrayの先頭要素(array[0])を指すポインタが代入されます。

>p[i]はポインタの
>配列の様に思えるのですが、実際は、&p[i]がアドレスです。

なぜp[i]がポインタの配列に思えるのでしょうか?
もっと突っ込めば,p[i]は「何型への」ポインタの配列だと思ったのでしょうか?

>そこの所が整理できないのです。

順番に確認してください。

arrayがint[5]型であることを理解していますか?
arrayが先頭要素へのポインタへ成り下がる事があることを理解していますか?(先に説明しました。)
pがint*型であることを理解していますか?
*pがint型であることを理解していますか?
*(p+1)がint型であることを理解していますか?
*(p+i)がint型であることを理解していますか?
p[i]が(ポインタではなく)int型であることを理解していますか?


この投稿にコメントする

削除パスワード

No.26210

Re:ポインタと[]について
投稿者---あきき(2006/02/20 11:28:52)


>>pはarrayの先頭アドレスを指し、
>
>正確ではありません。
>p=array;
>で,pへ(暗黙の型変換により)arrayの先頭要素(array[0])を指すポインタが代入されます。

ポインタにより配列はarray[0]に読み替えられると理解してますが。

>なぜp[i]がポインタの配列に思えるのでしょうか?
>もっと突っ込めば,p[i]は「何型への」ポインタの配列だと思ったのでしょうか?
>
>>そこの所が整理できないのです。
>
>順番に確認してください。
>
>arrayがint[5]型であることを理解していますか?
はい。

>arrayが先頭要素へのポインタへ成り下がる事があることを理解していますか?(先に説明しました。)

>pがint*型であることを理解していますか?
はい。

>*pがint型であることを理解していますか?
はい。

>*(p+1)がint型であることを理解していますか?
はい。

>*(p+i)がint型であることを理解していますか?
はい。

>p[i]が(ポインタではなく)int型であることを理解していますか?
ここがわからないんです。



この投稿にコメントする

削除パスワード

No.26211

Re:ポインタと[]について
投稿者---NykR(2006/02/20 11:49:43)


1. p[i] == p + i
2. p[i] == *(p + i)
3. *p[i] == p + i
4. *p[i] == *(p + i)

正しいもの(いくつでも)に○をつけてみてください


この投稿にコメントする

削除パスワード

No.26214

Re:ポインタと[]について
投稿者---あきき(2006/02/20 12:08:27)


>1. p[i] == p + i
>2. p[i] == *(p + i)
>3. *p[i] == p + i
>4. *p[i] == *(p + i)
>
>正しいもの(いくつでも)に○をつけてみてください

たぶん、2だけ。でも、それは本に書いてあったからとしか言いようがありません。


この投稿にコメントする

削除パスワード

No.26220

Re:ポインタと[]について
投稿者---NykR(2006/02/20 12:52:54)


>>2. p[i] == *(p + i)
  :
>>正しいもの(いくつでも)に○をつけてみてください
>
>たぶん、2だけ。でも、それは本に書いてあったからとしか言いようがありません。

p[i]と*(p + i)が同じものであることは知っているわけですよね?
でしたら、
「*(p+i)がint型であることを理解していますか?」と「p[i]が(ポインタではなく)int型であることを理解していますか?」は同じことを訊いているということはわかると思いますが。


この投稿にコメントする

削除パスワード

No.26213

Re:ポインタと[]について
投稿者---RiSK(2006/02/20 12:01:47)


>>>pはarrayの先頭アドレスを指し、
>>
>>正確ではありません。
>>p=array;
>>で,pへ(暗黙の型変換により)arrayの先頭要素(array[0])を指すポインタが代入されます。
>
>ポインタにより配列はarray[0]に読み替えられると理解してますが。

うーん…。用語|型変換の規則の理解が足りないのかもしれません。
理解不能な文になっています…。


>>p[i]はポインタの
>>配列の様に思えるのですが、実際は、&p[i]がアドレスです。
>
>なぜp[i]がポインタの配列に思えるのでしょうか?
>もっと突っ込めば,p[i]は「何型への」ポインタの配列だと思ったのでしょうか?

この質問がスルーされています。答えてください。

# 以下長文を書いていましたが,ばっさり削除。
# NykRさんの質問だけで十分ですね。さすが。


この投稿にコメントする

削除パスワード

No.26225

Re:ポインタと[]について
投稿者---あきき(2006/02/20 17:01:42)


>>ポインタにより配列はarray[0]に読み替えられると理解してますが。
>
>うーん…。用語|型変換の規則の理解が足りないのかもしれません。
>理解不能な文になっています…。
>
返信遅れました。

すみません。本では、「配列はポインタに読みかえられる」と書いてありました。

>>>>p[i]はポインタの
>>>配列の様に思えるのですが、実際は、&p[i]がアドレスです。
>>
>>なぜp[i]がポインタの配列に思えるのでしょうか?
>>もっと突っ込めば,p[i]は「何型への」ポインタの配列だと思ったのでしょうか?
>
>この質問がスルーされています。答えてください。

最初、pにはarrayの先頭アドレスが設定されています。
そのpがp[i]と表記されています。array[0]からarray[4]の各要素のアドレスをp[i]に格納しているのかと思い、p[i]は、int*型のポインタの配列と思ったんです。ただ宣言では、int *p;ですから分からなくなって。



この投稿にコメントする

削除パスワード

No.26227

Re:ポインタと[]について
投稿者---DD.(2006/02/20 17:27:58)


>そのpがp[i]と表記されています。array[0]からarray[4]の各要素のアドレスをp[i]に格納しているのかと思い、p[i]は、int*型のポインタの配列と思ったんです。ただ宣言では、int *p;ですから分からなくなって。
p[i] はあくまで、アドレス p から i 分移動したアドレスが指す要素です。
p = array; は暗黙的に p = &array[0]; に変換されます。

いいたいことはわかるんですけど、ポインタとして宣言した変数(int *p)を配列表現として参照したからといって(p[i])ポインタの配列にはならないですし、ポインタとして宣言したのですから、それ以上でも以下でもないと思います。

*p の中身を取得するには *(p+i) とするか p[i] とするんだと割り切ってしまったほうが早いのかも。。。


この投稿にコメントする

削除パスワード

No.26230

Re:ポインタと[]について
投稿者---円零(2006/02/20 19:06:16)


>最初、pにはarrayの先頭アドレスが設定されています。
つまり、p = &(array[0])です。これはいいですね?

>そのpがp[i]と表記されています。
p = arrayですからp[i] = array[i]なんですが、ここまでは大丈夫でしょうか。

>array[0]からarray[4]の各要素のアドレスをp[i]に格納しているのかと思い、
それだと p[i] = &(array[i]) になってしまいませんか?
上記とあわせるとxと&xが等しいと言うことになってしまいます。
そりゃおかしいでしょう。

>p[i]は、int*型のポインタの配列と思ったんです。
話の本筋ではありませんが、これは"p[i]は"じゃなくて"pは"と書いて欲しい。
foo[i]とあったら、fooが配列、foo[i]が配列の要素でしょう。
因みに、ここではp[i]はint型、pはint型へのポインタ型でありint型の配列と同様な扱い方ができる、となります。

>ただ宣言では、int *p;ですから分からなくなって。
つまるところ自分の中の解釈の何かと何かが矛盾したと言うことだと思うんですが、
「分からなくって」じゃあこちには何が分からないのか分からないですよ。


この投稿にコメントする

削除パスワード

No.26233

Re:ポインタと[]について
投稿者---円零(2006/02/20 21:52:47)


別の側面から。

>pはarrayの先頭アドレスを指し、p[i]はポインタの配列の様に思えるのですが、
正確にはp[0]〜p[4]がポインタの配列、と言いたいんだと仮定して進めます。
もしp[0]がarray[0]のアドレス、p[1]がarray[1]のアドレス…とイコールであるとするならば、
p = p[0]、(p + 1) = p[1]…ということになります。
しかし、pと書けばarray[0]のアドレスを表現できるのに、なんでわざわざp[0]で同じものを表現しないといけないのでしょうか。
10 + 20を10[20]と書ける演算子って、あんまり有り難味がないですよねえ。

p[i]は、*(p + i)であって(p + i)ではないのです。
もしも後者だとすれば、p = arrayの時p[i] = &(array[i])、即ち *(p[i]) = array[i]となりますが、
Cの規格はそうではありません。
これは単にp = arrayの時p[i] = array[i]の方が便利だから、と考えてしまって構わないと思います。


この投稿にコメントする

削除パスワード

No.26212

Re:ポインタと[]について
投稿者---DD.(2006/02/20 11:57:05)


>ポインタの配列の様に思えるのですが
「ポインタの配列」つ int *p[10]
「配列へのポインタ」つ int (*p)[10]


この投稿にコメントする

削除パスワード

No.26217

Re:ポインタと[]について
投稿者---あきき(2006/02/20 12:25:59)


>>ポインタの配列の様に思えるのですが
>「ポインタの配列」つ int *p[10]
>「配列へのポインタ」つ int (*p)[10]

すみませんが、「配列へのポインタ」と言う言葉を
はじめて聞くのでもう少し詳しく教えて頂けないでしょうか。
今までは、ポインタの配列を基準に考えていましたので。



この投稿にコメントする

削除パスワード

No.26221

Re:ポインタと[]について
投稿者---DD.(2006/02/20 13:48:29)


int *p[10] は (int*) × 10個 = int型のポインタを指す配列、
int (*p)[10] は (int[10]) を指すポインタになります = 配列を指すポインタ。
#う〜ん。表現の仕方がヘタで申し訳ない

int *parray[10];
int array[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
parray[0] = &array[0];

int (*p)[10];
int pointer_of_array[1][10];
p = pointer_of_array;


この投稿にコメントする

削除パスワード

No.26223

Re:ポインタと[]について
投稿者---kz3(2006/02/20 14:44:01)


>int *p[10] は (int*) × 10個 = int型のポインタを指す配列、
>int (*p)[10] は (int[10]) を指すポインタになります = 配列を指すポインタ。
>#う〜ん。表現の仕方がヘタで申し訳ない

ポインタの"幅"が
    int *p では sizeof(int) 、
    int (*p)[10] では sizeof(int)*10
ということですよね。


#include <stdio.h> int main( void ) { int array[2][5] = { { 1, 2, 3, 4, 5 }, { 10, 20, 30, 40, 50 }, }; int (*p)[5]; int i, j; p = array; for( i=0 ; i<2 ; i++ ){ for( j=0 ; j<5 ; j++ ){ printf( "array[%d][%d] = %d\n", i, j, *((int *)p+j) ); } p++; } return 0; }



この投稿にコメントする

削除パスワード

No.26224

Re:ポインタと[]について
投稿者---DD.(2006/02/20 14:49:40)


>ポインタの"幅"が
> int *p では sizeof(int) 、
> int (*p)[10] では sizeof(int)*10
>ということですよね。
適切な回答ありがとうございます<(_ _)>


この投稿にコメントする

削除パスワード

No.26216

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/20 12:21:18)



>p[i]はポインタの配列の様に思えるのですが、
int *p; と定義しているように pはポインタです。

p = array; としたので pはarrayの先頭を指します
(p = &array[0];と同じです)。

p[i]は pが指す先から数えてi番目の要素です
(この場合はarray[i]と同じです)。

>実際は、&p[i]がアドレスです。
>そこの所が整理できないのです。

&p[i] は「(pが指す先から数えてi番目の要素の)アドレス」です。

http://www9.plala.or.jp/sgwr-t/c/sec10-2.html
をどうぞ。



この投稿にコメントする

削除パスワード

No.26218

Re:ポインタと[]について
投稿者---kz3(2006/02/20 12:29:42)


>>> そして、*(p+i)を、*p[i]に変更しても結果は同じです。
>> 違います。コンパイルエラーになりませんでしたか?
> p[i]のタイプミスでした。
> ですが、pはarrayの先頭アドレスを指し、p[i]はポインタの
> 配列の様に思えるのですが、実際は、&p[i]がアドレスです。

ポインタ配列変数の場合は次のようになります。

#include <stdio.h> #define N 5 int main( void ) { int i; int *p; int array[N]; int **pp; int *parray[N]; for( i=0 ; i<N ; i++ ){ array[i] = i; parray[i] = &array[i]; } /* array の要素は int 型だから int 型へのポインタが p に代入されます */ p = array; /* parray の要素は int 型へのポインタだから int 型へのポインタへのポインタが pp に代入されます */ pp = parray; for( i=0 ; i<N ; i++ ){ printf( "array[%d] = %d\n", i, p[i] ); // ポインタが指す要素の参照 printf( "parray[%d] = %d\n", i, pp[i] ); // ポインタが指すポインタの値の表示 printf( "*parray[%d] = %d\n", i, *pp[i] ); // ポインタが指す要素のポインタが指す要素の参照 } return 0; }



この投稿にコメントする

削除パスワード

No.26219

Re:ポインタと[]について
投稿者---TJ(2006/02/20 12:44:04)
http://home.f01.itscom.net/toge/programingreport/


>ですが、pはarrayの先頭アドレスを指し、p[i]はポインタの
>配列の様に思えるのですが、実際は、&p[i]がアドレスです。
>そこの所が整理できないのです。

(p+i)はアドレスなのに、(似たような表記である)p[i]がなんで要素なのか理解出来ないって事でしょうか?

だとしたら、そうだと覚えるしかないと思います。。


この投稿にコメントする

削除パスワード

No.26231

Re:ポインタと[]について
投稿者---あきき(2006/02/20 20:15:41)


>(p+i)はアドレスなのに、(似たような表記である)p[i]がなんで要素なのか理解出来ないって事でしょうか?

p=array;

と設定してから変更していないから、元に戻して
pをarrayと表現できると言う事でしょうか。つまり、
p[i]→array[i]と。



この投稿にコメントする

削除パスワード

No.26232

Re:ポインタと[]について
投稿者---iijima(2006/02/20 21:41:51)


繰り返しますが、p[i]が*(p+i)と同じものであることは、文法上の決まり事です。
そのように覚えるしかありません。
また、pにarrayを代入したのなら、p[i]とarray[i]は同じです。

    // 確認
    p = array;
    for( i = 0; i < 5; i++ ){
        printf("%d, %d, %d, %d\n", *( p + i ), p[ i ], *( array + i ), array[ i ] );
    }



この投稿にコメントする

削除パスワード

No.26235

Re:ポインタと[]について
投稿者---TJ(2006/02/21 01:15:23)
http://home.f01.itscom.net/toge/programingreport/


>p=array;
>
>と設定してから変更していないから、元に戻して
>pをarrayと表現できると言う事でしょうか。つまり、
>p[i]→array[i]と。

質問の内容と私が書いていることが食い違っているかもしれないのですが、

p = array

とすればp も arrayも殆ど同じ様に使えます。
例えば
p[i] と array[i] は同じ内容ですし、
(p + i) と (array + i) は同じアドレスを指します。

ちなみに、ポインタも配列の名前も同じように使えますが、
p++;
のようにはできても、
array++;
とはできません。


この投稿にコメントする

削除パスワード

No.26239

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/21 07:39:35)


>p=array;
>
>と設定してから変更していないから、元に戻して
>pをarrayと表現できると言う事でしょうか。つまり、
>p[i]→array[i]と。

「元に戻して」という表現がとても気になります。

以下の a は int 型で、
a = 10;
と設定してから(for文の中で)変更していませんが、
「元に戻して」なんて考え方をしますか?

int i, a;
a = 10;
for(i = 0; i < 5; i++) {
    printf("%d\n", a+i);
}

#元に戻す以前に、何もしていないんだが。



この投稿にコメントする

削除パスワード

No.26240

Re:ポインタと[]について
投稿者---あきき(2006/02/21 09:09:02)


>p=array;
>
>と設定してから変更していないから、元に戻して
>pをarrayと表現できると言う事でしょうか。つまり、
>p[i]→array[i]と。

>「元に戻して」という表現がとても気になります。

投稿した後に気づいて、実を言うと、p=arrayですから
p[i]のpを配列の配列の先頭アドレスarrayを用いて表現したかったのです。つまり、p[i]をarray[i]と表せるはずじゃないかと。

違う側面から考えたのですが、
p[i]と*(p+i)の違いを下のように説明するとp[i]はどうなるのか教えていただきたいのです。

*(p+i) == *(配列の先頭アドレス+サイズ(int型)*i) ← 間違いなく、配列のi番目の要素の値を指していると思いますが。
では、p[i]はどう表せるのでしょうか。


この投稿にコメントする

削除パスワード

No.26242

Re:ポインタと[]について
投稿者---nop(2006/02/21 09:58:25)


>p[i]と*(p+i)の違いを下のように説明するとp[i]はどうなるのか教えていただきたいのです。

まず、ここに大きな間違いがあります。
「p[i]」は「*(p+i)」のシンタックスシュガーであり、
単に書き方が変わっただけです。

# 「カッパの川流れ」と「弘法も筆の誤り」等の様に、
# 意味は同じですが、書き方が変わったのです。


>*(p+i) == *(配列の先頭アドレス+サイズ(int型)*i) ← 間違いなく、配列のi番目の要素の値を指していると思いますが。
>では、p[i]はどう表せるのでしょうか。

p[i] == *(p+i) == *( 配列先頭ポインタ + i )

# 仮に「p」がint型配列の時、「p+1」で次の要素を指します。
# 基本的にサイズを意識する必要はありません。


この投稿にコメントする

削除パスワード

No.26243

Re:ポインタと[]について
投稿者---iijima(2006/02/21 10:02:46)


> p[i]のpを配列の配列の先頭アドレスarrayを用いて表現したかったのです。
> つまり、p[i]をarray[i]と表せるはずじゃないかと。

p[i]とarray[i]は、どちらもarray配列のi番目の要素ですよ。
No.26232を再確認してください。


> p[i]と*(p+i)の違いを下のように説明するとp[i]はどうなるのか

"p[i]"は「(pが指す位置+ポインタの型(int型)のサイズ×i)が指す位置にある値」を表します。
"*(p+i)"の説明と違いはありません。

3度目ですが、"p[i]"が"*(p+i)"と同じものであるということは、C言語の文法上の「決まり事」です。
"*(p+i)"の別の表記法(書き方)であると言っても良いです。
気に入らなくても、C言語を使う以上は従うしかありません。

# 3回も同じレスポンスをしましたが、論点がずれてますか?


この投稿にコメントする

削除パスワード

No.26248

Re:ポインタと[]について
投稿者---かずま(2006/02/21 18:56:49)


> p[i]はポインタの配列の様に思えるのですが、
int *p; という宣言があるので、p はポインタ。
[] は配列を表すから、p[i] は「ポインタの配列」。
そう考えたのですね。

ここが誤解の最大のポイントです。

では、int a[5]; という宣言があると、a は配列。
[] は配列を表すから、a[i] は「配列の配列」。
そう考えますか?

違いますね。a[i] は、「配列の i番目の要素」です。
a は配列ですが、a[i] は配列ではありません。a[i] の型は int です。

宣言のときの [] は、その直前の名前が配列であることを表しますが、
式の中での [] は、メモリー上にある配列の要素を表します。



この投稿にコメントする

削除パスワード

No.26249

Re:ポインタと[]について
投稿者---あきき(2006/02/22 01:25:34)


>> p[i]はポインタの配列の様に思えるのですが、

>int *p; という宣言があるので、p はポインタ。
[] は配列を表すから、p[i] は「ポインタの配列」。
そう考えたのですね。
>ここが誤解の最大のポイントです。

>宣言のときの [] は、その直前の名前が配列であることを表しますが、
>式の中での [] は、メモリー上にある配列の要素を表します。

式の中での [] にはそういう意味があったのですか。全然知りませんでした。
でしたら、p=array;と
設定してから常にarrayの先頭アドレスとpが同じである事を前提にしている訳ですよね。



この投稿にコメントする

削除パスワード

No.26251

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/22 11:27:49)


>式の中での [] にはそういう意味があったのですか。全然知りませんでした。
ということは、あききさんが(No.26200で)示したコード
>for(i = 0; i < 5; i++) {
>    array[i] = i;
>}
の[]にはどんな意味があるのと(今まで)解釈していたのでしょう?

>でしたら、p=array;と
>設定してから常にarrayの先頭アドレスとpが同じである事を前提にしている訳ですよね。
前提も何も、(No.26200のコードの)どこに p が変更される
可能性がある、と考えているのでしょうか?

途中でp++ のようなことをやればもちろん違ってきますが。
#このことを指摘したいのですか?
なおNo.26235でTJさんが指摘しているように、array++ のようなことは許されません。

(まとめてレスします)
No.26240
>p[i]のpを配列の配列の先頭アドレスarrayを用いて表現したかったのです。
「配列の配列の先頭アドレス」という表現がtypoであることを祈ります。
arrayは「配列の先頭アドレス(&array[0])」に等しいですが、
「配列の配列の先頭アドレス」ではありません。

>つまり、p[i]をarray[i]と表せるはずじゃないかと。
示されたコードの範囲ではp[i] と array[i]は等しい。
ただし、p[i]もarray[i]も配列の中身(要素)であり、
int型の値である、ということは理解していますか?
#アドレスではありません

示されたコードの範囲では以下の全部が成り立ちます。

1.   p    ==   array    == &array[0] (アドレス)
2.  (p+i) ==  (array+i) (アドレス)
3.  &p[i] ==  &array[i] (アドレス)
4. *(p+i) == *(array+i) (中身)
5.   p[i] ==   array[i] (中身)

もっと極端に書くと

2a.  (p+i) ==  (array+i) == &p[i] == &array[i](アドレス)
4a. *(p+i) == *(array+i) ==  p[i] ==  array[i](中身)

ですが、理解できないのは何番ですか?




この投稿にコメントする

削除パスワード

No.26256

Re:ポインタと[]について
投稿者---あきき(2006/02/23 00:58:32)


返信が遅れて申し訳ありませんでした。

>式の中での [] にはそういう意味があったのですか。全然知りませんでした。
ということは、あききさんが(No.26200で)示したコード
>for(i = 0; i < 5; i++) {
> array[i] = i;
>}
の[]にはどんな意味があるのと(今まで)解釈していたのでしょう?

int array[5];
と宣言しているので、array[i]のは配列のi番目の要素を指している事は
容易に分かります。つまり、[]は配列を示すものと解釈してました。ですが、
int *p;
と宣言しているので、pはポインタです。しかしプログラムの途中で、
p[i]と言うのが出てきています。pはポインタで、[]は配列を表すから、
p[i]はポインタの配列かな、それにしても、「ポインタの配列」の宣言はいつ
行われたのだろう。という疑問が大いにあったのです。
そこは、NO26248のかずまさんが指摘してくれました。

>宣言のときの [] は、その直前の名前が配列であることを表しますが、
>式の中での [] は、メモリー上にある配列の要素を表します。
と。

>でしたら、p=array;と
>設定してから常にarrayの先頭アドレスとpが同じである事を前提にしている訳ですよね。
>前提も何も、(No.26200のコードの)どこに p が変更される
>可能性がある、と考えているのでしょうか?

>途中でp++ のようなことをやればもちろん違ってきますが。
>#このことを指摘したいのですか?
>なおNo.26235でTJさんが指摘しているように、
>array++ のようなことは許されません。

その点について説明不足でした。私が「常にarrayの先頭アドレスと
pが同じである事を前提にしている」というのは、ぽへぇさんがいう
「途中でp++ のようなことをやればもちろん違ってきますが。」を
指しています。

>(まとめてレスします)
>No.26240
>p[i]のpを配列の配列の先頭アドレスarrayを用いて表現したかったのです。
>「配列の配列の先頭アドレス」という表現がtypoであることを祈ります。
>arrayは「配列の先頭アドレス(&array[0])」に等しいですが、
>「配列の配列の先頭アドレス」ではありません。

ご指摘ありがとうございます。私も何を言いたいのかわかりません。
この「pを配列の配列の先頭アドレスarrayを用いて表現したかった
のです。」の部分は「pを配列の先頭アドレスarrayを〜」と
表現したかったのですが、回答者の皆さんに大変な誤解を招いた事
申し訳ありませんでした。

>つまり、p[i]をarray[i]と表せるはずじゃないかと。
>示されたコードの範囲ではp[i] と array[i]は等しい。
>ただし、p[i]もarray[i]も配列の中身(要素)であり、
>int型の値である、ということは理解していますか?
>#アドレスではありません
>
>示されたコードの範囲では以下の全部が成り立ちます。
>
>1. p == array == &array[0] (アドレス)
>2. (p+i) == (array+i) (アドレス)
>3. &p[i] == &array[i] (アドレス)
>4. *(p+i) == *(array+i) (中身)
>5. p[i] == array[i] (中身)
>
>もっと極端に書くと
>
>2a. (p+i) == (array+i) == &p[i] == &array[i](アドレス)
>4a. *(p+i) == *(array+i) == p[i] == array[i](中身)
>
>ですが、理解できないのは何番ですか?

理解できないものはありません。と言うのも、このスレッドは
なぜ、int型をint*型(誤解していた、p[i])に設定できるのかでしたから。

 宣言時の配列の添字演算子[]と
式の中での添字演算子[]の意味は全然違う事がわかりましたので、
p[i]==*(p+i)の意味は理解できました。

ぽへぇさんをはじめ多くの回答者の皆さんどうもありがとうございました。




この投稿にコメントする

削除パスワード

No.26259

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/23 06:19:08)


>その点について説明不足でした。私が「常にarrayの先頭アドレスと
>pが同じである事を前提にしている」というのは、ぽへぇさんがいう
>「途中でp++ のようなことをやればもちろん違ってきますが。」を
>指しています。

それではこのコード例もあわせてどうぞ。

p = array;
for(i = 0; i < 5; i++) {
    printf("[%d]\n", *p);
    p++;
}





この投稿にコメントする

削除パスワード

No.26261

Re:ポインタと[]について
投稿者---あきき(2006/02/23 12:54:34)


>>その点について説明不足でした。私が「常にarrayの先頭アドレスと
>pが同じである事を前提にしている」というのは、ぽへぇさんがいう
>「途中でp++ のようなことをやればもちろん違ってきますが。」を
>指しています。

>それではこのコード例もあわせてどうぞ。

>p = array;
>for(i = 0; i < 5; i++) {
> printf("[%d]\n", *p);
> p++;
>}

array[0]の値がarray[1]からarray[4]まで書きこまれるってやつですか。



この投稿にコメントする

削除パスワード

No.26263

Re:ポインタと[]について
投稿者---kz3(2006/02/23 13:12:14)


>>p = array;
>>for(i = 0; i < 5; i++) {
>>    printf("[%d]\n", *p);
>>    p++;
>>}
>
>array[0]の値がarray[1]からarray[4]まで書きこまれるってやつですか。

違います。どこを見て
配列要素 array[0] を 配列要素 array[1] から array[4] まで
書き込んでいると思われたのでしょうか。

配列要素に対しては参照( 内容の読み出し )しか行われておりません。







この投稿にコメントする

削除パスワード

No.26264

Re:ポインタと[]について
投稿者---nop(2006/02/23 13:12:55)


>array[0]の値がarray[1]からarray[4]まで書きこまれるってやつですか。

とりあえず、動作させてみましょう。


この投稿にコメントする

削除パスワード

No.26269

Re:ポインタと[]について
投稿者---あきき(2006/02/23 21:41:20)


>p = array;
>for(i = 0; i < 5; i++) {
> printf("[%d]\n", *p);
> p++;
>}
>
>array[0]の値がarray[1]からarray[4]まで書きこまれるってやつですか。
>
とんでもないですね。これを書き直したら、以下のプログラムと同じで
array[i]の値を参照してp++しているに過ぎない。
いろんな書き方がありますね。

    array;
    for(i=0;i<5;i++)
    {
        printf("[%d]\n", p[i]);
    }



この投稿にコメントする

削除パスワード

No.26271

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/24 06:56:47)


>p = array;
>for(i = 0; i < 5; i++) {
>   printf("[%d]\n", *p);
>   p++;
>}

>これを書き直したら、以下のプログラムと同じで
>    for(i = 0; i < 5; i++) {
>        printf("[%d]\n", p[i]);
>    }

表示される結果は同じですが、違います。
forの繰り返しの中で、
前者はp(アドレス)が変更されるのに対し、
後者のpは変更されません。

No.26256
>「常にarrayの先頭アドレスとpが同じである事を前提にしている」
>というのは、ぽへぇさんがいう「途中でp++ のようなことをやれば
>もちろん違ってきますが。」を指しています。

ということを書いていたので pが変更される例を示したのですが。
論点がずれていますか?

>array[i]の値を参照してp++しているに過ぎない。
意味不明。





この投稿にコメントする

削除パスワード

No.26272

Re:ポインタと[]について
投稿者---あきき(2006/02/24 09:54:55)


>>p = array;
>for(i = 0; i < 5; i++) {
> printf("[%d]\n", *p);
> p++;
>}

>for(i = 0; i < 5; i++)
>{
> printf("[%d]\n", p[i]);
>}

>表示される結果は同じですが、違います。
>forの繰り返しの中で、
>前者はp(アドレス)が変更されるのに対し、
>後者のpは変更されません。

>No.26256
>「常にarrayの先頭アドレスとpが同じである事を前提にしている」
>というのは、ぽへぇさんがいう「途中でp++ のようなことをやれば
>もちろん違ってきますが。」を指しています。

>ということを書いていたので pが変更される例を示したのですが。
>論点がずれていますか?

いいえ、ぽへぇさんの仰るとおりです。

「ぽへぇさんがいう「途中でp++ のようなことをやれば
もちろん違ってきますが。」」の部分ですが、プログラムの中で
手違いでfor文実行前にアドレスを変更したケースを考慮しただけです。

ですから、for文内での表示方法については、
printf("[%d]\n",p[i]);はアドレスは固定して表示する。
printf("[%d]\n",*p);はアドレスを変更させながら表示する。
この2点を明記しておくべきでした。

array[i]の値を参照してp++しているに過ぎない。
この文章はおかしいですが、メモリー上にある配列の要素の値はアドレスを変更させながら表示させているんだと言いたっかのです。


この投稿にコメントする

削除パスワード

No.26278

Re:ポインタと[]について
投稿者---円零(2006/02/24 11:40:39)


>>array[i]の値を参照してp++しているに過ぎない。
>意味不明。

「p++することによってiが0〜4の場合についてのarray[i]を順に参照している」
「arrayの中身には手をつけず、ポインタであるpをインクリメントしてるに過ぎない」
と言いたかったのではないかと私は推測しました。

全般的に、あききさんの投稿は日本語の段階で混乱があるような気がします。
p[i]を「配列かと思った」と言っていましたが、
配列なのは、実際にはi=0〜4の時のarray[i]なりp[i]なりの集合であって、
その中の一つでしかないarray[i]を「配列」と呼ぶのは、言わば部分をもって全体を表す「換喩」に類する表現です。
赤い頭巾をかぶった少女を「赤ずきんちゃん」と呼ぶようなもの。
自分で使った比喩表現(ないし省略表現)で自分が混乱してしまってはね。


この投稿にコメントする

削除パスワード

No.26268

Re:ポインタと[]について
投稿者---ぽへぇ(2006/02/23 19:57:51)


>array[0]の値がarray[1]からarray[4]まで書きこまれるってやつですか。

全然理解できてないですね。
http://www9.plala.or.jp/sgwr-t/c/sec10-2.html
からやり直してください。




この投稿にコメントする

削除パスワード

No.26265

Re:ポインタと[]について
投稿者---RiSK(2006/02/23 16:52:20)


宣言ではなくて式の[]について:

添え字演算子[]はポインタに使います。
配列に使うわけではありません。

int array[10];
array[1]は*(array+1)です。
array[1]は*(&array[0]+1)です。

array[1]のように式で[]が出てきた時
arrayが配列であることは考える必要はありません。
配列だから[]を使うのではありません。
# ↑ここが誤解の元ですね?
配列が成り下がった「配列の先頭要素へのポインタ」に[]演算子が適用されるのです。

>p[i]==*(p+i)

これはpが配列であろうと,pがポインタであろうと成り立ちます。
なぜpが配列でも成り立つかというと,
配列が先頭要素へのポインタへ成り下がるからです。
この例外のお陰で,ポインタと配列で同じようなアクセスの仕方が
できるようになります。
しかし,何度でも言いますが,ポインタに[]演算子が適用される
です。

添え字演算子[]はポインタにのみ使えます。

int p=array[10];
p[1]は*(p+1)です。
これが単純な本来の意味の(というと語弊があるけど)[]の使い方です。
pはポインタだからです。


この投稿にコメントする

削除パスワード

No.26267

Re:ポインタと[]について
投稿者---RiSK(2006/02/23 16:58:23)


typo.

>int p=array[10];

int array[10];
int*p=array;

に訂正。


この投稿にコメントする

削除パスワード

No.26292

Re:ポインタと[]について
投稿者---まい(2006/02/28 05:48:43)


int a[5]; とはint型の領域を5個確保してその先頭アドレスをaに入れるということだ。

*aとはアドレスaの値を参照するということだ。

またこれはa[0]としても呼び出せる。

それだけだ。


この投稿にコメントする

削除パスワード

No.26293

Re:ポインタと[]について
投稿者---まい(2006/02/28 05:53:27)


(メモリのアドレス)[i]と書けばこれはi個先のアドレスの値を呼び出すという決まりなんだ。C言語だからそうなんだ。文句言うなよ!


この投稿にコメントする

削除パスワード

No.26294

Re:ポインタと[]について
投稿者---YuO(2006/02/28 09:48:35)


あまりに突っ込みどころが満載なので,突っ込んでおきます。


>> int a[5]; とはint型の領域を5個確保してその先頭アドレスをaに入れるということだ。

int a[5];とは,要素型をint型とする,要素数5個の配列オブジェクトに識別子aを付ける,という宣言です。
識別子aが指し示すオブジェクトはあくまでint [5]型であって,int *型ではありません。
# このあたりの説明は,「オブジェクト」と「識別子」の区別がついていないとわかりにくいかも。


>> *aとはアドレスaの値を参照するということだ。

*aは「ポインタaが指すオブジェクト」を指し示す左辺値です。
# aが関数を指すポインタの場合を除く。
「アドレスaの値を参照する」は意味不明。


> (メモリのアドレス)[i]と書けばこれはi個先のアドレスの値を呼び出すという決まりなんだ。C言語だからそうなんだ。文句言うなよ!

そんな決まり,どこに書いてあるのやら……。
そもそも,「メモリのアドレス」って何のことだか……。

ポインタ型のオブジェクトpが配列aのi番目のオブジェクトを指していて,
整数型のオブジェクトjがあった時にp[j]は配列aの(i + j)番目の要素を指し示す左辺値になります。
# ただし,i + jは0以上であり,配列aの要素数未満であること。



この投稿にコメントする

削除パスワード

No.26295

Re:ポインタと[]について
投稿者---まい(2006/02/28 13:44:34)


>識別子aが指し示すオブジェクトはあくまでint [5]型であって,int *型ではありません。

int a[5]; はint型の領域を5個確保して、その先頭のアドレスをポインタ定数aにセットするの!int [5]型なんて存在しないの!
ポインタとの違いはaが変化させられない定数だという点だけ!


この投稿にコメントする

削除パスワード

No.26296

Re:ポインタと[]について
投稿者---REE(2006/02/28 14:13:55)


>>識別子aが指し示すオブジェクトはあくまでint [5]型であって,int *型ではありません。
>
>int a[5]; はint型の領域を5個確保して、その先頭のアドレスをポインタ定数aにセットするの!int [5]型なんて存在しないの!
>ポインタとの違いはaが変化させられない定数だという点だけ!

sizeof(a)を確認してみましょう。


この投稿にコメントする

削除パスワード

No.26311

Re:ポインタと[]について
投稿者---REE(2006/02/28 19:37:25)


世話が焼けますねえ

#include <stdio.h>

int main() {
    int a[5];
    int *b;
    printf("sizeof(a)=%d\n", sizeof(a));
    printf("sizeof(b)=%d\n", sizeof(b));
    return 0;
}


結果
sizeof(a)=20
sizeof(b)=4




この投稿にコメントする

削除パスワード

No.26297

Re:ポインタと[]について
投稿者---かずま(2006/02/28 14:26:45)


定数じゃないよ。
#include <stdio.h>

void f1(void) { int a[5]; printf("a = %p\n", a); }
void f2(void) { f1(); }
int main(void) { f1(); f2(); return 0; }

---------------------------------------------
gcc での実行結果

a = 0x22ee60
a = 0x22ee50



この投稿にコメントする

削除パスワード

No.26302

Re:ポインタと[]について
投稿者---円零(2006/02/28 17:14:37)


>定数じゃないよ。
>#include <stdio.h>
>
>void f1(void) { int a[5]; printf("a = %p\n", a); }
>void f2(void) { f1(); }
>int main(void) { f1(); f2(); return 0; }
>
>---------------------------------------------
>gcc での実行結果
>
>a = 0x22ee60
>a = 0x22ee50

それってstaticじゃないことの証明では?
「定数」とはまた別の話では…


この投稿にコメントする

削除パスワード

No.26315

Re:ポインタと[]について
投稿者---かずま(2006/02/28 20:36:47)


> それってstaticじゃないことの証明では?
>「定数」とはまた別の話では…

別の話ではありません。JIS X3010:2003 の「6.6 定数式」または
JIS X3010-1993 の「6.4 定数式」のところに、

: アドレス定数(address constant)は、空ポインタ、静的記憶域期間のオブ
: ジェクトを指し示す左辺値を指すポインタ又は関数指示子を指すポインタ
: とする。アドレス定数は、単項&演算子若しくは整数定数のポインタ型への
: キャストによって明示的に生成されるか、又は配列型若しくは関数型の式
: の使用によって暗黙に生成されたものでなければならない。

とありますから、static でなければアドレス定数ではないということです。


この投稿にコメントする

削除パスワード

No.26320

Re:ポインタと[]について
投稿者---円零(2006/02/28 22:39:55)


>> それってstaticじゃないことの証明では?
>>「定数」とはまた別の話では…
>(略)
>JIS X3010:2003 の「6.6 定数式」または
>JIS X3010-1993 の「6.4 定数式」
>(略)
>static でなければアドレス定数ではないということです。

なるほど、奥が深い。
しかし、「ポインタ定数」と「アドレス定数」は同義なんですか?


この投稿にコメントする

削除パスワード

No.26298

Re:ポインタと[]について
投稿者---YuO(2006/02/28 15:57:28)


>int a[5]; はint型の領域を5個確保して、その先頭のアドレスをポインタ定数aにセットするの!int [5]型なんて存在しないの!
>ポインタとの違いはaが変化させられない定数だという点だけ!

で,その根拠は?

ISO/IEC 9899:1999 6.2.5 Para. 20

An array type describes a contiguously allocated nonempty set of objects with a particular member object type, called the element type.

ISO/IEC 9899:1999 6.3.2.1 Para. 3

Except when it is the operand of the sizeof operator or the unary & operator, or is a string literal used to initialize an array, an expression that has type “array of type” is converted to an expression with type “pointer to type” that points to the initial element of the array object and is not an lvalue.


あたりを読めば,「配列型」というものが存在し,それがポインタ型ではないことが自明だと思いますが。



この投稿にコメントする

削除パスワード

No.26309

ここ嫁!
投稿者---まい(2006/02/28 19:11:19)


C言語-Wikipedia http://ja.wikipedia.org/wiki/C%E8%A8%80%E8%AA%9E
> 配列とポインタの宣言は別物であるが、配列操作の実体はポインタ演算である。
> ポインタを配列表記でアクセスすることや、その逆も可能。(糖衣構文)



糖衣構文-Wikipedia http://ja.wikipedia.org/wiki/%E7%B3%96%E8%A1%A3%E6%A7%8B%E6%96%87
> 糖衣構文の例
> C言語の配列の記法 a[i] は、 *(a + i) の糖衣構文である。
> 前者の方が読みやすいのは、明瞭である。
> また、配列の操作であって純粋なポインタ演算ではないことを示唆できる。
> (なお、i[a]と表記しても同じ結果となる。このことをもって、
> 「C言語には本当の『配列』は無い」とする意見がある。)


この投稿にコメントする

削除パスワード

No.26310

Re:ここ嫁!
投稿者---nop(2006/02/28 19:34:54)


参照が規格でない時点でおル。
こちらへどうぞ。


この投稿にコメントする

削除パスワード

No.26312

Re:ここ嫁!
投稿者---あかま(2006/02/28 19:42:39)


REEさんもかかれてますが
>int a[5]; はint型の領域を5個確保して、その先頭のアドレスをポインタ定数aにセットするの!int [5]型なんて存在しないの!
>ポインタとの違いはaが変化させられない定数だという点だけ!
ならば↓のaとbは同じサイズを表示するはず

#include <stdio.h>

int main(){
    int a[5],*b,c;
    b = a;
    printf("a:%d\n",sizeof(a));//int[5]型のサイズ
    printf("b:%d\n",sizeof(b));//int *型のサイズ
    printf("c:%d\n",sizeof(c));//int 型のサイズ
    return 0;
}

ではintともint*ともサイズの違うaはいったい何型?

ついでに問題
int *a[5];
int (*a)[5];
の違いはなんでしょう?
これが分かれば多分問題ないです。



この投稿にコメントする

削除パスワード

No.26322

Re:ここ嫁!
投稿者---YuO(2006/03/01 02:06:49)


うーーん,だからどうした,という記述しかないのですが。
Wikipediaの文章は間違っていないのですが,それは規格から導き出せる範疇です。
# 「本当の配列」の有無は,そもそも「本当の配列」とは何か,という定義の問題に帰着するかと。


信頼できる根拠を提示して貰わないと話にならないので,対象を限定しましょう。

国際標準規格であるISO/IEC 9899:1999 Programming languages -- C,
またはその国内一致規格であるJIS X 3010:2003 プログラム言語Cにおいて,
int a[5];という宣言が,
・int型を要素型とし5個の要素を持つ配列型のオブジェクトを指し示す,aという識別子の宣言
ではなく,
・int型を指すポインタ型のオブジェクトを指し示す,aという識別子の宣言
である根拠はどこにあるのでしょうか。


この投稿にコメントする

削除パスワード

No.26313

Re:ポインタと[]について
投稿者---nop(2006/02/28 19:47:23)


>int [5]型なんて存在しないの!

では、何故以下の様なソースはコンパイルエラーとなると言うのですか?
# 「int [5]」型が無ければ、「int (*)[5]」型もあり得ないはずですし、
# 以下のソースがコンパイルエラーにもならないはずです。


void  hoge( int (*a)[5] )
{
    /* 「a」を使ってホニャララ */
}

int  main( void )
{
    int  a[10];
    hoge( &a );

    return 0;
}



この投稿にコメントする

削除パスワード

No.26314

Re:ポインタと[]について
投稿者---επιστημη(2006/02/28 19:50:01)


> int [5]型なんて存在しないの!

ありますよん。

#include <iostream>
#include <typeinfo>

int main() {
  char a[5];
  char* b;
  std::cout << typeid(a).name() << std::endl;
  std::cout << typeid(b).name() << std::endl;
}

実行結果
char[5]
char*



この投稿にコメントする

削除パスワード

No.26316

Re:ポインタと[]について
投稿者---かずま(2006/02/28 20:42:47)


>  std::cout << typeid(a).name() << std::endl;

C をよく理解していない人に、C++ で例を示しても仕方ないでしょう。
char [5] 型を使った Cプログラムを示します。

#include <stdio.h>

void func(char [5]);

int main(void)
{
    return printf("%d\n", sizeof(char [5]));
}



この投稿にコメントする

削除パスワード

No.26317

Re:ポインタと[]について
投稿者---επιστημη(2006/02/28 21:24:31)


>>  std::cout << typeid(a).name() << std::endl;
> C をよく理解していない人に、C++ で例を示しても仕方ないでしょう。

ごもっとも (^^
コンパイラが認識している型を直接晒すにはこれしかないかな、と思って。




この投稿にコメントする

削除パスワード

No.26318

Re:ポインタと[]について
投稿者---かずま(2006/02/28 22:17:10)


> コンパイラが認識している型を直接晒すにはこれしかないかな、と思って。

でも、typeid(...).name() で出てくる表示は処理系依存ですよ。g++ だと

char[5]
char *

ではなく、

A5_c
Pc

と出てしまいますよ。


この投稿にコメントする

削除パスワード

No.26319

Re:ポインタと[]について
投稿者---επιστημη(2006/02/28 22:38:50)


>> コンパイラが認識している型を直接晒すにはこれしかないかな、と思って。
>でも、typeid(...).name() で出てくる表示は処理系依存ですよ。

それもごもっとも。少なくともコンパイラはX[]とX*を別の型として認識してるってとこまではわかりますけどね (^^



この投稿にコメントする

削除パスワード

No.26323

Re:ポインタと[]について
投稿者---まい(2006/03/01 07:21:23)


配列よくわかってなかったみたいです。すみません。


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧