• ベストアンサー

p[-3][-4]にアクセス出来るようにしたい

ポインタのポインタをうまく使って、p[-3][-4]のようなアクセス(が有効に行われるように)したいのですが、うまくいきません。 ご教授願えないでしょうか。 以下のコードで p[-3][0] を a[0][0] を参照させる(?)ようにはできました。 後ろ側の添え字のマイナスシフトができないのです。 つまり p[-3][-4] が a[0][0] を参照させるようにするギミックが知りたいのです。よろしくお願いします。 ------------------------------------- int **a; // 領域の動的確保 ( [12][18] ) a = new int*[12]; for(int i = 0; i < 12; i++) a[i] = new int[18]; int **p; p = &(a[3]) ; for (int y=0; y<12;y++) for (int x=0; x<18;x++) a[y][x] = 1; p[-3][0] = 99; //a[0][0]が99になる。 //領域の解放 for(int i = 0; i < 12; i++) delete [] a[i]; delete [] a;

質問者が選んだベストアンサー

  • ベストアンサー
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.3

どうしてもp[-3][-4]がa[0][0]を参照するようにしたいのでなければ、次のようにしてはどうでしょう。 ------------------------- int **a; // 領域の動的確保 ( [12][18] ) a = new int*[12]; for(int i = 0; i < 12; i++)  a[i] = (new int[18]) + 4; // ← 変更点 int **p; p = &(a[3]) ; for (int y=0; y<12;y++)  for (int x=0; x<18;x++)   a[y][x] = 1; p[-3][0] = 99; //a[0][0]が99になる。 //領域の解放 for(int i = 0; i < 12; i++)  delete [] (a[i] - 4); // ← 変更点 delete [] a; ------------------------- 上のコードでは、p[-3][-4]がa[0][-4]を参照することになりますが、目的は満たせるのではないでしょうか。

lachesis-r
質問者

お礼

素晴らしいです。感動しました。 こんなに早く目的通りの回答をいただきありがとうございました。 (念のためもう1日程待ってから閉めたいと思います。)

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (10)

  • alfsan
  • ベストアンサー率0% (0/2)
回答No.11

ポインタのポインタをうまく使って・・の項目が絶対でなければ ポインタを使わずに、そこのindexをとったほうがわかりやすくてスピードもそんなに落ちないと思うのですが、どうでしょうか int **p; -> int pX, pY; p = &(a[3]) ; -> pX=3;pY=4; p[-3][0] = 99; //a[0][0]が99になる。 -> pX-=3;pY-=4;a[pX][pY]=99; あと、c++では普通動的配列なら、標準のvectorをオススメしておきます。 最適化がきけば、普通の配列と同じ速度でアクセスできるらしいので、今回のような用途でも大丈夫だと思います 使い方はこんな感じ #include <stdio.h> #include <vector> int main(){ using namespace std; vector< vector<int> > table(12);//vector<int>が12個入ったvecor<vector<int> >を作る for(int i = 0; i < table.size(); i++){ table[i].resize(18,i);//各要素vector<int>を、サイズが18の値が全てiのintで初期化する } for(int y=0;y<table.size();y++){ for(int x=0;x<table[y].size();x++){ printf("%d,",table[y][x]);//表示してみる } } return 0;//開放は自動でやってくれる }

lachesis-r
質問者

お礼

回答ありがとうございます。 vectorはbuilderのコンパイラでは普通に使っても速度的に不利なことが分かっていますので(最初に確認済み)どうしてもアルゴリズムを使いたい場合に限定されます。 (インテルコンパイラだとよいのかもしれませんね) 最初の例は、クラスの内部でアドレスをオフセットするのと同じですね? builderのコンパイラは加算部分を常には最適化できないようで、着目アドレス以外(隣とか)を同時にアクセスすると遅くなるようです。(きちんと確認できていませんが)

全文を見る
すると、全ての回答が全文表示されます。
  • jacta
  • ベストアンサー率26% (845/3158)
回答No.10

少しだけチャチャを入れます。 > 恥ずかしながらreinterpret_castというのは初めて見ました。 reinterpret_castでオブジェクト型へのポインタを他のオブジェクト型へのポインタ型に変換した場合、(境界調整の条件さえクリアしていれば)元のポインタ型に再変換しても値が変わらないことが保証されているだけで、それ以外は未規定(要するに不定)になります。 T x; U* p = reinterpret<U*>(&x); assert(reinterpet_cast<T*>(p) == &x); // OK reinterpret_castは整数型とポインタ型の間の相互変換等には使えますが、それ以外は案外使い道がありません。(現物合わせで動けばOKなら使えますが...)

