2016-10-03 3 views
1

ダイナミック配列のサイズを変更し、一度にそれを埋めることができる関数を書こうと思っていました。私は(...ので、私がやったので、それが動作します)私は、「reallocの」を使用してそれを行う必要があることを知っているが、私の最初の試みは、このように見えた:関数本体「プリントアレイ(dArray、NewSizeパラメータ)でmallocとmemcpyを使った動的な配列のサイズの変更

void ChangeDynamicArraySize(int* dArray, int oldSize, int newSize){ 

    int* tempArray = (int*) malloc(sizeof(int) * oldSize); 
    CopyArray(tempArray, dArray, oldSize); 
    free(dArray); 
    dArray = (int*) malloc(sizeof(int) * newSize); 
    CopyArray(dArray, tempArray, oldSize); 

    for (int i = oldSize; i < newSize; i++){ 
     scanf("%i", &dArray[i]); 
    } 
    PrintArray(dArray, newSize); 
    free(tempArray); 
} 

; "正しい。メインから呼び出された場合 は、しかし、()、それは次のような結果を与える: - 17891602 - 17891602 - 17891602 - 17891602

dArrayが解放されたようなので、それが見えますか...?しかし、私は割り当てられたmemmoryが自動的に関数を終了した後に解放されないことを知っている。

次に、理由は何でしょうか?

+0

A CopyArrayはmemcpyのちょうど私のバージョンです – WJuz

+3

'dArray'は値渡しで、ローカルコピーを変更しています。 – deniss

答えて

2

Cでは、関数のパラメータはローカルにコピーされます。 dArrayの値が(*dArray)を指している場合は変更されますが、パラメータとして渡されたdArrayの(アドレスの)変更は、コピーであるためこの関数のローカルのみです。

あなたの配列のアドレス(あなたのメインには&array、関数プロトタイプにはdArray**)を渡して、代わりにポインタを変更したいかもしれません。

このような何か:

void ChangeDynamicArraySize(int** dArray, int oldSize, int newSize){ 

    int* tempArray = (int*) malloc(sizeof(int) * oldSize); 
    CopyArray(tempArray, *dArray, oldSize); 
    free(*dArray); 
    *dArray = (int*) malloc(sizeof(int) * newSize); 
    CopyArray(*dArray, tempArray, oldSize); 

    for (int i = oldSize; i < newSize; i++){ 
     scanf("%i", dArray[i]); 
    } 
    PrintArray(*dArray, newSize); 
    free(tempArray); 
} 

また、あなたもちょうど(あなたの関数ではなく、価値のないこのint*を返す作る)新しいmallocエド配列のアドレスを返すことがあります。

また、良い方法ではnot cast the return of mallocを使用し、失敗したかどうか、POSIX APIを使用している場合はchanged ERRNOを確認することができます。

+0

A、ok ...ありがとう:) – WJuz

+0

これを試しましたが、scanf( "%i"、dArray [i])がアクセス違反の書き込み場所0xccccccccを発生しました。 – WJuz

+0

しかし、その1つ:scanf( "%i"、&(* dArray)[i])はうまくいくようです;)今は動作しています。 – WJuz

1

ブロックスコープを持つdArrayにmallocによって割り当てられた新しいメモリを割り当てています。このポインターを呼び出し関数に戻す必要があります。 dArrayは渡されたポインタのコピーで、呼び出し元の関数に戻ると、元のポインタは変更されません。あなたのような関数呼び出している必要がありますdArrayので

ptr = ChangeDynamicArraySize(ptr, oldSize, newSize); 

を使用すると、関数の外に見える*dArrayの値を変更するときに値を変更しているので、関数呼び出しで渡されたポインタのコピーです元のポインタとコピーの両方によって指し示されるメモリ位置に格納される。しかし、関数内にdArrayポインターを再割り当てすると、このポインターが現在別の場所を指しているはずです。元の位置は元の位置を示します。

元の質問でのソリューションは、根本的な問題に苦しんでいる:あなたが関数にメモリのセクションにポインタを渡し、ポインタはメモリがmalloc()またはcalloc()またはrealloc()を使用していることを再割り当てする場合、新しいメモリが新しいアドレスを持っています。これは、realloc()であっても、要求されたメモリを割り当てるための十分な連続したバイトが古い場所にない可能性があるためです。元のソリューションは、ChangeDynamicArraySize()関数内のメモリを再割り当てし、このメモリの内容を変更します。しかし、リターン後、呼び出し関数は新しいメモリがどこにあるか分かりません。したがって、新しく割り当てられたメモリへのポインタを呼び出し側に返さなければなりません。

@Ditiは、ポインタのアドレスを配列の最初の要素に渡すことでこれを回避する代替の方法を提案しました。このポインタは、逆参照され、新しく割り当てられたメモリのアドレスの値が与えられます。このようにして、呼び出し側の関数は配列を呼び出すたびに、配列の最初の要素のアドレスを提供するポインタを介して呼び出しを行うため、呼び出す関数は賢明ではありません。きちんとしたしかし、私はまだ可能な限り明示的にポインタを渡すことを好むと思います。それは私には明らかです。

+0

hm、dArrayはポインタなので、ブロック内での操作は、変数の値を変更するなど、その外側のポインタにも影響します。 – WJuz

+1

Nope。関数の中では、コピーを使って作業しています。関数内で '* dArray'を変更すると、元のポインタとコピーの両方が指し示すメモリに格納されている値を変更しているので、関数の外に表示されます。しかし、関数内でポインターを再割り当てすると、他のポインターのコピーであったこのポインターが他のポインターを指し示すはずであるということになります。 –

+0

これで、ChangeSize関数本体でrealloc()を呼び出すと、realloc()がMainPointerとChangeSizePointerの両方で指し示されているメモリブロックを参照するため、効果がmain()私が正しいと思う...それはサイズだけでなく、場所を変えている。 – WJuz

関連する問題