プロが教えるわが家の防犯対策術!

固定要素数の行列の処理ですが、subでセグメントエラーを起こしています。
アドレスを出力してみると、subでは元々確保したアドレスでは無いところを指しています。
呼び出し側では「行列の先頭のアドレス」を明示したつもりだったのですが、どこが間違っているのでしょうか。少し長いですが、ソースコードと出力を示します。
typedefのところとsubのIFは変更できないので、double[3][3]とdouble** のIFを合わせないといけないのですが、合わせ方がよくわかりません。
よろしくお願いします。

=========================================
#include <stdio.h>
#include <string.h>

typedef double Matrix[3][3];

void sub( const double** mat );

int main(void)
{

 int ret = 0;
 int i, j;

 Matrix mat = { { 0., 1., 2. },
     { 3., 4., 5. },
     { 6., 7., 8. } };
 
 for( i = 0; i < 3; i++ ){
  for( j = 0; j < 3; j++ ){
   printf( "main : mat[%d][%d] = %f\n", i, j, mat[i][j] );
   printf( "main : &mat[%d][%d] = %p\n", i, j, &mat[i][j] );
  }
 }
 printf( "\n" );

 sub( &mat[0][0] );

 return ret;
}

void sub( const double** mat )
{
 int i, j;
 printf("---- &mat = %p\n", &mat );
 for( i = 0; i < 3; i++ ){
  for( j = 0; j < 3; j++ ){
   printf( "sub : mat[%d][%d] = %f\n", i, j, mat[i][j] );
   printf( "sub : &mat[%d][%d] = %p\n", i, j, &mat[i][j] );
  }
 }
 printf( "\n" );
}

=========================================
main : mat[0][0] = 0.000000
main : &mat[0][0] = 0x7ffffca7bca0
main : mat[0][1] = 1.000000
main : &mat[0][1] = 0x7ffffca7bca8
main : mat[0][2] = 2.000000
main : &mat[0][2] = 0x7ffffca7bcb0
main : mat[1][0] = 3.000000
main : &mat[1][0] = 0x7ffffca7bcb8
main : mat[1][1] = 4.000000
main : &mat[1][1] = 0x7ffffca7bcc0
main : mat[1][2] = 5.000000
main : &mat[1][2] = 0x7ffffca7bcc8
main : mat[2][0] = 6.000000
main : &mat[2][0] = 0x7ffffca7bcd0
main : mat[2][1] = 7.000000
main : &mat[2][1] = 0x7ffffca7bcd8
main : mat[2][2] = 8.000000
main : &mat[2][2] = 0x7ffffca7bce0

---- &mat = 0x7ffffca7bc68
セグメンテーション違反です

A 回答 (14件中1~10件)

別物なのでそのままでは合わせようがないです。

どうしてもというなら

const double *m[] = {mat[0], mat[1], mat[2]};

としたものを

sub(m);

で渡すしかないんじゃないか。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。

Illegal initialization というコンパイルエラー(Borland)が出ましたが、typedefしたものをラップすればよいという理解でよいですか。動くようにがんばってみます。

お礼日時:2011/01/02 14:31

ANo.8 の回答をしたものです。



「ANo.5 が正解」と書きましたが,場合によっては正解ではないかもしれません。
コンパイル時・実行時にエラーにならなくても,意味的に間違っている可能性はあります。

例えば,要素を格納する順番までは,引数の型だけでは分からないので。
列方向優先で格納することも比較的よくあります。

とにかく,
sub 関数がどういうデータを要求しているか,よく確認して下さい。
そして,それに合ったデータを用意してあげてください。

# 全要素のコピーが必要になるかも
    • good
    • 0
この回答へのお礼

何度もご回答、ありがとうございます。
既存の(自分が作ったものではない)関数を使う時は、おっしゃる通りの確認が必要ですね。間違えないように気をつけます。

お礼日時:2011/01/03 00:32

A No.6の者ですが、ちょっと間違っていたので補足です。



double (*mat)[3];

mat = (double (*)[3])mat_;