lachesis-r
質問者

補足

c++について勉強不足が露呈しました^^; 理解する前にまず使ってきているので基礎ができていませんね。反省です。 テンプレート?も使った経験がないので、機会があればトライしてみます。

全文を見る
すると、全ての回答が全文表示されます。
noname#30727
noname#30727
回答No.9

#5です。 >このテクニックは、2次元配列(に見える1次元配列)が隙間無く並んでいる事を利用してるんですよね? 仮に1次元単位の先頭(何と呼んだらいいのだろう)でアラインメントされたとしても特に影響無いですから、何かを利用したテクニックと言えるような大層なものではないです。 >2次元配列から1次元配列にアドレス変換するときに乗算が発生するのでテーブルの方が早いと思いますがいかかでしょうか? テーブル参照が無い方が有利というのは不用意な発言でした。 アクセス毎にインデックスからアドレス変換するのであれば、テーブル参照の方が有利な事もあると思います。 しかし、ループさせて計算する場合などは、最適化によってアドレス変換からポインタの移動に置き換えられる事も多いですし、縦方向の移動も単純な加減算で解決できます。 計算内容やアーキテクチャと処理系の違いで結果が変わりそうです。 >reinterpret_castというのは初めて見ました。 C++スタイルのキャストを使うと、キーワードに色を付けられるエディタで注意しやすくなっていいですよ。 (そんな理由で推奨するのを他で聞いた事は無いですが・・・)

lachesis-r
質問者

お礼

そうですね。ループ内で注目座標だけにアクセスする場合、コンパイラはアドレスを1づつデクリメントするものに変えてくれてもよさそうですよね! builderのコンパイラは2重ループの場合にはそこまでできない?ようです。速度的には不利でした。 もうちょっと色々試してみないと総合評価はできないですが、1次元配列も選択肢として残すべきですね。 ありがとうございました。

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.8

#2,#4回答者です。 pと同じ性質(qが配列へのポインタであって、qに対する添字に-3が使用できること)とは、すなわち 1. 配列を確保し 2. その配列に対してq[-3]のような形でアクセスできるようにqを初期化する ということです。 その上でq[n] = p[n] + 4を行うと、結果としてq[n]の内容は、#3でのp[n]の内容と同じになります。

lachesis-r
質問者

お礼

