1

このおもちゃのコード例では:

int MAX = 5;

void fillArray(int** someArray, int* blah) {
  int i;
  for (i=0; i<MAX; i++)
    (*someArray)[i] = blah[i];  // segfault happens here
}

int main() {
  int someArray[MAX];
  int blah[] = {1, 2, 3, 4, 5};

  fillArray(&someArray, blah);

  return 0;
}

...配列someArrayを埋めて、関数の外部で変更を保持したいと思います。

これは非常に大きな宿題の一部であり、この質問は私が解決策をコピーすることを許可せずに問題に対処します。int **をパラメーターとして受け入れる関数シグネチャーが与えられ、その配列を満たすロジックをコーディングすることになっています。fillArray()関数内で&someArrayを逆参照すると、必要な配列(最初の要素へのポインター)が得られ、その配列で括弧で囲まれた配列要素にアクセスすると、割り当てる必要のある必要な位置が得られるという印象を受けました。 。ただし、なぜセグメンテーション違反が発生するのか理解できません。

どうもありがとう!

4

3 に答える 3

3

配列someArrayを埋めて、関数の外部で変更を保持したいと思います。

配列が最初の要素へのポインターに減衰するときに、配列を関数に渡すだけです。

void fillArray(int* someArray, int* blah) {
    int i;
    for (i=0; i<MAX; i++)
        someArray[i] = blah[i]; 
}

呼び出されます:

fillArray(someArray, blah);

要素への変更は、関数の外部に表示されます。

実際のコードが配列を割り当てる場合は、fillArray()次のint**ようになります。

void fillArray(int** someArray, int* blah) {
    int i;
    *someArray = malloc(sizeof(int) * MAX);
    if (*someArray)
    {
        for (i=0; i<MAX; i++)  /* or memcpy() instead of loop */
            (*someArray)[i] = blah[i];
    }
}

呼び出されます:

int* someArray = NULL;
fillArray(&someArray, blah);
free(someArray);
于 2012-12-15T23:26:53.990 に答える
1

int myArray [10] [20]などの配列を作成すると、保証された連続したメモリブロックがスタックから割り当てられ、通常の配列演算を使用して配列内の任意の要素が検索されます。

その3D「配列」をヒープから割り当てたい場合は、malloc()を使用してメモリを取り戻します。その記憶は「ばかげている」。これは単なるメモリのチャンクであり、ベクトルと見なす必要があります。配列に付随するナビゲーションロジックには付属していません。つまり、目的の3D配列をナビゲートする別の方法を見つける必要があります。

malloc()を呼び出すとポインターが返されるため、最初に必要な変数は、実際の整数データIEを保持する必要があるint*のベクトルを保持するためのポインターです。

int * pArray;

...しかし、これはまだ整数を格納したいストレージではありません。あなたが持っているのは、現在何も指していないポインタの配列です。データのストレージを取得するには、malloc()を10回呼び出す必要があります。各malloc()は、呼び出しごとに20個の整数にスペースを割り当て、その戻りポインターはポインターの*pArrayベクトルに格納されます。この意味は

int * pArray

に変更する必要があります

int ** pArray

ポインタのベクトルのベースへのポインタであることを正しく示すため。

最初の間接参照*pArray[i]は、intポインターの配列内のどこかに到達し、2番目の間接参照* p [i] [j]は、intポインターの配列内のどこかに到達します。 pArray[i]。

IE:ヒープ全体に散在する整数ベクトルのクラウドがあり、それらの位置を追跡するポインターの配列によって示されます。スタックから静的に割り当てられたArray[10][20]とはまったく異なります。これはすべて連続したストレージであり、どこにも単一のポインターがありません。

他の人が理解していなかったように、ポインタベースのヒープメソッドは一見したところあまり効果がないように見えますが、非常に優れていることがわかります。

まず第一に、free()またはrealloc()を使用して、いつでもヒープメモリのサイズを変更でき、関数が戻ったときにスコープ外になることはありません。さらに重要なことに、経験豊富なCコーダーは、可能な場合はベクトルを操作するように関数を配置します。この場合、関数呼び出しで1レベルの間接参照が削除されます。最後に、使用可能なメモリに比べて大きなアレイの場合、特に大規模な共有マシンでは、連続したメモリの大きなチャンクは使用できないことが多く、動作にメモリを必要とする他のプログラムには適していません。スタックに割り当てられた大きな静的配列を持つコードは、メンテナンスの悪夢です。

ここで、テーブルは、ベクトル操作から返されたベクトルポインターを収集するシェルであり、興味深いことはすべてベクトルレベルまたは要素レベルで発生することがわかります。この特定のケースでは、VecRand()のベクトルコードはcalloc()自身のストレージを呼び出し、calloc()のリターンポインタをTblRand()に返しますが、TblRandにはVecRand()のストレージを割り当てる柔軟性もあります。 VecRand()へのNULL引数をcalloc()への呼び出しに置き換えるだけです

/*-------------------------------------------------------------------------------------*/
dbl **TblRand(dbl **TblPtr, int rows, int cols)
{
    int  i=0;

    if ( NULL == TblPtr ){
        if (NULL == (TblPtr=(dbl **)calloc(rows, sizeof(dbl*)))) 
            printf("\nCalloc for pointer array in TblRand failed");
    }
    for (; i!=rows; i++){
        TblPtr[i] = VecRand(NULL, cols);
    }
    return TblPtr;
}
/*-------------------------------------------------------------------------------------*/

dbl *VecRand(dbl *VecPtr, int cols)
{
    if ( NULL == VecPtr ){
        if (NULL == (VecPtr=(dbl *)calloc(cols, sizeof(dbl)))) 
            printf("\nCalloc for random number vector in VecRand failed");
    }

    Randx = GenRand(VecPtr, cols, Randx);
    return VecPtr;
}
     /*--------------------------------------------------------------------------------------*/

static long GenRand(dbl *VecPtr, int cols, long RandSeed)
{
    dbl  r=0, Denom=2147483647.0;

    while ( cols-- )
    {
        RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
        r       = sqrt(-2.0 * log((dbl)(RandSeed/Denom)));
        RandSeed= (314159269 * RandSeed) & 0x7FFFFFFF;
        *VecPtr = r * sin(TWOPI * (dbl)(RandSeed/Denom));
        VecPtr++;
    }
    return RandSeed;
}
于 2012-12-16T01:57:35.847 に答える
0

「配列/ポインタ」の同等性はなく、配列とポインタは大きく異なります。それらを混同しないでください。配列someArrayです。は配列へのポインタであり、型はです。この関数は、ポインタへのポインタを取ります。つまり、メモリ内のどこかにあるポインタ変数を指す必要があります。コードのどこにもポインタ変数はありません。それはおそらく何を指しているのでしょうか?&someArrayint (*)[MAX]int **

配列値は、特定の式の最初の要素のポインター右辺値に暗黙的に低下する可能性があります。アドレス()を取得するような左辺値を必要とするものは、明らかにこのようには機能しません。配列型とポインタ型の違いは次のとおりです。&

  • 配列型を割り当てたり渡したりすることはできません。ポインタタイプは
  • 配列へのポインタとポインタへのポインタは異なるタイプです
  • 配列の配列とポインタの配列は異なるタイプです
  • 配列型のsizeofは、コンポーネント型の長さとサイズの積です。ポインタのsizeofサイズはちょうどポインタのサイズです
于 2012-12-16T00:21:50.383 に答える