が正しいですね。Matrixにキャストしても意味が無い(--;

それから、呼び出し側もとりあえず、

sub( (const double **)mat );

で動きます。(gcc -Wall では)

キャストで逃げるのは邪道な気はしますが、事情があれば仕方ないですね。
    • good
    • 0
この回答へのお礼

何度もご回答、ありがとうございます。
こういう方法があるのですね。勉強になりました。

お礼日時:2011/01/03 00:29

> 以下のワーニングがでています(Borland)。



質問そのものへの回答は既に他の方が挙げられていますのでほぼ解決していると思いますが、この警告が「何を言っているか」は理解していますか?
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。
警告の内容は、「ポインタに変換した型が一致していない疑いあり」という感じでしょうか。sub内ではポインタのポインタとして引数を扱わないといけないのに、呼び出しで指定したポインタは、(単なる最初の要素へのポインタということで)シングルポインタになっているから合っていない、と言われているのかと理解しました。

お礼日時:2011/01/03 00:21

エラー? と思ったので gcc で確認してみた



Matrix mat = {{ 0., 1., 2. },
{ 3., 4., 5. },
{ 6., 7., 8. }};
double *m[] = {mat[0], mat[1], mat[2]};
として
sub(m);

エラーなしで一応動作するけど?

それから、私も既存ライブラリにインタフェース合すということは良くあるので、今回もそうだろうと思いましたが、そういう事は最初に書いておくべきでしたね。
    • good
    • 0
この回答へのお礼

ご回答、ありがとうございます。
そのままコピペさせていただきましたが、なぜか、Borlandではエラーが出ます…。
質問の仕方は、今後気をつけます。

お礼日時:2011/01/03 00:12

既存のコードとかライブラリを使うとかで,インターフェイスを変更できないこともありますよね。



その場合は,
要求に合ったデータを呼び出し側で作るしかないので,ANo.5 が正解だと思う。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
動くようになんとかがんばってみます。

お礼日時:2011/01/02 15:25

typedef は、新たな型宣言と同じだから、Matrixを渡すのに、double**は、間違い。



そもそも、**の解釈が正しくない。
Answer8の方が一番正解。

出題者の、意図を聞いてみたい。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
確かに、Matrixからdouble**へはそのままでは渡せないですね。大人の事情(No.7の方へのお礼に記載)のために悩んでいたところです。

お礼日時:2011/01/02 15:16

>呼び出し側では「行列の先頭のアドレス」を明示したつもりだったのですが、どこが間違っているのでしょうか。



 「間違っている」というより、せっかく typedef したのだから、const double** はないような。


 typedef const double Matrix[3][3];

 void sub( Matrix mat ); // プロトタイプ
  ・
  ・
   sub( mat ); // 関数呼び出し
  ・
  ・
 void sub( Matrix mat )  // 関数本体
  ・
でエラーは出ませんよ。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
おっしゃる通りで、ご回答の通りにしたいのですが、大人の事情(No.7の方へのお礼に記載
)でそういうわけにもいかなくなったのです。

お礼日時:2011/01/02 15:12

main では


sub((void *)mat);
のように void * に変換して逃げ, sub で
void sub( const double** mat_ )
{
Matrix *mat = (const void *)mat_;
/* 以下略 */
とするかなぁ.... そもそも「subのIFは変更できない」という条件がなぜ付いているのか理解できないのだが.
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
voidポインタってこういう時に威力を発揮するのですね!
今回の問題は、typedefの方は相手の承認を得てしまっているのでもう変更できない、subの方は既存の実績ある関数で、これをそのまま使おうという方針になったことが発端なのです。

お礼日時:2011/01/02 15:05

double ** は、double * へのポインタなので、


double * の指す先に何が入っているのか、コンパイラには
判断がつきません。

今回の場合は、double A[3][3]; と、サイズが分かっているので、
以下の様に、配列サイズを教えてあげる必要があります。

void sub( const double** mat_)
{
int i, j;
double (*mat)[3];

mat = (Matrix)mat_;
printf("---- &mat = %p\n", &mat );
...

みたいな感じかな。
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
最初の[]以外の配列サイズは教えてあげる必要があることは理解しました。

mat = (Matrix)mat_;

のところで、Incompatible type conversion とエラーが出た(Borland)のですが、なんとか動くようにがんばってみます。

お礼日時:2011/01/02 14:41

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!