- ベストアンサー
Cの配列についての質問
- Cの配列についての質問についての要約文です。
- C言語の配列における数字の表示が変な数字になる原因について説明します。
- gcc4.6.3とubuntu 12.04の環境下でのC言語の配列の表示に関する質問です。
- みんなの回答 (8)
- 専門家の回答
質問者が選んだベストアンサー
- ベストアンサー
> 少しずれてしまいますが、お行儀が悪いというのはどういった点ででしょうか? このアクセス方法を習慣にしてしまうのは良くありません。 データ型はプログラムの整合性を保つのに重要な役目を果たすので、キャストは避けるべきです(興味があれば「ラッセルのパラドックス」を調べてみてください)。 メモリ上の連続した領域に二次元配列が確保されるので一次元配列のようにアクセスできますが、保守のしやすさやバグの混入を予防するならfor文を入れ子にし、a[i][j] のように本来の二次元配列としてアクセスした方が良いと思います。プログラマの良心として。
その他の回答 (7)
- akayoroshi
- ベストアンサー率50% (46/91)
#6の回答に示したコードの訂正です。 int *b, *be=&a[0][0]+(sizeof a / sizeof(int)); for ( b=&a[0][0]; b<be; b++ ) printf("%2d", *b);
お礼
下よんでわからなかったんですが、とてもわかりやすくなっていますね。これなら理解できるかと思います。 ありがとうございます。
- akayoroshi
- ベストアンサー率50% (46/91)
#5の回答のコードを、[]を使わないで for (i =0;i<(sizeof(a)/sizeof(a[0][0]));i++){ printf("%2d", *((int *)a+i) ); } と書いても同じです。 私なら、二次元配列のすべての要素を一重のforループで参照したければ、たとえば、 int *b, *be=b+(sizeof a / sizeof(int)); for ( b=&a[0][0]; b<be; b++ ) printf("%2d", *b); のようにします。
お礼
後半部分がかなり僕には難しいので、いろいろテストして理解を深めようと思います。ありがとうございました。
> 下に書いたように(int)*aの書き間違いでしたが、 *a の値は a[0] と同じです。そして a は二次元配列です。なので a[0] は一次元配列の先頭アドレスになります。つまりそれが「変な数字になってしまう」理由です。 下のように強制的に一次元配列であるかのように扱えば、お望みの結果が得られるでしょう(あまり行儀が良い方法とは言えませんが)。 for (i =0;i<(sizeof(a)/sizeof(a[0][0]));i++){ printf("%2d", ((int *)a)[i]); }
お礼
ありがとうございます。 このようなループにできないか考えていました。 少しずれてしまいますが、お行儀が悪いというのはどういった点ででしょうか?
- Tacosan
- ベストアンサー率23% (3656/15482)
正しいプログラムはどうなっているのでしょうか? 全て出してください. あと, その場合どのような数字が出ているのでしょうか?
お礼
実現できる、というのはmain関数内でできるということです。口下手で申し訳ありません。
補足
ここまでと書いているところまではそのままです。 \Nと\nを間違えている部分については\nが正しいです。 それ以降のプログラムは(3行ですが)自分で考えた部分です。 後出しになるのは困るのでここで言っておかなければならないのは、 setの部分に for (i= 0;i<n;i++){ printf("%d",b[i]) } と書くと1が26並ぶので、同じ動作をiとaだけで実現できるか知りたいだけなのです。
変な数字に見えるのはメモリのアドレスだからです。配列の名前はその配列の先頭アドレス、つまりメモリ上のどの番地から配列が始まるか、を返します。 この数字はデータの存在する場所を意味し、配列に代入した値(この場合は1)とは無関係です。 また、printf("%2d",(int *)a);でアドレスを10進数の整数で表示していますが、一般的にはアドレスの表示に printf(" %p",a); を用います(お使いの環境では配列のアドレスが16進数で表示されます)。for文で繰り返しても、単に a だけではいつも先頭アドレスを返すので、繰り返し同じアドレスが表示されるだけです。 該当部分を下のようにすると、a[i][j]のアドレスと、配列に代入した値の関係が分かりやすいでしょう。 for (i = 0;i<M;i++){ for (j= 0;j<N;j++){ printf(" %p=%p:%d=%d", &a[i][j], ((*(a+i))+j), a[i][j], *((*(a+i))+j)); } printf("\n"); }
補足
下に書いたように(int)*aの書き間違いでしたが、 残念なことにちょうど同じタイミングで書いてしまったようですね。 *((*(a+i))+j)が目的とするものに近いです。 この部分を1つの変数で表す(set()と同じように)するにはどうすればいいかを考えて、現在困っています
- k_kota
- ベストアンサー率19% (434/2186)
これが何を表示しようとしているのか理解していますか? 何を表示しようとしているのか補足して下さい。 そこが合ってないと変な数字の何が変なのかがはっきりしません。 まあ、ポインタ型を整数で出力したらまともな値はでない気がします。
お礼
目的というか、予想したのは1が26回続く出力です
補足
下にも書きましたが、(int *)aは(int) *aの間違いです
- Tacosan
- ベストアンサー率23% (3656/15482)
何を表示しようと思ってそのように変更したのでしょうか? そして, それで何を表示しているのか理解できていますか? あと, printf("\N"); はおかしいと思うよ.
お礼
上に書き忘れてしまったので。 111111 111111 111111 111111 が本来の結果として得られます
補足
上のset()で配列の数によらないようにsizeofを用いて、かつ1次配列のように扱ったので、main関数内でも1次配列のようにしてa[][]を出力できるか調べようとしていました。 書き写し間違いなのですが、最後の部分が(int)*aとしたのの間違いです 直接のコピーではないので、いろいろ書き間違えています
お礼
ありがとうございました。 ラッセルのパラドクスをとりあえず理解しましたが 今回の件までどう関係するかはわかりません。 とりあえず、保守性に欠けるというのは かなりわかりやすく、そのようなことがないよう頑張っていきたいと思います。