• 締切済み

C++ 2次元配列について 【 初心者です 】

こんにちは.C++初心者です. 以下のプログラムは, オブジェクトの2次元配列の作成と そのアクセスをポインタで行うことを 目的としています. 以下の□■部が質問箇所です. なぜobをsamp型でキャストするのか分かりません. obはすでにsamp型で宣言しているのに… それと※部において 2度目のp++処理について教えていただきたいです. メモリーイメージを書いてもらえると ありがたいです。 よろしくおねがいします。 #include <iostream.h> using namespace std; class samp { int a; public: samp(int n) { a = n; } int get_val() { return a; } }; int main(void) { samp ob[3][2] = { 1, 2 3, 4, 5, 6 }; int i; samp *p; // □■□■□■□■ p = (samp *) ob; for(i = 0; i < 3; i++) { cout << p->get_val() << ' '; p++; ※ cout << p->get_val() << endl; ※ p++; } cout << endl; return 0; } }

みんなの回答

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.5

>ところでメンテナンスで処理を追いにくくする要因とは、 >具体的にはどのような影響があるのですか? それは、あなたが1番理解しているはずです。 あなたは、このコードを見て、どうしてこういう処理で動くのか理解できずにこちらに質問されました。 プログラムのメンテナンスというのはプログラムを作った人間とは別の人間が行うことが多々あります。 メンテナンスとはようするにコードの修正なのですが、修正するにはそのコードの動きを理解しなくてはなりません。 そのとき、このように理解しづらいコードがあると、その分メンテナンス作業が遅れることになります。

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.4

>free(p)とメモリを解放せずにいました… これは、まずいですよ^^;)。freeで解放するのは mallocしたものです。同様に deleteしていいのは newした領域です。 このプログラム上では、p は ob配列の領域を指すアドレスを一時的に格納する為の変数です。 #1の方の補足部分ですが >ところでメンテナンスで処理を追いにくくする要因とは、 今回の場合、ポインタでループする特別な理由がない限り普通に配列で参照した方があとで見直したときに解りやすいと思います。 for (i = 0; i < 3; i++) {  cout << ob[i][0].get_val() << ' ';  cout << ob[i][1].get_val() << endl; } もっと大きなプログラムですと顕著です。1ヶ月後の自分でも解るプログラムを書くようにしましょう>自分(T_T)

  • ranx
  • ベストアンサー率24% (357/1463)
回答No.3

どう見ても初心者が勉強すべきコードじゃないな。 hitomuraさんのいう「添字を使って書く」ということですが、 p->getval() と書いてあるところを、 ob[i][0].get_val() という書き方にするということで良いと思います。 どうしてもポインタにこだわるのであれば、 そもそもobを二次元配列にする必然性のあるプログラムには見えないので、 samp ob[6]; という定義にしてしまえば、元々のご質問であるキャストも 不要になりますし、C++のコードとしては、その方がすっきりします。 samp (*p)[2]; という定義の仕方もありますが、これも初心者にはお勧めしません。

  • yatokesa
  • ベストアンサー率40% (201/496)
回答No.2

> p = (samp *) ob; 2次元配列の ob を単純に参照すると、型は samp** です。p = ob としてもコンパイル時にワーニングが出るだけでバイナリに違いはでません。 1回目のループで考えると、 >cout << p->get_val() << ' '; で p は ob[0][0]をさしています。 >p++; p++することで ob[0][1] をさします >※ cout << p->get_val() << endl; p は ob[0][1]をさしています。 >※ p++; で、ob[1][0] をさします 3回ループしたとき全ての ob配列は出力され、pはob配列の外側をさした状態で終了しますが、プログラム上で「使わないこと」を前提に問題有りません。 配列は連続したメモリイメージです。お絵かきをしてループを1ステップずつ追いかければ見えてくると思いますよ。

soramamegorou
質問者

補足

こんにちは。非常にわかりやすくかったです。 ポインタpの「後始末」というか free(p)とメモリを解放せずにいました… ありがとうございました。

  • hitomura
  • ベストアンサー率48% (325/664)
回答No.1

