Array als Pointer übergeben



  • Hallo,

    Wir haben letze Woche in der Uni angefangen in C zu programmieren und am zweiten Blatt (Pointer) bin ich auf ein Problem gestoßen welches ich zwar lösen konnte, aber nicht zu meiner Zufriedenheit. Folgender Quellcode (ausschnitt) War gegeben:

    static int cnt = 0;
    
    void extend(int *arr, int *newarr) {
    	int i,j;
    	newarr = (int*) malloc(2 * cnt * sizeof(int*));
    	for (i=0,j=0; i < cnt; i++) {
    		newarr[j++] = arr[i];
    		newarr[j++] = arr[i];
    	}
    }
    
    int main(void) 
    {
            int arr[4], *zeros, i;
    	printf("How many integers (3 or 4)?\n");
    	scanf("%d", &cnt);
    
            int *newarr;
    	extend(arr, newarr);
    
    	for (i=0; i < cnt*2; i++) printf("%d ", newarr[i]);
    }
    

    Dieser Code speichert zwar in der Methode extend(..) die richtigen Werte in newarr, jedoch wenn ich diese in der Mainmethode Ausgeben will, kommt nur sinnloses Zeug heraus. Schreibe ich allerdings

    int *extend(int *arr, int *newarr)
    

    und in der Mainmethode dann:

    newarr = extend(arr, &newarr);
    

    So funktioniert es einwandfrei. Auch wenn ich beim ursprünglichen Code nur die Adresse übergebe kommt nur Wirres Zeug dabei raus. Kann mri einer Sagen woran das liegt? Oder muss ich zwangsläufig die Adresse zurückgeben?

    Danke schonmal



  • Lass dir doch mal vor und nach extend mal den Wert von dem Zeiger ausgeben:

    printf("arr: %p | newarr: %p\n", arr, newarr);
    

    Kannst du auch in extend vor und nach malloc machen.

    Bei deiner Lösung ist beim Aufruf das & zuviel.

    Du kannst auch die Adresse von newarr übergeben. Dann hast du in extend aber einen Doppelzeiger.

    void extend(int *arr, int **newarr) {
        int i,j;
        *newarr = (int*) malloc(2 * cnt * sizeof(int*));
        for (i=0,j=0; i < cnt; i++) {
            (*newarr)[j++] = arr[i];
            (*newarr)[j++] = arr[i];
        }
    }
    ....
    extend(arr, &newarr);
    

    Hast du schon die Funktion swap gemacht?

    void swap(int *a, int *b)
    {
     int temp = *a;
     *a = *b;
     *b = temp;
    }
    
    ...
    int x,y;
    swap(&x,&y);
    


  • newarr ist ein Pointer der irgendwohin zeigt (nicht definiert) und du übergibst diese Adresse. Bei der Übergabe wird sie kopiert, und in einer lokalen Varaible gespeichert. In "extend" überschreibst du dann diese Adresse mit einer von malloc zurückgegebenen Adresse. Allerdings speicherst du diesen Wert NUR in der lokalen newarr Variable, die in der main Methode wird nicht verändert. Deshalb zeigt die auch noch ins nirgendwo, und die Ausgabe gibt Mist aus.

    Du müsstest

    void extend(int *arr, int **newarr) { 
        int i,j; 
        *newarr = (int*) malloc(2 * cnt * sizeof(int*)); 
        for (i=0,j=0; i < cnt; i++) { 
            *newarr[j++] = arr[i]; 
            *newarr[j++] = arr[i]; 
        } 
    } 
    
    int main(void) 
    { 
        //...
        extend(arr, &newarr); 
    }
    

    verwenden. Dabei wird die Addresse der lokalen "newarr" Variable der main-Methode an die Funktion übergeben, und wenn du dann mit "*newarr=" veränderst worauf sie zeigt sieht man das logischerweise auch in der main-Methode.

    Allerdings ist es sinnvoller die Speicherverwaltung in die main-Methode zu packen, dann brauchst du keine Pointerpointer.



  • Also bei der Ausgabe der Pointer bekomme ich (mit dem ursprünglcihen Code):

    arr: 0x7fffa8e9b410 | newarr: 0x7fffa8e9b520
    extend
    arr: 0x7fffa8e9b410 | newarr: 0x7fffa8e9b520

    Also die Adressen sind noch gleich, d.h. malloc hat keinen Speicher alloziert?

    Während des Schreibens kam die Ausfürliche Antwort von DarkShadow44, danke dafür, das hat mir sehr weitergeholfen!

    @DirkB: Ja, die funktioniert ja, aber das ist ja auch kein Array, bzw der Erklärung vorher folgend: Ich lege ja keinen Speicher an (und verändere so die Adresse), sondern greife nur direkt auf die übergebene Adresse zu.(Gelesenes tutorial: http://openbook.galileocomputing.de/c_von_a_bis_z/012_c_zeiger_006.htm)

    Danke an alle für die schnelle Hilfe 🙂



  • Duck93 schrieb:

    Also die Adressen sind noch gleich, d.h. malloc hat keinen Speicher alloziert?

    Der Speicher wird alloziert, darum solltest du die Ausgabe ja auch noch in extend machen.

    In C werden als Funktionsparameter nur Kopien der Werte übergeben.1
    Willst du einen Wert ändern, musst du wissen wo er liegt. Darum übergibst du in so einem Fall die Adresse.

    Wenn du einen Zeiger ändern willst, musst du auch von dem Zeiger die Adresse übergeben.
    (Ein Zeiger ist eine Variable, die eine Adresse speichert)

    1Eine Ausnahme sind hier die Arrays.



  • OK, damit ich das jetzt richtig verstanden habe:
    Bei der ersten Lösung übergebe ich zwar den Zeiger, allerdings wird die Variable newarr nur lokal in der Funktion gesetzt und mit Hilfe der Zweiten Lösung ändere ich wirklich die Adresse auf die newarr zeigt?

    Hab mir nun auch mal die Ausgabe in der extend-Funktion angeschaut: ja, newarr verweist tatsächlich auf eine Andere Adresse.

    Werde mich dorthingehend wohl doch tiefer einarbeiten müssen (Java nimmt einem das durch explizite call by reference schon recht angenehm ab)

    Danke für die Hilfe, werde heute Nacht wohl noch ein paar Bücher wälzen.

    lg



  • Duck93 schrieb:

    OK, damit ich das jetzt richtig verstanden habe:
    Bei der ersten Lösung übergebe ich zwar den Zeiger, allerdings wird die Variable newarr nur lokal in der Funktion gesetzt und mit Hilfe der Zweiten Lösung ändere ich wirklich die Adresse auf die newarr zeigt?

    Ja.



  • Duck93 schrieb:

    Werde mich dorthingehend wohl doch tiefer einarbeiten müssen (Java nimmt einem das durch explizite call by reference schon recht angenehm ab)

    In Java gibt es kein Call-by-reference, auch kein "explizites". Deine Funktion, 1:1 nach Java übersetzt, sieht so aus:

    void extend(int[] arr, int[] newarr) {
       newarr = new int[2 * cnt];
       for (...) // Kopieren abschreiben schenk ich mir
    }
    

    und funktioniert genausowenig wie die C-Variante.


Log in to reply