0

これは関数のプロトタイプですsum。2つの任意の配列の要素を合計するために使用しています。

double **sum(double **A, double **B, int M, int N);

それらは両方ともダブルポインタとして渡され(理由は聞かないでください)、それぞれ配列の次元であると想定されていますMN

私が問題を抱えているのは、関数の実装内で、配列の要素にアクセスすることです。私はアレイを「延期」しようとしましたが(またはそう思います)、役に立ちませんでした。以下は私が試したことです:

> *A;  // Gives me an address, 0xf5c28f5c, not a number
> **A; // Error
> &A;  // Gives me the address of A

sumこれは、役立つ場合に配列を渡す方法です。

double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};

sum( (double **) a, (double **) b, 4, 4);

したがって、問題は、ポインタ/ダブルポインタによって渡されたときに、配列内の要素をどの程度正確に取得することになっているのかということです。

4

4 に答える 4

3

関数への配列の通過は完全に正しくありません。ダブルポインタは、ポインタからポインタへと考えるのが最善です。ポインタがメモリへのアドレスをどこかに保持する変数であるのと同じように、ポインタからポインタも同様のアドレスを保持します。それが参照するメモリは、別のポインタが占めるメモリです。これは、例で最もよく説明されています。

include <stdio.h>

int main(int argc, char* argv[])
{
    int a = 5;
    int *p = &a;
    int **pp = &p;
    printf("pp=%p, &p=%p, p=%p, &a=%p *p=%d\n", pp, &p, p, &a, *p);
    return 0;
}

私のMBA64ビットでは、これにより次のことがわかります。

pp=0x7fff50828bc8, &p=0x7fff50828bc8, p=0x7fff50828bd4, &a=0x7fff50828bd4 *p=5

それを把握すると、コードに問題が見つかると思います。最初の問題は、「a」と「b」のダブルポインターへのハードキャストです。多分代わりに彼らのアドレスを試してみてください。次に、関数の逆参照にこれらのポインターをどのように使用しているかを再検討する必要があります。これは、作業が必要になる可能性もあるためです。

于 2012-09-17T03:20:24.097 に答える
2

double**問題は、関数内のときから値を取得することではなく、それは些細なことです。問題は、ポインタのセットではなく配列を作成していることです。関数はこれを引数として受け入れることができません。引数を使用してキャストしようとすると(double**)、のAようにアクセスするとアクセス違反が発生します**

double** sum(double** A, int size)
{
  printf("First element: %f", A[0][0]); // Print the first element      
  printf("Last element: %f", A[size-1][size-1]); // Print the last element.
  return A;
}


const unsigned int SIZE = 4;
double** a = new double*[SIZE];
for(int i=0; i<SIZE; i++)
{
  a[i] = new double[SIZE];
}

a = sum(a, SIZE);

このようなポインタ(コンテナではなく、これらの状況を処理するために特別に設計されたもの)を使用する場合の最大の問題は、メモリ管理が手に負えなくなる可能性があることです。

for(int i=0; i<SIZE; i++)
{
  delete [] a[i]; // Free the inner array
}
delete [] a; // Free the outer array.
于 2012-09-17T04:08:24.270 に答える
1

関数がへのポインタを取り、double実際の配列から始める場合は、配列のアドレスのコピーを作成してから、そのアドレスへの参照を渡す必要があります。

double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};

double *aPtr = a;
double *bPtr = b;
sum(&aPtr, &bbtr, 4, 4);

関数で、sum参照を解除して配列に戻ります*A[0]

于 2012-09-17T02:43:48.667 に答える
1

明らかな解決策は、配列をダブルポインターとしてではなく、ポインターとして渡すことです。

double sum(double *A, double *B, int M, int N)
{
   double ret = 0.0;
   for (int i=0; i<M; i++) ret += A[i];
   for (int j=0; j<N; j++) ret += B[j];
   return ret;
}

double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
double s = sum( a, b, 4, 4);
printf("The sum is %f\n", s);

...それを行うのが最も簡単なことです。ただし、既存のAPIによって、ダブルポインターを使用する関数シグネチャに制約されている場合は、APIが、呼び出された関数が渡されたポインターを変更できるようにする必要があるためである可能性があります。ポインターからポインターへの受け渡しにより、呼び出された関数は、必要に応じて、ポインターからポインターへの書き込みを行うことができます。

double sum_and_change_pointers(double ** A, double ** B, int M, int N)
{
   // Compute sum
   double ret = 0.0;
   for (int i=0; i<M; i++) ret += (*A)[i];
   for (int j=0; j<N; j++) ret += (*B)[j];

   // And just for fun, modify the caller's pointer-values too
   static double some_other_array[5] = {0,0,0,0,0};
   *A = some_other_array;
   *B = some_other_array;

   return ret;
}

このようなシナリオでは、関数は次のように呼び出されます。

double a[] = {5.34, 5.23, 6.5, 3.51};
double b[] = {74.3, 42.1, 642.2, 54.2};
double * pa = a;  // copy address of arrays into pointers
double * pb = b;  // because changing the address of an array itself wouldn't work
printf("Before calling sum_and_change_pointers, pa=%p and pb=%p\n", pa, pb);
double s = sum_and_change_pointers( &pa, &pb, 4, 4);
printf("After calling sum_and_change_pointers, s=%f, pa=%p and pb=%p\n", s, pa, pb);

別の注意:投稿されたコードでは、関数がdoubleではなく(double **)を返します。それは簡単には機能しないと思います。まず、sumという名前の関数は、おそらくポインターからポインターではなく、倍精度浮動小数点値を返すので、(double **)を返すのは意味がありません...しかし(何らかの理由で)そのようにしたい場合でも、返されたポインタへのポインタがメモリ内の有効な場所を指していること(およびその場所が関数が戻ると関数のローカル変数がすべてなくなるため、関数内から行うのは難しいため、メモリ内の有効な場所も)。スレッドセーフを失うことを気にしないのであれば、静的変数またはグローバル変数でそれを行うことができると思います。

double ** sub (double ** A, double ** B, int M, int N)
{
   // Compute sum
   double ret = 0.0;
   for (int i=0; i<M; i++) ret += (*A)[i];
   for (int j=0; j<N; j++) ret += (*B)[j];

   static double result;
   result = ret;

   static double * pointerToResult;
   pointerToResult = &ret;
   return &pointerToResult;
}

[...]
double ** s = sum( a, b, 4, 4);
printf("Sum's result was %f\n", **s);

...しかし、繰り返しますが、これは醜く、安全ではなく、実際に行うのは役に立ちません。やりたい仕事に正しいタイプを使用する方がはるかに良いです。

于 2012-09-17T04:16:02.750 に答える