2016-10-03 2 views
1

Ich wollte eine Funktion schreiben, die die Größe des dynamischen Array ändert und ermöglicht es dem Benutzer, es sofort zu füllen. Ich weiß, dass ich es bei der Verwendung von „realloc“ tun sollte (also tat ich und so funktioniert es ...), aber mein erster Versuch sah wie folgt aus:C dynamisch ändern Größe des Arrays mit malloc und 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); 
} 

In Funktionskörper „print (Darray, newSize) " hat richtig funktioniert. Aber wenn von der Haupt() aufgerufen es gibt ein Ergebnis wie: - 17891602 - 17891602 - 17891602 - 17891602

So sieht es aus wie Darray befreit wurde ...? Aber wie ich weiß, zugewiesene Speicher wird nicht automatisch nach dem Beenden der Funktion freigegeben.

Dann was könnte der Grund sein?

+0

A, und CopyArray ist nur meine Version von memcpy() – WJuz

+3

'dArray' wird von Wert übergeben und Sie ändern nur seine lokale Kopie. – deniss

Antwort

2

In C werden die Funktionsparameter lokal kopiert. Jede Änderung, die Sie am Wert dArray vornehmen, funktioniert (*dArray), aber jede Änderung, die Sie an der als Parameter übergebenen (Adresse von) dArray vornehmen, ist nur lokal für diese Funktion, da es sich um eine Kopie handelt.

Sie können die Adresse Ihres Arrays (eine &array in Ihrem Haupt, eine dArray** in Ihrem Funktionsprototyp) weitergeben und stattdessen Änderungen am Zeiger vornehmen.

Etwas wie folgt aus:

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); 
} 

Alternativ können Sie auch das Rück nur die Adresse des neuen malloc ed Array (was Ihre Funktion int* zurückkehren, anstatt keinen Wert).

Auch für gute Praktiken möchten Sie möglicherweise not cast the return of malloc, und überprüfen Sie, ob es fehlgeschlagen ist und changed ERRNO (wenn Sie die POSIX-API verwenden).

+0

A, ok ... Ich habe es, danke :) – WJuz

+0

Ich habe das versucht, aber scanf ("% i", dArray [i]) steigt Zugriffsverletzung Schreibort 0xcccccccc. – WJuz

+0

Aber das eine: scanf ("% i", & (* dArray) [i]) scheint in Ordnung zu sein;) Jetzt funktioniert es. – WJuz

1

Innerhalb der Funktion weisen Sie den neuen Speicher zu, der von malloc zugewiesen wurde, dArray, der den Blockbereich hat. Sie müssen diesen Zeiger an die aufrufende Funktion übergeben. dArray ist eine Kopie des übergebenen Zeigers, und wenn Sie zu der aufrufenden Funktion zurückkehren, ist der ursprüngliche Zeiger unverändert. Sie sollen einen Funktionsaufruf haben wie:

ptr = ChangeDynamicArraySize(ptr, oldSize, newSize); 

Seit dArray eine Kopie des in dem Funktionsaufruf übergebene Zeigers ist, wenn Sie den Wert von *dArray ändern, die sichtbar außerhalb der Funktion ist, weil Sie den Wert ändern gespeichert an der Speicherstelle, auf die sowohl der Originalzeiger als auch die Kopie zeigen. Aber wenn Sie den Zeiger dArray innerhalb der Funktion neu zuweisen, sagen Sie nur, dass dieser Zeiger jetzt auf eine andere Position zeigen sollte. Das Original zeigt immer noch auf den ursprünglichen Speicherort.

Die Lösung in der ursprünglichen Frage leidet an einem fundamentalen Problem: Wenn Sie einen Zeiger auf einen Abschnitt des Speichers an eine Funktion übergeben, und der Zeiger neu zuweist, dass der Speicher malloc() oder calloc() oder realloc() verwenden, der neue Speicher, der eine neue Adresse . Dies gilt sogar für , da möglicherweise nicht genügend zusammenhängende Bytes am alten Speicherort vorhanden sind, um den angeforderten Speicher zuzuordnen. Die ursprüngliche Lösung reserviert Speicher innerhalb der ChangeDynamicArraySize()-Funktion neu und ändert dann den Inhalt dieses Speichers. Aber nach der Rückkehr hat die aufrufende Funktion keine Ahnung, wo der neue Speicher ist. Sie müssen also dem Aufrufer einen Zeiger auf den neu zugewiesenen Speicher zurückgeben.

@Diti schlug eine alternative Lösung vor, um dies zu umgehen, indem die Adresse des Zeigers an das erste Element des Arrays übergeben wurde. Dieser Zeiger kann dereferenziert werden und den Wert der Adresse des neu zugewiesenen Speichers erhalten. Auf diese Weise ist die aufrufende Funktion nicht die klügere, weil, wann immer die aufrufende Funktion auf das Array zugreift, dies durch den Zeiger geschieht, der die Adresse des ersten Elements des Arrays bereitstellt. Ordentlich. Aber ich denke immer noch, dass ich es vorziehe, wenn immer möglich, die Hinweise explizit zu übergeben - es scheint mir klarer zu sein.

+0

Hm, dArray ist ein Zeiger, also dachte ich, dass die Operation, die im Block gemacht wurde, auch den Zeiger außerhalb davon beeinflussen würde - wie sich der Wert der Variablen ändert ... – WJuz

+1

Nein. Innerhalb der Funktion arbeiten Sie nur mit einer Kopie. Wenn Sie '* dArray' in der Funktion ändern, wird THAT außerhalb der Funktion sichtbar sein, da Sie den Wert ändern, der im Speicher gespeichert ist, auf den sowohl der Originalzeiger als auch die Kopie zeigen. Aber wenn Sie den Zeiger innerhalb der Funktion neu zuweisen, sagen Sie nur, dass dieser Zeiger, der eine Kopie eines anderen Zeigers war, jetzt woanders zeigen sollte. –

+0

Ok, jetzt verstehe ich, dass, wenn ich realloc() in meinem ChangeSize-Funktionskörper aufruft, der Effekt auch in main() sichtbar ist, weil realloc() auf den Speicherblock verweist, auf den sowohl mein MainPointer als auch ChangeSizePointer zeigt. Ich hoffe, ich habe Recht ... es ändert nur seine Größe, nicht den Ort. – WJuz