補足ありがとうございます。 やはり別に領域を確保しないといけないのですね。 今すぐは確認できませんが(^^; ちょっと試行してみます。

全文を見る
すると、全ての回答が全文表示されます。
  • sha-girl
  • ベストアンサー率52% (430/816)
回答No.7

えっ?って感じで質問をみましたが、回答の内容をみて関心しました。 ちなみにC++ならclassで[]演算子をオーバーライドできるので コード上p[-3][-4]でアクセスする事自体は簡単にできます。 >※6行目はコンパイルは通りますが実行時に不正なポインタ演算エラーが発生します。( int **q q[-3] = p[-3] + 4; を p[-3] = p[-3] + 4; とでもしたのではないですか? そうするとnewしたポインタの位置が書き換わってしまうので、deleteが失敗します。

lachesis-r
質問者

補足

No.4で補足しました。 まず「qが配列へのポインタであって、qに対する添字に-3が使用できること」の条件が満たせていないようです。

全文を見る
すると、全ての回答が全文表示されます。
  • Interest
  • ベストアンサー率31% (207/659)
回答No.6

ANo.1 です。 本音は、「職人芸的な技に感動したので自分も使ってみたかった」ということなのですね。これはあくまで私の考えですが、もう職人芸的プログラムを書く人の時代ではないと思います。職人芸より、他人が読んでさっと理解できる、誤解されないプログラムがよいプログラムなのだと。 言語仕様からすると文法的に間違いでなくても、普通の人がやらないようなことをやるのは、バグを自ら埋め込むことに近く、危険な行為ではないでしょうか。 > ある種の処理(フィルタ)では配列の外側が仮想的にあると非常にシンプルに記述できます。 > クラスにして添え字をずらすとオーバーヘッドが生じます(多分)ので、何千万回も処理する場合には効いてきます。 処理速度を上げたいのであれば、まずは最大のボトルネックを探し出し、必要とあらばアルゴリズムを替えるのが王道だと思います。添え字をずらす程度の処理は、コンパイラの最適化オプションで吸収されてしまうのではないでしょうか。そういうわけで、技巧に走らず、素直に実装なさることをお勧めします。

lachesis-r
質問者

補足

仰るとおり趣味の領域なのかもしれません。 私はc++builderしか使えないので、他の環境ではなんとも言えませんが、builderのコンパイラ、pentiumの命令スケジューリング、どちらも極めて優秀で、大抵は自分で最適化したつもりでもあまり早くなりません。 但し今回のケースでは確実に速度の改善が見られるようです。 フィルタ処理がほとんどなので配列の参照が多く配列の外側を参照するかどうかのチェックはオーバーヘッドになります。 クラスにして内部でずらすと早くなりますが、それでも下記のテクニックよりはかなり遅いです。(試しました) 実際にはフィルタ処理を早くさせるアルゴリズムは見つけてあるのですが、こちらの方は難解でデバッグが大変なので、使わないようにしているのです。 仮想的にアドレスをずらすだけなら、枠組みを用意するだけですし、枠組みの設計段階でデバッグをきちんと行えば後は楽です。

全文を見る
すると、全ての回答が全文表示されます。
noname#30727
noname#30727
回答No.5

ポインタへのポインタを使うという条件は満たせないですが、オーバーヘッドを気にするなら、ポインタテーブルが無い方が若干有利かな。 自分で言うのもなんですが、怪しいコードですね(笑 int (*a)[18] = new int[12][18]; a[0][0] = 1; int (*p)[18] = reinterpret_cast<int(*)[18]>(&a[3][4]); p[-3][-4] = 99; std::cout << a[0][0] << std::endl; delete[] a;

lachesis-r
質問者

お礼

回答ありがとうございます。 動作確認しました^^ すごいです。 恥ずかしながらreinterpret_castというのは初めて見ました。 まだまだ研鑽が足りません。 このテクニックは、2次元配列(に見える1次元配列)が隙間無く並んでいる事を利用してるんですよね? 2次元配列から1次元配列にアドレス変換するときに乗算が発生するのでテーブルの方が早いと思いますがいかかでしょうか? (以前試してみたことがあります。幅が2^nで無い場合にはやや遅くなったと思います)

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.4

#2回答者です。ううっ恥かしい・・・ 指摘のとおり、「p = a - 3」は「p = a + 3」の誤りです。 同様に q[-3] = p[-3] - 4; も q[-3] = p[-3] + 4; の誤り。 なお、後者はqに関して「qが配列へのポインタであって、qに対する添字に-3が使用できること」、つまりpと同じ性質が必要です。

lachesis-r
質問者

お礼

補足ありがとうございます。 「qが配列へのポインタであって、qに対する添字に-3が使用できること」の部分がよくわかっていないようです(汗 int **q; と用意して、 q[-3] = p[-3] + 4; としてもダメなのですね。 qも領域を確保しないとまずいのでしょうか。

全文を見る
すると、全ての回答が全文表示されます。
  • xcrOSgS2wY
  • ベストアンサー率50% (1006/1985)
回答No.2

一般にp[x]と*(p + x)は同じものの違う書き方に過ぎませんので、p[-3]とa[0]が同じものを指すようにするには p = a - 3; としておけば済みます。 さて、既にp[-3]とa[0]が同じものを指すようにはできたのですよね。つまり、p[-3][0]とa[0][0]も同じものを指すように、です。 このとき、q[-3][-4]とp[-3][0]が同じものを指すようにするには、最初の例を適用して q[-3] = p[-3] - 4; としておけばよいことになります。 つまり、pと同じ構造の配列をもう1つ用意し、そのそれぞれの要素として格納するポインタの値をずらすわけです。

lachesis-r
質問者

補足

早速の回答ありがとうございます。 ※2行目は p=a+3 ですね? ※6行目はコンパイルは通りますが実行時に不正なポインタ演算エラーが発生します。(c++builder使用) 参照するポインタのずらし方として正しいものはありませんか?

全文を見る
すると、全ての回答が全文表示されます。
  • Interest
  • ベストアンサー率31% (207/659)
回答No.1

ポインタの仕組みはご存知の上での質問と思いますが、なぜわざわざそのような危険なことをしたいのでしょうか? new, delete をお使いのようですが、C++ を想定されているのですか? C++ならば、クラスを作って get(x,y), set(x,y) のようなアクセス用メンバ関数を用意し、関数の中で配列にアクセスする数字を修正するという手はありそうですね。 とにかく、なぜそのようなことをしたいのか教えてください。

lachesis-r
質問者

補足

奥村晴彦著「C言語による最新アルゴリズム事典」で1次元の配列に巧妙にp[-5]のようにアクセスしていますので、イリーガルというわけではないのだと思います。 (私のようにポインタが不確かなまま使うのはリスキーですが) ある種の処理(フィルタ)では配列の外側が仮想的にあると非常にシンプルに記述できます。 クラスにして添え字をずらすとオーバーヘッドが生じます(多分)ので、何千万回も処理する場合には効いてきます。 (本当は上記アルゴリズム事典を見て感動したからなんですが)

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 初心者です。 配列のエラーがどうしても解決できません。 誰か助けてください・・・

    魔方陣のプログラムを考えて書いてみましたが、 エラーが出てしまい実行することができません。 class mahoujin{ public static void main(String args[]){ int n=3; int a[][] = new int[3][3]; int x=0; int y=1; for(int p=0;p<=3;p++){ for(int q=0;q<=3;q++){ a[p][q]=0;} } for(int i=1;i<=n*n;i++){ if((i%n)==1){x++; }else{x--; y++;} if(x==0){x=3;} if(y==3){y=0;} a[x][y]=i;} } } 空の配列や配列を外れるものがあるかをよく考えてみましたが、どうしても解決できません。助けてください・・・

  • ポインタ配列の開放について

    いつもお世話になっております。 C++言語初心者です。 ポインタ配列の開放(delete)について質問です。 ※includeは省略します。 int main(){   int *a[10];   for(int i=0;i<10;i++){     a[i]=new int[5];   }   delete[] *a;   return 0; } ポインタ配列を開放する場合、 上記のような書き方で正しいのでしょうか? ただ、上記のような記述方法が間違っている場合、 for(int i=0;i<10;i++){   delete[] a[i]; } とやるのはスマートでない気がするので、 もし他に方法がありましたらお願いします。

  • 多次元配列の new

    多次元配列を new すると、どのような型のサイズの領域の配列が確保されるんでしょうか?たとえば、  int (*a)[2] = new int[3][2]; とすると、  1. 長さ2のintの配列へのポインタ型の長さ3の配列の領域が確保される のか、  2. int[3][2] すなわち、int が 6 つ分の領域が確保される のか。 今まで、「そりゃあ 2 の方だろう」と信じ込んであまり考えずにいたんですが、「コードの型形式からすると 1 の方の解釈でもいいよなぁ」と、ふと思ったものですから、質問させていただきました。 わたしの環境で調べてみると(配列用のハウスキーピング的な余分の領域とか、パディングなどは無視して)、確かに 1 の方なんですか、これで標準準拠なんでしょうかね?^^; XP Home Edition Ver.2002 SP2 cygwin v.1.0.2-1 GNU g++ v.4.1.1 ===== #include <iostream> #include <new> #include <cstdlib> struct A { char a; void *operator new(std::size_t s) { void *p = std::malloc(s); std::cout << "A::new(): " << p << '\t' << s << '\n'; return p; } void operator delete(void *p, std::size_t s) { std::cout << "A::delete(): " << p << '\t' << s << '\n'; if (p) std::free(p); } void *operator new[](std::size_t s) { void *p = std::malloc(s); std::cout << "A::new[](): " << p << '\t' << s << '\n'; return p; } void operator delete[](void *p, std::size_t s) { std::cout << "A::delete[](): " << p << '\t' << s << '\n'; if (p) std::free(p); } }; int main() { std::cout << sizeof(char) << '\t' << sizeof(A) << '\t' << sizeof(A(*)[8]) << '\n'; A *a = new A; std::cout << a << '\n'; A *aa = new A[8]; std::cout << aa << '\n'; A (*aaa)[8] = new A[8][8]; std::cout << aaa << '\n'; A (*aaaa)[8][8] = new A[8][8][8]; std::cout << aaaa << '\n'; delete[] aaaa; delete[] aaa; delete[] aa; delete a; } ===== % ./a.exe 1 1 4 A::new(): 0x870668 1 0x870668 A::new[](): 0x870678 12 0x87067c A::new[](): 0x870688 68 0x87068c A::new[](): 0x8706d0 516 0x8706d4 A::delete[](): 0x8706d0 516 A::delete[](): 0x870688 68 A::delete[](): 0x870678 12 A::delete(): 0x870668 1

  • newで生成したものをdelete[]で破棄するのは間違い?

    int* p = new int(0); と確保したものを、普通は delete p; と書いて破棄しますが、代わりに delete[] p; と書いて破棄しても問題はないのでしょうか? 非常に悪いコードなのですが..... <1>: int* p = new int(0); <2>: int* p = new int[x]; //xはどこかで値を設定済み このうちの、1か2かのどちらかでpに対して領域を割り付けた場合に、どちらもdelete[]で破棄しても問題ないか? という意味の質問です。 コンパイルして実行しても特にエラーを吐くことはありませんでしたが非常に心配です。

  • オブジェクトのコピー

    以下のプログラムはVC++6.0(win2k上)で、 オブジェクトのコピーを練習するために書いたものです。 このプログラムは、コンパイルは通りますが、 実行エラーになります。どのように変更すればよいでしょうか? #include <iostream> #include <stdio.h> #include <assert.h> using namespace std; class Player{ int data; Player *p; public: Player(); ~Player(); Player(const Player & x); void SetData(int d){ data = d; } int GetData(){ return data; } //代入演算子 Player & operator=(const Player & x); }; Player & Player::operator = (const Player & x){ p = new Player; //Playerオブジェクトを別の場所に作る *p = *(x.p); //pの指すオブジェクトに、mのpが指すオブジェクトを代入 return *this; } Player::Player(const Player& x){ p = new Player; //Playerオブジェクトを別の場所に作る *p = *(x.p); //pの指すオブジェクトに、mのpが指すオブジェクトを代入 } class App { Player *p[3]; public: App(); ~App(){for(int i=0;i<3;i++)delete p[i];} //pの指すオブジェクトのデータを設定するだけ void SetData(int i1,int i2){ p[i1]->SetData(i2); } void init(){p[0]=new Player;p[1]=new Player;p[2]=new Player;} void copy(){p[0]=p[1];SetData(0,100);} void output(){ for(int i=0;i<3;i++)printf("%d\n",p[i]->GetData()); } }; void main() { App *x=new App; x->init(); for(int i=0;i<3;i++)x->SetData(i,i); x->copy(); x->output(); delete x; }

  • C言語のポインタについて教えてください。

    C言語のポインタについて教えてください。 ・pointer1.c  int main(){   int a;   int *p;   p = &a;     a = 123;   printf("%d", *p);   return 0;  } ・pointer2.c   int main(){ int a[100]; int *p; p = &a[0]; int i; for(i = 0; i < 100; i++) a[i] = i; for(i = 0; i < 100; i++) printf("%d", *p++); return 0; } と二つのソースコードがあるとき、pointer2.cの「p = &a[0]」をpointer1.cのように「p = &a」と書けないのはなぜですか?  また、「&a」は動かすことのできなく、「aを指し示す*p」は動かすことができる変数のようなもの、という認識に誤りはないでしょうか?  宜しくお願いします。

  • NoSuchMethodErrorが解決できません。

    実行時エラーNoSuchMethodErrorが出て困っています。 どこを修正すればいいのでしょうか? class A implements Runnable{ int x; int y; public void run(){ for(int i = 0;i < 100;i++){ x++; y++; System.out.println("x="+x+"y="+y); } } } class B{ public static void main(String args[]){ new Thread(new A()).start(); new Thread(new A()).start(); } }

    • ベストアンサー
    • Java
  • fprintfでの文字化け

    Cで作ったプログラムなのですが最後の部分でファイルに出力すると数字が 文字化けして出てきます(‰など)その原因を教えて頂ければ嬉しいです 他にも何かあれば教えてください プログラミングは詳しくないのでゴロゴロ見つかるかもしれません 【プログラム】 #include <stdio.h> #include <math.h> #include <stdlib.h> #include <time.h> int a,i,j,k,t; double p,p1,b; int X[999][1000],Y[999][1000]; int s0,s1,delta; int main(void) { int**X = calloc(sizeof(int),sizeof(int)*1000); int**Y = calloc(sizeof(int),sizeof(int)*1000); FILE *output; output=fopen("monte.dat","w"); b = 0.01; /*逆温度*/ srand((unsigned int)time(0)); /*メモリの確保*/ if( X == NULL ){ exit( EXIT_FAILURE ); } for(i=0; i<=999; ++i){ /* 各列分の領域を割り当てる */ X[i] = (int*)calloc(sizeof(int),sizeof(int)*1000); } if( Y == NULL ){ exit( EXIT_FAILURE ); } for(i=0; i<=999; ++i){ /* 各列分の領域を割り当てる */ Y[i] = (int*)calloc(sizeof(int),sizeof(int)*1000); } /*終わり*/ /*初期配列の設定*/ for(i=0;i<1000;i++){ X[0][i]=a; a = (int)((rand() / ((double)RAND_MAX+1.0)) * 2);//debag } /*終わり*/ for(t=0;t<2;t++){ //debag /*配列中a番目を抽出*/ a = 10; //debag /*終わり*/ /*a番目のスピンを逆にした配列作成*/ for(j=0;j<1000;j++){ Y[t][j] = X[t][j]; } Y[t][a] = (X[t][a]+1)%2; /*終わり*/ /*遷移確率p1計算*/ s0=0; s1=0; for(k=0;k<1000;k++){ s0=s0+pow(-1,X[t][k]+X[t][k+1]);//(11),(00)なら値1 s1=s1+pow(-1,Y[t][k]+Y[t][k+1]);//(10),(01)なら値-1 } delta = -s1 + s0; p1 = 0.5 * (1 - tanh(0.5 * b * delta)); printf("%d %d %d %f ",s0,s1,delta,p1); //←この時点ではX[t][]は正しく出力する /*終わり*/ /*新しい配列(i番目の符号を交換するか)*/ p = (double)((rand() / ((double)RAND_MAX+1.0)) * 1); for(j=0;j<1000;j++){ X[t+1][j] = X[t][j]; } if(p<=p1){ X[t+1][a] = (X[t][a]+1)%2; printf("交換したよ! %d → %d\n",X[t][a],X[t+1][a]); } else{ X[t+1][a] = X[t][a]; printf("交換しないよ!\n"); } /*終わり*/ } /*記入*/ for(i=0;i<1000;i++){ fprintf(output,"%d ",X[0][i]); //←ここが文字化けする } fprintf(output,"\n"); for(i=0;i<1000;i++){ fprintf(output,"%d ",Y[0][i]); //←出力されない } /*終わり*/ fclose(output); return 0; } 【プログラム終】

  • C++で領域の確保の方法

    今C++の勉強中なのですが、 領域の確保の方法でいい方法が知りたいのです。 ポインターのポインターを使って二次元配列の領域を確保したいのですがいい方法が思いつきません。 int **pBox; pBox = new int *[ 10 ]; for( int i=0; i<10; i++ ) { pBox[ i ] = new int[10]; } //ちなみに今はこんな感じのものしか考え付きませんint型[10][10] を確保したつもりです。 間違っていたら教えていただきたいです。 本題はこちらで、もっと効率のいい確保の方法を知りたいのでご協力を よろしくお願いします。

  • ポインタ配列

    "one","two","three","four","five","six","seven","eight","nine","ten" のポインタ配列の文字列を、ASCIIコード順に並べ変えようと思ったのですが、 もうどこが間違っているかさえわからないぐらいになってしまいました。 まだまだはじめたばかりなもので、わからないことだらけなんで、 できるだけわかりやすい説明おねがいします。 関数の引数に問題があるのじゃないかと思ったのですが、 何かいいアドバイスありましたら、お願いします。 #include <stdio.h> /* 関数のプロトタイプ宣言 */ int strmp(char *,char *); void cpy(char *,char *); int main (void) { /* ポインタ配列の定義 */ char *x[10]={"oneee","twooo","three","fourr","fivee","sixxx","seven","eight","ninee","tennn"}; /* ポインタのポインタの定義 */ char **pp=x; char k[100]; char *p=k; int i,t,a,b,c,d; a=0; /* ポインタ配列を自作関数を使って、ASCIIコードの大きいほうからに並び替える */ for(i=0;i<9;i++) { for(t=1;t<10;t++) { a=strmp(*(pp+i),*(pp+t)); if(a<0) { cpy(p,*(pp+i) ); cpy(*(pp+i),*(pp+t) ); cpy(*(pp+t),p); } } } for(i=0;i<10;i++) { printf("%s ,",x[i]); } printf("\n"); return 0; } /* 文字の比較をする関数 */ int strmp(char *x,char *y) { int i; for(i=0;*(x+i)==*(y+i);i++) { if( *(x+i)=='\0') { return 0; } } return *(x+i)-*(y+i); } /* 文字をコピーする関数 */ void cpy(char *a,char *b) { int i; for(i=0;*(b+i)!='\0';i++) { *(a+i)=*(b+i); } *(a+i)='\0'; }