Mehrdimensionales Array variabler Länge in Funktion übergeben und verändern



  • Hallöchen,
    ich bin relativ neu in C und habe daher wenig Erfahrung. Ich versuche aber mein Bestes 😃

    Ich möchte für ein Programm eine Funktion schreiben, die als Argument u.a. eine Matrix (also ein zweidimensionales Array) double A[n][n] und deren (variable, vom User eingegebene) Länge int n haben soll.
    In dieser Funktion soll die Matrix A auch veränderbar sein, also zum Beispiel wird der Eintrag A[n-1][n-1] um 1 verringert.

    Das sieht dann bei mir etwa so aus (und der Compiler zeigt mir durchgehend Fehler an, das fett markierte ist das, wobei ich mir unsicher bin, wie man es schreibt):

    [code="c"]
    ...
    int funktion1(double A**, int n)
    {
    ...
    A[n-1][n-1] -= 1; //nur ein Beispiel
    ...
    }
    ...
    int main()
    {
    int n;
    ... //n wird vom User eingegeben
    double A[n][n];
    ... //Werte von A werden vom User eingegeben
    funktion1(
    &A[n][n]*, n);
    ...
    }
    [/code]

    Die Fehler sind meistens derart, dass entweder 'incompatible pointer type' angezeigt wird, oder die Matrix unverändert bleibt, obwohl die Funktion durchgelaufen ist.

    Daher meine Fragen:

    1. Was muss ich beim Definieren einer Funktion als Dateityp angeben? (ich habe dieses double** gefunden, aber weiß nicht, ob es stimmt)

    2. Was muss ich beim Aufrufen der Funktion schreiben? (&A, &A[n][n], A[n][n], A, &A** habe ich schon ausprobiert, der Compiler wollte aber nichts davon)

    3. Was muss ich während der Funktion schreiben, damit die Werte in die ursprüngliche Matrix verändert zurückgegeben werden, also z.B. nach Aufruf der Funktion funktion1 der Eintrag A[n-1][n-1] um eins verringert ist?

    Bitte versucht es auf nicht zu komplizierte Weise zu erklären 😃
    Danke,
    euer verweifelter Anfaenger 😃



  • *A[n-1][n-1] -= 1; //nur ein Beispiel
    

    Der * Operator ist hier falsch und wenn der "user" für n einen Wert kleiner 1 eingibt, dann hast du ein Problem 🙂

    funktion1(&A[n][n], n);
    

    Dein Problem hier ist, dass die Funktion ein pointer erwartet, aber ein array bekommt (nochnichtmal ein array &A[n][n] ist die Adresse eines Elements des arrays.
    Also:

    double **A;
    

    in der main und reserviere mit malloc dann n-entsprechend viele double's.
    Der Funktion übergibst du dann einfach A ohne das '&'
    Edit: was wie in Wutz Beispiel zu erkennen nicht effizient ist.





  • funktion1(&A[n][n], n);
    

    Du willst ein Zeiger auf ein Array von Arrays übergeben, also tu das auch:

    funktion1(A, n);
    

    Die Verwendung geschieht wie üblich, also nicht

    *A[n-1][n-1] -= 1;
    

    sondern

    A[n-1][n-1] -= 1;
    


  • Ein echtes 2D-Array ergibt keinen Doppelzeiger

    Bitmapper schrieb:

    &A[n][n] ist die Adresse eines Elements des arrays.

    Aber ein Element, dass gar nicht existiert, da n über der Grenze liegt



  • vielen Dank erstmal an alle 😃

    diese mysteriöse malloc-Funktion kannte ich noch nicht (bin wohl wirklich noch sehr unerfahren). Ich versuche es jetzt einmal und hoffe, ihr könnt mir sagen, ob es so richtig ist 😃

    ich bin inzwischen so weit:

    int funktion1(double** A, int n)
    {
      ...
      A[2][3] += 1; //Nur ein Beispiel (ich nehme außerdem 3<n an)
      ...
    }
    
    int main()
    {
      ...
      int n;
      ...
      double **A; //Definition der Matrix A
      A = (double **) malloc(n * n * sizeof(double));
      ...
      funktion1(A, n);
      ...
    }
    

    Ist es so richtig?
    Vielen Dank im Voraus,
    euer verweifelter Anfaenger 😃



  • Ich hatte eigentlich daran gedacht:

    for (i=0;i<n;i++)
        A[i] = malloc(n * sizeof(double));
    

    (nicht getestet)



  • -Hier stand müllus maximus-



  • roflo schrieb:

    Ist ja im Grunde das gleiche nur muss man dann auch entsprechend free()n.

    Nein, ist es nicht.

    Einmal hast du den einen Speicherbereich von malloc und einen Zeiger darauf.
    Das andere Mal ein Speicherbereich für Zeiger (Spalte) auf viele Speicherbereiche (Zeilen), alle mit malloc besorgt

    int spalten = n, zeilen = n;
    double **A; //Definition der Matrix A
    A = malloc(zeilen * sizeof(*double));
    for (i=0;i<n;i++)
        A[i] = malloc(spalten * sizeof(double));
    

    Was gefällt euch an dem Beispiel von wutz nicht?



  • DirkB schrieb:

    Einmal hast du den einen Speicherbereich von malloc und einen Zeiger darauf.
    Das andere Mal ein Speicherbereich für Zeiger (Spalte) auf viele Speicherbereiche (Zeilen), alle mit malloc besorgt

    Und welche Variante ist 'besser'? Wenn man das so sagen kann.

    DirkB schrieb:

    Was gefällt euch an dem Beispiel von wutz nicht?

    Ich verstehe es nicht ganz 😕

    1. muss es nicht sizeof(<irgendwas>) heißen?
    2. wie kann ich dann eine Matrix mit double-Einträgen daraus machen?
    3. wieso ist *speicher dann vom typ void?



  • A = (double **) malloc(n * n * sizeof(double));
    

    Wie DirkB gesagt hat, so sind es keine "2 Dimensionen"
    sizeof(irgendwas) ist die Größe des Datentyps und ein vielfaches davon wird mit malloc reserviert.
    Ein Zeiger vom Typ void enthält einfach eine Adresse, im Prinzip das selbe wie ein anderer Zeiger nur dass der compiler keinen Datentyp damit in Verbindung bringt.


  • Mod

    verweifelteranfaenger schrieb:

    1. muss es nicht sizeof(<irgendwas>) heißen?

    sizeof ist keine Funktion, sondern ein Operator. So wie beispielsweise ein Minuszeichen, -5 und -(5) sind das gleiche. Die Klammern sind nur nötig, wenn der Operator sich auf einen Gesamtausdruck beziehen soll, der ansonsten seinen Sinn verändern würde ( -5+4 ist etwas anderes als -(5+4) ) oder wenn man Leuten das Lesen erleichtern möchte.

    2. wie kann ich dann eine Matrix mit double-Einträgen daraus machen?

    Dann muss in Zeilen 2, 11 und 23 double statt int stehen.

    3. wieso ist *speicher dann vom typ void?

    Weil das eben der Typ für generische Zeiger in C ist, in den alle Zeigertypen umgewandelt werden können und der in alle Zeigertypen umgewandelt werden kann (ausgenommen Funktionszeiger). Welchen Typ sollten wir sonst nehmen?
    int (*)[spalten] ? Passt nicht bei der Übergabe.
    int * ? Passt nicht zu dem, was wir damit machen wollen.



  • Vielen Dank an alle, die mir geholfen haben 😃



  • Bei sizeof (type-name) müssen aber die Klammern hin (d.h. es entspricht einer Typumwandlung (Cast)), nur bei einem Ausdruck, wie z.B. sizeof 42, können diese wegfallen, s.a. sizeof-Operator (C) oder sizeof.


Log in to reply