- ベストアンサー
for 文における処理の改善(C言語プログラム)
はじめまして。panicdjです。 いまCでプログラムを組んでいます。 環境はVC++ver6.0 Win32 Console Applicationです。 以下のプログラムを見てください。 #define X_MAX 10 #define Y_MAX 20 #define Z_MAX 5 int main(int argc , char ** argv) { int i, j, k; int aa[10][20][5]; for (i = 0; i < X_MAX; i ++) { for (j = 0; j < Y_MAX; j ++) { for (k = 0; k < Z_MAX; k ++) { aa[i][j][k] = 10.0; } } return 0; } 過去のスレッドでポインタ型によるアクセスを すれば、処理が高速になるとかかれていました。 自分は,for文による繰り返す処理ではなく, その「ポインタ型によるアクセス」を実装したいのです。 こんな私にアドバイスお願い致します。
- みんなの回答 (9)
- 専門家の回答
質問者が選んだベストアンサー
> C言語などを解説しているサイトでのサンプルコードとかでしょうか?? も、含めてですね。オープンソースなプログラムとかでもよいと思います。勉強の種は沢山転がってますから探してみてください。 > これは、たとえばVCを用いているのであれば、デバッカの プログラミングの際の話のつもりで書きました。頭の中にメモリのイメージ(箱とか?)を思い浮かべると良いです。今宣言した変数はどこにあるのか、とか、ポインタの先の実体はどこなのかというのを常に意識してということです。 > できることなら、参考になる書籍やサイトを提示させて 残念ながら Cに関しての書籍・サイトともに知りません。 が、http://alfin.mine.utsunomiya-u.ac.jp/~niy/algo/index.html で集められた関数等は勉強になると思います。
その他の回答 (8)
- yatokesa
- ベストアンサー率40% (201/496)
>for (i = X_MAX*Y_MAX*Z_MAX; i; i--) { >とすると、速くなるのでしょうか? 理屈は #6:terra5さんのとおりです。また、terra5さんの仰るとおり、コンパイラが勝手に最適化する可能性もありますので、知っている人が見れば気分的に早いコードだ!って気分になれる程度の速さです^^;)。デバッグモードなどでアセンブラとの混合リストを見ると違いが分かるかもしれません。 >レベルなのでなんとかその域から脱却したのですが。 私が Cを始めたのはもう十ン年前なので...。私が学習したのは「はじめてのC」というやつですがね。公開されている色々な人のコードを見るのが良い勉強になると思います。 ポインタを理解したいのなら、常に変数がどのメモリ(スタックも含めて)に配置されているのかを考えながらコーディングすることです。
お礼
yatokesaさん,何度もアドバイスいただきありがとうございます。 >公開されている色々な人のコードを見るのが良い勉強になると思います ちょっと、別件なのですが、↑は,サイトで公開されているコードとは、 C言語などを解説しているサイトでのサンプルコードとかでしょうか?? >ポインタを理解したいのなら、常に変数がどのメモリ(スタックも含めて)に配置されているのかを考えながらコーディングすることです。 上記についてもう少し教えてください. これは、たとえばVCを用いているのであれば、デバッカの 混合モードを開いてアセンブラでどの変数がpushされているか とか確認することなのでしょうか?? 私は、詳しく混合モードの使い方 (例えば、espレジスタなどのレジスタの詳しい機能 他) がよくわかっていません。 できることなら、参考になる書籍やサイトを提示させて 頂けると助かるのですが. 以上、どうかよろしくおねがいします!
- shuyamakawa
- ベストアンサー率67% (111/164)
#4 a-kuma様 int* p_end = &aa[X_MAX][Y_MAX][Z_MAX]; は int* p_end = &aa[X_MAX-1][Y_MAX-1][Z_MAX-1] + 1; が正しいのではないかと... (^^;;;
お礼
syuyamakawaさん、ご助言ありがとうございましたっ!!
- terra5
- ベストアンサー率34% (574/1662)
ポインタを理解するなら意味がありますが、 高速化の為に・・なら、あまり意味がないですね。 まず、意味があるほどの差がでないか、変わらないですし、 読みづらいプログラムは悪です(^^; >for (i = X_MAX*Y_MAX*Z_MAX; i; i--) { >とすると、速くなるのでしょうか? アセンブラレベルの話になりますが、 CPUの命令は、ある値とある値が等しいかを比べる命令が無いか, あってもある数値が0かどうかを調べる命令より実行速度がたいてい遅いからです。 (命令が無い場合は引き算をして、結果が0かどうかを調べるという、二つの命令を実行することになります) ただ、コンパイルしてアセンブラになる時に どんな命令になるかはわかりませんから、 必ずしも速いとは言い切れません。 現在のコンパイラは最適化といって、 こういう高速化のための小細工は勝手にやりますので。
お礼
terra5さん、詳しい解説ありがとうございました. 「処理はコンパイラが最適化する」とのことですが、 処理の高速を考える際は,どのような観点から コードを組めばよろしいのでしょうか?? よろしくおねがいします!!
- mkii
- ベストアンサー率40% (43/105)
int aa[X_MAX][Y_MAX][Z_MAX]; int *p = (int *)aa + sizeof (aa) / sizeof (int); while (p != (int *)aa) *--p = 10; 怒られそうだ(笑)
お礼
mkiiさん、ご助言ありがとうございます!!
- a-kuma
- ベストアンサー率50% (1122/2211)
No.2 の回答にある >「見やすさを優先するためのプログラミングをした方が良いと思います。」 に大きく同意しつつ、もうちょっと早そうなコードを。 int aa[X_MAX][Y_MAX][Z_MAX]; int* p = &aa[0][0][0]; int* p_end = &aa[X_MAX][Y_MAX][Z_MAX]; while (p != p_end) { *p++ = 10; } もし、 int* p_end = &aa[X_MAX][Y_MAX][Z_MAX]; が気持ち悪いのであれば、 int* p_end = p + X_MAX * Y_MAX * Z_MAX; でも OK 。 # この程度のサイズなら、たいした差は出ないと思いますよ。
お礼
a-kumaさん、名前によらず天使のようなアドバイスありがとうございます! >int* p_end = &aa[X_MAX][Y_MAX][Z_MAX]; (1) >が気持ち悪いのであれば、 >int* p_end = p + X_MAX * Y_MAX * Z_MAX; (2) 僕の場合、なぜか(1)の方の初期化の方がしっくりきてしまいました。 (2)のような初期化はたいへん参考になります。 どうもありがとうございました!
- yatokesa
- ベストアンサー率40% (201/496)
fuji1さんと同じ回答になってしまいました for (i = 0; i < X_MAX*Y_MAX*Z_MAX; i++) { ↓ for (i = X_MAX*Y_MAX*Z_MAX; i; i--) { とした方が、多少スピードアップになると思います。
補足
すみません、なぜ以下のように、 for (i = X_MAX*Y_MAX*Z_MAX; i; i--) { とすると、速くなるのでしょうか?
- yatokesa
- ベストアンサー率40% (201/496)
見やすさを優先するためのプログラミングをした方が良いと思いますよ。コンパイラの最適化によってあまり速度差がでないこともあります。 上限の決まっている領域の初期化は、for文かwhileを使うのは仕方ないことでしょう。それをふまえて、ポインタを使うと次のような感じで出きると思います。 int *p; int aa[X_MAX][Y_MAX][Z_MAX]; // 折角defineしているのだから、定数を使いましょう int i; p = (int*)aa; for (i = 0; i < X_MAX*Y_MAX*Z_MAX; i++) { *p++ = 10; // 10.0は浮動小数です } ですか、ね。
お礼
yatokesaさん、お返事ありがとうございます。 >見やすさを優先するためのプログラミングをした方が良いと思いますよ。 ごもっともですが、僕のプログラムはまだまだです。 細かい点も注意して頂きありがとうございます。 PS。yatokesaさんがプログラムを組む上で、または勉強した本やサイトの 中で推薦できるものがあったら教えて頂きたいのですが。。 僕は、一般的なC言語本にあるサンプルコードのような レベルなのでなんとかその域から脱却したのですが。
- fuji1
- ベストアンサー率29% (109/371)
こんにちは。 int 型なのに、10.0 入れてはいけませんよ。(^o^)丿 さて、配列の場合は、基本的にはリニアにメモリを確保されることになります。 ですから、 #define X_MAX 10 #define Y_MAX 20 #define Z_MAX 5 int main(int argc , char ** argv) { int i; int aa[10][20][5]; int *p ; p = (int *)aa ; for (i = 0; i < X_MAX * Y_MAX * Z_MAX; i ++) { *(p++) = 10 ; } return 0; } でOKだと思います。 ただ、このリニアにとられるというのは、どんなときにもとは行かないので、アーキテクチャを確認する必要はありますね。 Wintel 系だったら大丈夫だと思いますが。
お礼
fuji1さん早速の解答ありがとうございます。 御返答の内容について質問があります。 >配列は、基本的にはリニアにメモリを確保されることになります。 つまり、malloc()関数を用いたときと 異なり、連続的にメモリが確保されるというこですね? >ただ、このリニアにとられるというのは、どんなときにもとは行かないので、 >アーキテクチャを確認する必要はありますね。 ↑のことがよくわかりません。 リニアに確保できないarchitectureとは例えばどのような 構造でしょうか? よろしければついでに教えて頂きたいのですが・・・ >Wintel 系だったら大丈夫だと思いますが。 Pentium 3を使っています.
お礼
yatokesaさん、何度もアドバイスありがとうございます。 >> C言語などを解説しているサイトでのサンプルコードとかでしょうか?? >も、含めてですね。オープンソースなプログラムとかでもよいと思います。勉強の種は沢山転がってますから探してみてください。 はい、承知しました。 yatokesaさん、いろいろ教えて頂きありがとうございました。 なお、本スレッドでお世話になった方にも感謝しています。 ありがとうございました!!