
2次元配列を作り、そのアドレスなどを表示させましたが
どうもおかしいです。
3行5列の配列で、3本のポインタ配列がありますが、
その配列のアドレスがかぶっているのです。
まずはコンパイルしてみてください。
#include<stdio.h>
main()
{
int i;
int k;
int y=1;
int **p;
p=(int **)malloc(sizeof(int *)*3);
for(i=0;i<=2;i++)
{
*(p+i)=(int *)malloc(sizeof(int)*5);
}
for(i=0;i<=2;i++){
for(k=0;k<=4;k++){
p[i][k]=(i+k)*y;
}
y=y*10;
}
for(i=0;i<=2;i++){
for(k=0;k<=4;k++){
printf("%4d",*(*(p+i)+k));
}
printf("\n");
}
printf("\n");
for(i=0;i<=2;i++)
{
printf("%p\n",p+i);
}
printf("\n");
for(i=0;i<=2;i++)
{
printf("%p\n",&p+i);
}
printf("\n");
for(i=0;i<=2;i++)
{
printf("%p\n",*(p+i));
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",*(p)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&*(p)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&**(p)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",*(p+1)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&*(p+1)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&**(p+1)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",*(p+2)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&*(p+2)+i);
}
printf("\n");
for(i=0;i<=4;i++)
{
printf("%p\n",&**(p+2)+i);
}
printf("\n");
for(i=0;i<=2;i++){
for(k=0;k<=4;k++){
printf("%p\n",&*(*(p+i)+k));
}}
free(p);
return 0;
}
どこがかぶっているかと申しますと、
for(i=0;i<=4;i++)
{
printf("%p\n",&*(p)+i);
}
とfor(i=0;i<=4;i++)
{
printf("%p\n",&*(p+1)+i);
}
と
for(i=0;i<=4;i++)
{
printf("%p\n",&*(p+2)+i);
}
です。
これが同じアドレスになるはずは論理的にありえないことです。
VC++2008無料バージョンです。
よろしくお願いいたします。
No.1ベストアンサー
- 回答日時:
> printf("%p\n",&*(p)+i);
*(p)で、pが指している場所の値を取りだしています。
そして、&で、そのアドレスを取り出しています。そこは、pそのものです。
つまり、&*(p)+i は、p+i と同じです。
同様に、
> printf("%p\n",&*(p+1)+i);
&*(p+1)+i は、p+1+i と同じです。
また、
> printf("%p\n",&*(p+2)+i);
&*(p+2)+i は、p+2+i と同じです。
結局、おかしいとおっしゃっている3つのループでは、それぞれ
p~p+4
p+1~p+5
p+2~p+6
を出力しています。
重複している部分があります。そこが同じ値になるのは当然です。
ありがとうございます。
そこでp[1][3]に注目してみました。
それがこれです。
#include<stdio.h>
main()
{
int i;
int k;
int y=1;
int **p;
p=(int **)malloc(sizeof(int *)*3);
for(i=0;i<=2;i++)
{
*(p+i)=(int *)malloc(sizeof(int)*5);
}
for(i=0;i<=2;i++){
for(k=0;k<=4;k++){
p[i][k]=(i+k)*y;
}
y=y*10;
}
for(i=0;i<=2;i++){
for(k=0;k<=4;k++){
printf("%4d",*(*(p+i)+k));
}
printf("\n");
}
printf("%d\n",p[1][3]);
printf("%p\n",&p[1][3]);
printf("%d\n",*(*(p+1)+3));
printf("%p\n",*(p+1)+3);
printf("%p\n",&*(p+1)+3);
printf("%p\n",&*(p+2)+2);/*アドレスがかぶってしまっている*/
return 0;
}
下から1個目と2個目が理解できません。
p[1][3]に入っている値は40、
p[1][3]のアドレスは00370764、
*(p+1)+3が指す先は40、
*(p+1)+3が入っている値は00370764
ここまでは理解できます。
じゃあ
*(p+1)+3のアドレスはと思い、調べようと思ったのです。
*(p+1)+3のアドレスを調べようと思い、&をつけたら
なんと勝手に1+3=4を計算してしまっています。
ためしに*(p+2)+2のアドレスも調べてみたら2+2=4なので
同じアドレスになっています(最終行)
どうやったら
p[1][3]のアドレスが入っている変数のアドレス
を知ることができるのでしょうか?
No.16
- 回答日時:
言語使用の解説からちょっと行ってみましょう。
質問者様は左辺値と右辺値をご存知ないようですね。(もしご存知ならこれを見て復習してください。)
Cの値には左辺値と右辺値があり、右辺値は1だとか2だとかいった数値などです。
左辺値とは右辺値の入れ物を指すものです。
a = 10;
とあれば、aが左辺値、10が右辺値です。
また、左辺値は右辺値が要求される場所にあった場合、自分の持っている右辺値を返します。
a = b;
bは左辺値ですが、bは自分の持っている右辺値を代入演算子に渡します。
「&」はアドレス演算子といいます。
この演算子は単項演算子で、右結合です。
オペランドとして左辺値を取り、そのポインタを返します。
ポインタとはそれだけではただの右辺値であり、左辺値ではありません。そこで「*」が登場します。
「*」は間接演算子といい、ポインタ型の左辺値を右辺値にします。
よって以下のとおりとなります。(コメントは面倒なんでC99方式)
char *p; //ポインタ
char c = 'a'; //char型
p = &c; //cのアドレスをpに保存 (cは左辺値でアドレス演算子により右辺値のchar*型の値を返す。pは左辺値なので、pの右辺値が書き換えられる。
*p = 'b'; //pはchar*型だが、間接演算子によりポインタの指す場所(c)の左辺値を返す。結局この式はc = 'b';と同じになる。
putchar(*p); //pはchar*型だが、間接演算子により該当する場所の左辺値(cと等しい)を返す。しかし、関数の引数は右辺値を取るので*pの持つ値を返す。結局この式はputchar('b')ということになる。
という感じです。右辺値と左辺値については参考URLをご覧ください。
要するに左辺値は場所、右辺値は数値であり、場所からしかアドレス演算子でアドレス(ポインタ)が取れないのです。
ポインタ自体は場所を示す数値であり、場所じゃないので、間接演算子で場所を取ります。
そして、配列は先頭から連続する場所として作られるので、先頭アドレスにインデックスを加算したアドレスを間接演算子に渡すと、配列の指定されたインデックスの場所を返してくれるわけです。
そして、場所からは数値が取れますが、数値からは数値がいる場所は取れません。たとえば、左辺値を箱、右辺値を箱に入ってる玉として、玉を見るためには箱から取り出す必要があったとします。
箱に入ってる玉は、箱を開けて取り出してみれば分かります。箱を開けて玉を取り出しました。さて玉はどの箱に入っているのでしょうか?
さっきの箱? いいえ、違います。取り出してるので今手元にある玉はどの箱にも入っていません。
どの箱にも入っていないのだから、箱の場所は分かりません。
実際の計算機上ではきっとレジスタといわれるアドレスの取れない一時的な記憶領域に計算のために、(あるいは計算の結果として)置かれています。
参考URL:http://ja.wikipedia.org/wiki/%E5%80%A4_(%E6%83%8 …
みなさん、ありがとうございました。
とりあえず、浅い理解はできました。
これ以上深追いするのはやめておきます。
数学でもなんでもそうですが、ある時突然わかる日が来る場合もあります。
僕は頭が悪いのでその日は来ないかもしれません。
しかし大変ためになりました。
No.15
- 回答日時:
>a+1は7を指差し、a[1]のアドレスも持ち
>a+2は8を指差し、a[2]のアドレスも持っています。
指してはいますが、持ってはいません。
"自分"はそもそも居ません。居ませんから居場所もありません。
aの1つ次、2つ次、です。
int a = 5;
printf ("%d \n", a);
printf ("%d \n", a +1);
printf ("%d \n", a +2);
↑で6、7を保持する変数は居ないのと一緒です。
No.14
- 回答日時:
>a+1は7を指差し、a[1]のアドレスも持ち
>a+2は8を指差し、a[2]のアドレスも持っています。
>それなのに、自分のアドレスは持っていない(居場所が無い)というのは
>どういうことなのでしょうか?
そうですね。確かに、コンピューターの中の、「ある場所」にa+1という値は存在しています。
しかし、コンピュータの中というのは、すべての場所にアドレスがあるわけじゃないんです。CPUのレジスタだったり、あるいはレジスタですらないCPUの回路のどこかだったりします。こういった場所にはアドレスがありません。
a+1なんて値は、たいていそういった場所にしか存在しないんです。なので、C/C++の規格では、a+1といった値に対してはアドレスが取れないことになっています。そのほうが実行時の効率がいいからです。
このあたりはアセンブラを勉強してみると、感覚がつかめると思います。
最近のCPUはいろいろと複雑になっていて、わかりやすい本とかも少ないと思いますが、さらなる興味がおありでしたら、勉強してみるのもいいかと思います。
No.13
- 回答日時:
> printf("%p\n",a+1);/*a[1]のアドレスを保持している*/
保持しているとは、メモリー中のどこかにある、という意味ですか?
だとすると、それは勘違いです。
a+1という式で、a[1]という領域を指すことができるだけです。
No.11
- 回答日時:
> p=(int **)malloc(sizeof(int *)*3);
> まずここでポインタ配列を3個確保しています。
これはいいですね。ポインター配列の各要素には、p[0], p[1], p[2]で
アクセスできます。
> *(p+i)=(int *)malloc(sizeof(int)*5);
> ここでポインタ配列を15個確保しています。
> この15個の中身はp[i][j]のアドレスが入っています。
ここで勘違いされています。
「ポインター配列を15個確保している」というのは、誤りです。
このmallocで確保するのは、p[0], p[1], p[2]のそれぞれにぶら下がる
5個のint型領域です。5個のint *型領域ではありません。
当該のint型領域には、例えばp[1][2]でアクセスできます。
p[1][2]のアドレスは、通常の配列と同じように、&p[1][2]で求めます。
No.10
- 回答日時:
> printf("%p\n",&*(p+1)+i);
>にしたらコンパイルはできたということなんです。
コンパイルが通ればいいってもんじゃありません。
&*(p+1)+i
というのは、すなわち、
(p+1)+i
p+1+i
と同じです。なので、あなたが表示させたい値ではないと思います。
ではなぜ、
>printf("%p\n",&(*(p+1)+i));
がエラーになるかというと、
*(p+1)+i
に実体がないからです。
int a;
と、したときに、
&a
はaのアドレスを返しますが、
&(a+1)
は実体がないのでエラーになります。これと同じことです。
だんだん見えてきました。
僕の完全な勘違いでした。
昨日書いた定理は間違いでした。
#include<stdio.h>
main()
{
int a[3]={5,7,8};
printf("%d\n",*a);
printf("%d\n",*(a+1));/*指差している*/
printf("%d\n",*(a+2));
printf("%p\n",a);
printf("%p\n",a+1);/*a[1]のアドレスを保持している*/
printf("%p\n",a+2);
printf("%p\n",&a);
printf("%p\n",&(a+1));
printf("%p\n",&(a+2));
return 0;
}
僕はこれが正しいと思っていたんです。
しかし、下3行がコンパイルエラーになります。
しかし、それはいいとして、
a+1は7を指差し、a[1]のアドレスも持ち
a+2は8を指差し、a[2]のアドレスも持っています。
それなのに、自分のアドレスは持っていない(居場所が無い)というのは
どういうことなのでしょうか?
自分はメモリ上に存在しないのに、指を指し、アドレスを保持しているとはどういう理屈なんでしょうか。
存在しないのに指を指しアドレスを保持できるなんていう話は
聞いたことがありません。
No.9
- 回答日時:
#8です。
先ほどの回答に書き間違いがありました。> p[2][0]:p[0]と同じ, p[2][1]:0x00953468, p[2][2]:0x0095346C, p[2][3]:0x00953470, p[2][4]:0x00953474
ではなくて、
p[2][0]:p[2]と同じ, p[2][1]:0x00953468, p[2][2]:0x0095346C, p[2][3]:0x00953470, p[2][4]:0x00953474
です。
No.8
- 回答日時:
せっかくなので、もう少しおつきあいさせてください。
私のところで実験してみると、動的に確保した領域のアドレスは、それぞれ
p:0x00953424
p[0]:0x00953434, p[1]:0x0x0095344C, p[2]:0x00953464
p[0][0]:p[0]と同じ, p[0][1]:0x00953438, p[0][2]:0x0095343C, p[0][3]:0x00953440, p[0][4]:0x00953444
p[1][0]:p[1]と同じ, p[1][1]:0x00953450, p[1][2]:0x00953454, p[1][3]:0x00953458, p[1][4]:0x0095345C
p[2][0]:p[0]と同じ, p[2][1]:0x00953468, p[2][2]:0x0095346C, p[2][3]:0x00953470, p[2][4]:0x00953474
となりました。
どこもダブっていません。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
- C言語・C++・C# LU分解法のピボッティングについて(C言語/gcc-9) 3 2022/07/11 23:10
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# C言語 プログラミング 4 2022/05/22 11:53
- C言語・C++・C# LU分解法のピボット選択機能実装について(C言語・gcc-9) 1 2022/07/22 15:20
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
- C言語・C++・C# C言語の課題が出たのですが自力でやっても分かりませんでした。 要素数がnであるint型の配列v2の並 3 2022/11/19 17:41
- C言語・C++・C# プログラミング c言語 4 2023/03/07 01:05
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
高(1)男子 初めてC言語でコー...
-
C言語で 選択肢: |?| |?| |?| 1...
-
C++
-
+NANってなんですか??
-
ダブルポインタで2次元配列を作成
-
書式制御'%d'と'%f'について
-
c言語でAからZまでを表示する...
-
printf関数の振る舞い?に関して
-
プログラムの演算時間を調べた...
-
至急!!!! C言語のこのプロ...
-
C&C++、計算結果を表示する
-
プログラミングでわからないと...
-
y=x^3-2x^2-3の解を求めるプロ...
-
プログラムの作成
-
C言語トランプの確率を計算につ...
-
Cの九九を表示するプログラム...
-
両替プログラムなど
-
C言語についてです。(困ってお...
-
最適化したプログラムによる計...
-
文字列
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
10個出力で改行したいのですが...
-
c言語で2000年以降カレンダーを...
-
c言語でAからZまでを表示する...
-
【C】fizzbuzzのトリッキーなコ...
-
strcmp
-
printf で二進表示を行いたい。
-
【C言語教えてください】sin波...
-
コマンドラインに出力した文字...
-
8人分のテストの点数を入力し、...
-
コンパイルエラーについて
-
CTRL+Dでループを抜けるには
-
(C言語)めちゃくちゃな値にな...
-
cshの文字列操作(0埋め)
-
テキストカーソル位置の取得
-
コマンドプロンプトがすぐ消える
-
printfの出力内の文字をdefine...
-
scanfに文字が入力されたときに...
-
台形の面積を求めるプログラム
-
改行について 1行に何個かづ...
-
WM_CLOSEで閉じれないウィンド...
おすすめ情報