>なぜobをsamp型でキャストするのか分かりません. >obはすでにsamp型で宣言しているのに… おしい。obはsamp**形の定数と考えたほうがいいです。 また、キャストされた型はsamp*形です。 C/C++では、ポインタ形と元の型とでは明確に異なります。 >それと※部において >2度目のp++処理について教えていただきたいです. >メモリーイメージを書いてもらえると >ありがたいです。 配列obの各要素は、メモリ上では次のように並んでいます。  ob[0][0],ob[0][1],ob[1][0],ob[1][1],ob[2][0],ob[2][1] そして、obという値はob[0][0]を指すポインタ値となります。 このポインタ値の型は前述のとおりsamp**なのですが、これをsamp*型にキャストすることで上記の並びをあたかも1次配列であるかのように扱えるようになります。 最初のcout<<…ではob[i][0]の内容を出力し、p++することでメモリ上での次の要素であるob[i][1]をpが指すようにしてやっています。 2回目のcout<<…でob[i][1]の内容を出力し、p++することでメモリ上での次の要素であるob[i+1][0]をpが指すようにしてやっています。 …しかし、もし私がこのプログラムを監査する立場にあったら、この部分を添字を使って書くようにさせます(処理速度が問題になってるならば別ですが)。 なぜなら、このようなコードはのちのメンテナンスで処理を追いにくくする要因だからです。

soramamegorou
質問者

補足

さっそく詳細な解説ありがとうございます。 内容は大筋理解できました。 ところでメンテナンスで処理を追いにくくする要因とは、 具体的にはどのような影響があるのですか? 私は,学生のみで実際の開発現場はよく分かりませんので ご教示いただけれるとこれから注意してコードを 書くことができるのですが。 ところで、添え字とすれば.。。。。 /* ob[i * J_SIZE * j] 但し,J_SIZE は,#define J_SIZE ○ とマクロ定義されているものとします. */ といったコードでしょうか? 以上,よろしくおねがいします。

