- ベストアンサー
ポインタのポインタについて
VisualC++2008 の、Windowsフォームアプリケーションを使用しています。 自作クラスの中に組み込む線形リスト的なものを、後で移動したりする場合実体のコピーをしなくて済むよう 今、「アドレス」を格納する配列を作りたいです。 しかし、ポインタのポインタに対して色々実験してみたのですが どうもあと一歩ぐらいのところで手が届きません フォームのイベントで、試しに以下のように書いてみると Text = ""; char *a[8], b =7 ,*c = new char[7], i =7; while (i) { c[i] = --i; a[i] = &c[i]; } a[7] = &b; while (i<8) Text += *(*a+i++); delete c; これを実行したとき フォームのTextが 「01234567」 となってほしいのですが 「0123456-3」 となってしまいます。 試してみたのですが その直後にbを調べると、やはりちゃんと7になっており また a[7] と &b をifおよび==を用いて比較してみても 同じになっています。 なお、この-3というのはどうも、解放処理の後でそこにアクセスした場合はこの場合 「-35」 となり、確保中の時に代入してないアドレスにアクセスすると 「-3」 となるような感じです。 このような、連続していないアドレスへの参照を配列化しておいて取り出す事は出来ないのでしょうか?
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
えぇと, 「配列的な書き方」とか「ポインタ的な書き方」ってのは厳密に区別する必要はないと思いますよ. 今どきのコンパイラなら (それなりな最適化オプションをかければ) 同じコードにするはずですから, プログラム上で読みやすい書き方をすべきでしょう. でフォームの話はやったことないので見なかったことにして (<ぉぃ), 未定義動作関係の話だけします. c[i] = --i; という文が未定義動作になるのは, 直接的には「オブジェクトの値を変更する場合, その値は新しい値を決めるため以外に使ってはいけない」という規定によります. 今の例に即してもっとかみくだいていうと「右辺のデクリメントがどのタイミングで実行されるか確定していない」ことと「左辺と右辺のどちらを先に計算するかが定まっていない」ことの 2点が問題になります. つまり, コンパイラはこの文を (例えば) --i, c[i] = i; と解釈してもいいし c[i] = i-1, --i; と解釈してもかまいません (未定義動作なので「全く関係ない動作」を含む他のどのような解釈もありうるが). ... あれ? *(*a+i++) って, (*a)[i++] と等価ですよね.... *a[i++] と等価にしたいなら **(a+i++) では?
その他の回答 (3)
- FBL
- ベストアンサー率0% (0/3)
ガイドラインを読んでみて、これだけなら問題ないはず・・・? と思ったので、連絡・状況整理用に別IDで回答欄を使わせてください。 質問者です。 「質問・問題の解決につながる投稿」ですので、種類は「回答」にさせていただきます。 ちゃんと前置・後置という言葉があるんですね。 今回の質問は大丈夫そうなので締め切りとさせていただきます。 そして、残っている2点についてかなりかみ砕いて新質問を立てました。 後で見て分かりやすいようにここにリンクをはっておきますので、よろしければよろしくお願いいたします。 一時的なポインタを作る場合との速度比較についてです http://oshiete1.goo.ne.jp/qa4645062.html インクリメント、デクリメントの順序について http://oshiete1.goo.ne.jp/qa4645073.html
- asuncion
- ベストアンサー率33% (2127/6289)
>配列的な書き方しか出来ないのは最速処理は出来なく、 pをポインタ、nをスカラとするとき、 *(p+n) は p[n] と同値です。おそらく、どちらの書き方でも 処理速度は同じでありましょう。
お礼
ありがとうございます。 すみません。 直されるとさきほど本でチェックしました。そうですよね? ポインタのややこしさに気を取られて微妙に履き違えた感じの事を書いてしまったっぽいです。 私が言いたかったのは、下記のような内容です。
- Tacosan
- ベストアンサー率23% (3656/15482)
あ, とりあえず c[i] = --i; という文は未定義動作となるので書いちゃダメです. そこが問題となっている可能性はありませんかね.
お礼
ありがとうございます。 なんか教えて!gooに投稿してみたら思ったより見にくくて・・・ 申し訳ありません この右側は、実際には先行デクリメントっていうのかな・・? です。 もしそれでもNGということならば 知っておきたいです。 どういう風に未定義動作扱いになるのでしょうか? こちらでやっている分には、そういう事をやる分だけには問題なく、ビルドは出来、ちゃんと先にiが-1されてからiがc[i]に格納される という風に、動作も出来るようです。 2個目のwhile文の中身の右辺の部分の括弧を外す、つまり **a+i++; てやったら出来ちゃいました。 にゃんかムズイですね。 ここも配列っぽく書くと *a[i++]; ってなりますが、こちらでもできました。 さらに 受け渡しは出来るのか確認するべく、ちょいと改造して新たな実験をしてみました。 Text =""; char **a=new char*[8], *d[8], b=7 ,c[7], i=7; while (i) { c[i] =--i; a[i] =&c[i]; } a[7] =&b; for (;i<8;i++) d[i] =a[i]; delete a; while (i) Text +=*d[--i]; 結果は、ちゃんと 「76543210」 になりました。 ただ、これで本当に合ってるのかどうか…というと、ちゃんと把握できてないのでちょっと不安です これは、ちゃんとaからdにアドレスの配列を受け渡せた、って事でOKでしょうかね…?
補足
・・・ってよく考えたら **a+i++ は、違いますね。 やり方の問題で一見結果としては同じに見えただけで、これでは単に*c+i++と同じ事ですよね(苦笑) c[i] = --i; を c[i] = --i+1; などとやってみたら 12345678 になってしまいました。やはり違う。 しかし *a[i++] ならば間違いないようです 12345677 と、正しい解を出せました! うーむ、しかし配列的な書き方しか出来ないのは最速処理は出来なく、悔しいので、ポインタ的書き方が2重ポインタで出来るならそっちも知りたいです。
お礼
ありがとうございます。 えっと、そこなんですが・・・ 私は基本的に、式というのは右から左へ実行されるはずだと思っていました。 しかし インクリメント、デクリメントが含まれる場合は、つまりそういう感じに微妙になる、ということでしょうか? **(a+i++) でできました! ありがとうございます。 ちょっと私は内容の趣旨を勘違いしていたかもしれません。 下のを変形させてみると(これもできました)私がやりたかった事はこんな感じの事です。 Text =""; char **a=new char*[8], *d[8], b=7 ,c[7], i=7; char *f =c+7 ,**g =a+7, **h =d; a[7] =&b; while (i) { *--f =--i; *--g =f; } for (;i<8;i++) *h++ = *g++; delete a; while (i) Text +=*d[--i]; こういう事ならば、毎回iの値を確認しなくてすむので、そういう比較においてはこちらの方が高速ですよね?
補足
ちなみに同様の内容について、この書き方ならば、両辺に同じものが含まれている事はないので、問題ない、という事でしょうか?