関連するQ&A

  • 配列の要素

    #include <iostream> using namespace std; int main() { int n[10] ={1,2,3,4,5,6,7,8,9,10}; int i; for(i = 0; i < 10; i++){ cout << "a[" << i << "] = " << n[i] << endl; } return 0; } ここまでは完成することはできたのですが この要素の並びをシャッフルしてランダムな順に並び変える方法がわかりません。

  • C++でどうすればcoutで表示できるのですか?

    C++についての質問です coutで表示するときに kannsuu関数の返り値を main関数とmain関数の cout << ++kannsuu(i) << endl; の部分を変更せずに kannsuu関数のみを変更して インクリメントして「2」と表示したいのですが どのようにすればいいですか? #include <iostream> using namespace std; int kannsuu(int i) {return i;} int main() { int i = 1; cout << ++kannsuu(i) << endl; return 0; }

  • オブジェクトのポインタ

    #include<iostream> using namespace std; class letters{ char ch; public: letters(char c){ch=c;} char get_ch(){return ch;} }; int main(){ letters ob(A) cout<<ob.get_ch(); return 0; } なんですが cout<<ob.get_ch(); を cout<<&ob->get_ch(); には何故できないのですか? これならコンパイルできるのですが、 letters *p; p=&ob; cout<<p->get_ch(); コンパイラはVisual Studio 2008です よろしくお願いします。

  • C++で乱数を重複しないように発生させる

    C++で乱数を重複しないように発生させるようにプログラムを変更しろと言われたのですが、できません。 教えていただきたいです。 #include<iostream> #include<cstdlib> #include<cstring> #include<ctime> using namespace std; int main() { int i,n; int *p; cout<<"何個記憶しますか?"<<endl; cin>>n; p=new int[n]; if(p==NULL){ cout<<"記憶域の確保に失敗しました。"<<endl; return 1; } srand((unsigned)time(NULL)); rand(); i=0; while(i<n){ p[i]=1+(int)((double)rand()/(RAND_MAX+1.0)*75); if(p[i]==p[i]) cout<<"p["<<i<<"]の値"<<p[i]<<endl; i++; } delete[] p; return 0; }

  • C++超初心者質問

    Visual C++ 2008 Express Edition Ver9.0.30729.1 SP を利用し、以下のプログラムを実行するための手順を教えてください。 Visual C++ 6.0では、ファイル>新規作成→ファイルTAB>C++ソースファイルのように、上記の場合はどのように進んだらよいのでしょう? ファイル>新規作成>プロジェクト→Win32 コンソール アプリケーション??? とすると、↓のエラーが出てしまいます。尚、VC2008をインストールしてから何も触っていません。 http://okwave.jp/qa4665322.html ソース #include<iostream> using namespace std; class coord{ int x,y; public: coord(){x=0;y=0;} coord(int i,int j){x=i,y=j;} void get_xy(int &i,int &j){i=x;j=y;} friend coord operator+(coord ob1,int i); friend coord operator+(int i,coord ob1); }; coord operator+(coord ob1,int i){ coord temp; temp.x=ob1.x+i; temp.y=ob1.y+i; return temp; } coord operator+(int i,coord ob1){ coord temp; temp.x=ob1.x+i; temp.y=ob1.y+i; return temp; } int main(){ char c[3]; // 画面固定のため coord o1(10,10); int x,y; o1=o1+10;; o1.get_xy(x,y); cout<<"(o1+10)X:"<<x<<",Y:"<<y<<"\n"; o1=99+o1;; o1.get_xy(x,y); cout<<"(99+o1)X:"<<x<<",Y:"<<y<<"\n"; cout<<"\nエンターで抜けます"<<endl; // 画面固定のため gets(c); return 0; }

  • C++

    今、下のようなプログラムを作っています #include <iostream> #include <iostream> using namespace std; int i=0, c=0, n; char str[10]; class X16karax10{ //16進から10進ヘ public: void keisan(); }; void X16karax10::keisan(void){ cout<<"16進を入力して下さい"<<endl; cout<<"英数字は大文字で入力してください(F→○ f→×)" <<endl; scanf("%s",str); while(str[i] != '\0'){ n = n * 0x10; c = str[i++]; if((c >= '0') && (c <= '9')){ n += c - '0'; } else if((c >= 'A') && (c <= 'F')){ n += c - 'A' + 10; } } cout<<("%d\n",n)<<"です\n"<<endl; } int main(){ for(i=0; ; i++){ X16karax10 p; p.keisan(); } } 16進を十進に変えるものなのですがreturn 0を使うと「X16karax10::keisan()' は値を返せない」と、でてしまうのですがどうしたらよいでしょうか?

  • C++プログラム問題(初心者です)

    C++の勉強初めて1ヶ月ぐらいです。 以下にある問題がわかりません。 解説付きでお願いします。 [問題] 関数 funcのみを修正することで、標準出力に 2 が表示する。 [プログラム] #include <iostream> using namespace std; int func(int i) {return i;} int main() { int i = 1; cout << ++func(i) << "\n"; return 0; }

  • C++の配列について

    #include <iostream> using namespace std; int main() { float w[] = {1.2,2.3,3.4,4.5,5.6}; float x[] = {4.8,2.6,1.3,9.1,8.7}; float u = 0.0; int i; for(i=0;i<5;i=i++) { u += w[i] * x[i]; } cout << "u=" << u << "です\n"; return 0; } u=105.83って出たんですが、これは何をしているプログラムなんですか

  • C++について教えてください。(初心者です)

    現在C++についての学習を進めているのですが、 2項演算子のオーバーロードで理解できないところがありますので、よろしかったらご教授ください。 //+をcoordクラスに対してオーバーロードする #include<iostream> using namespace std; class coord{ int x,y; public: coord() {x=0;y=0;} coord(int i,int j) {x=i;y=j;} void get_xy(int &i,int &j) {i=x;j=y;} coord operator+(coord ob2); }; //+をcoordクラスに対してオーバーロードする coord coord::operator+(coord ob2) { coord temp; temp.x = x + ob2.x; temp.y = y + ob2.y; return temp; } int main() { coord o1(10,10),o2(5,3),o3; int x,y; o3 = o1 + o2; o3.get_xy(x,y); cout << "(o1+o2) X:" << x << ",Y:" << y << endl; return 0; } この文の中で、o3.get_xy(x,y);というコードがありますが、 ここの部分がよくわからないのです。 そもそも、引数としてx,yがありますが、これはprivateメンバを 見に行きなさい。っと言っているのでしょうか? main()の中から直接使っている?? それとも?? すいません。この辺の理解が薄いようなので、2項演算子のオーバーロードとは関係ないかもしれませんが、教えてください。 よろしくお願いします。

  • C++で,配列に計算した値を入れたいです.

    C++で疑似乱数を発生させてサイコロをつくったのですが, サイコロを5回転がしたときのそれぞれの値をソートしたいと思い,配列に入れれば簡単だと考えてとりあえず配列に入れるプログラムを書いてみました. しかし,int array[i] = Dice(); のところでエラーが出てしまいます. ローベルのC++入門講座という本を使って独学で勉強している初心者なため,配列の使い方がいまいちよくわかりません. ご教授よろしくお願いします. 以下ソースコード #include <iostream> #include <cstdlib> #include <ctime> using namespace std; void InitRand(){ srand((unsigned int) time (NULL)); } int Dice(){ return rand() % 6 + 1; } int main(void){ int n = 0; //nはサイコロを転がす回数 cout <<"サイコロを何回転がしますか?" << flush; cin >> n; cout << "回転がします" << endl; InitRand(); for(int i = 0; i < n; ++i){ cout << Dice() << endl; int array[i] = Dice(); //エラーが発生する.i回目のサイコロの値をi番目の配列に入れたい. } }