Anzeige:
Ergebnis 1 bis 8 von 8

Thema: C: Zeiger auf Zeiger und ein Mehrdimensionales Array

  1. #1
    Registrierter Benutzer Avatar von Sector1379
    Registriert seit
    04.10.2005
    Ort
    KR
    Beiträge
    89

    C: Zeiger auf Zeiger und ein Mehrdimensionales Array

    Hallo zusammen,

    ich habe mal folgendes mini Programm in C geschrieben um mir die Übergabe von Mehdimensionalen Array an doppel Zeiger klar zu machen.

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #define S 10
    #define C 10
    //////////// fill ////////////////
    
    void output(int **feld) {
       int i, j;
    
       for(i = 0; i < 9; i++) {
          for(j = 0; j < 9; j++) {
             printf(" %3d ", feld[i][j]);
          }
          printf("\n");
       }
       printf("\n");
    }
    
    ////////////////////main/////////////////
    
    int main(void){
    
      int array[S][C];
      int i, j;
    
      
    
      for(j=0; j <= 9; j++){
        for(i=0; i<=9 ;i++)
          array[i][j] = i+j;
      }
    
      output(array[][S]);
      return EXIT_SUCCESS;
    
    }
    Leider bekomme ich es nicht hin das Array richtig an den Zeiger zu Über geben. Könnte mir jemand dabei helfen zu verstehen wie man das richtig macht ??
    Gruß Sector

  2. #2
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Es gibt n+1 Möglichkeiten das zu machen - eine davon:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #define S 10
    #define C 10
    //////////// fill ////////////////
    
    void output(int *feld) {
       int i, j;
    
       for(i = 0; i < S; i++) {
          for(j = 0; j < C; j++) {
             printf(" %3d ", *(feld + C*i + j) );
          }
          printf("\n");
       }
       printf("\n");
    }
    
    ////////////////////main/////////////////
    
    int main(void){
    
      int array[S][C];
      
      int i, j;
    
      
    
      for(j=0; j < S; j++){
        for(i=0; i < C; i++)
          array[i][j] = i+j;
      }
    
      output(&array[0][0]);
      return EXIT_SUCCESS;
    
    }
    und die n weiteren: http://c-faq.com/aryptr/ary2dfunc3.html

    Darfst auswählen

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  3. #3
    Registrierter Benutzer Avatar von Sector1379
    Registriert seit
    04.10.2005
    Ort
    KR
    Beiträge
    89
    Hallo Peschmä,

    danke für deine Antwort sieht ja auf den ersten Blick gruselig aus . Naja ich werde das mal ausseinander nehmen und gucken wie sich das alles zu einander verhält.

    Dein Link habe ich versucht aufzurufen aber leider sagt mein Browser mir das die Seite down ist......... naja ich probiers später nochmal
    Gruß Sector

  4. #4
    Registrierter Benutzer
    Registriert seit
    02.02.2006
    Beiträge
    41
    Hallo Sector,

    das gleiche Problem hatte ich auch. Ein Freund von mir hat mir folgendermaßen geholfen:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #define S 10
    #define C 10
    //////////// fill ////////////////
    
    // Funktion zum Allokieren eines 2D integer Arrays
    int **getmem2Di(const unsigned int rows, const unsigned int columns)
    {
      int **ptr;
      unsigned int i;
      int j;
    
      /* Allokieren des 2D-Speichers, sollte die Anfrage
         fehlschlagen den gesamten Prozess beenden */
      ptr=(int**)(calloc(rows,sizeof(int*)));
      if(ptr!=NULL)
      {
    
        for (i=0;i<rows;i++)
        {
          ptr[i]= (int*)(calloc(columns,sizeof(int)));
          if(ptr[i]==NULL)
          {
            for(j=i;j>=0;j--)
              free(ptr[j]);
            free(ptr);
            return(NULL);
          }
        }
        return(ptr);
      }
      return(NULL);
    }
    
    void output(int**feld) {
       int i, j;
    
       for(i = 0; i < S; i++) {
          for(j = 0; j < C; j++) {
             printf(" %3d ", feld[i][j]);
          }
          printf("\n");
       }
       printf("\n");
    }
    
    ////////////////////main/////////////////
    
    int main(void){
    
      int **array;
      
      int i, j;
    
      
      array = getmem2Di(S,C);
    
      for(j=0; j < S; j++){
        for(i=0; i < C; i++)
          array[i][j] = i+j;
      }
       output(array);
       
      return EXIT_SUCCESS;
    
    }
    Bei mir funzt das wunderbar.

    Viele Grüße
    Andreas

  5. #5
    Registrierter Benutzer
    Registriert seit
    24.12.2001
    Ort
    anywhere before EOF
    Beiträge
    236

    man sollte mit den Board-Tags umgehen können, dann klappts auch mit dem Code-Block

    Zitat Zitat von peschmae Beitrag anzeigen
    Code:
    [...]
    output(&array[0][0]);
    [...]
    Nein, das klappt nicht. So bekommt man die Adresse der Stelle im Speicher wo der Wert des ersten Elements liegt. Die ist aber nicht gleich dem Anfang der Folge wo die Zeiger auf die Unterbereiche liegen (logisch, weil auch die Zeiger Platz im Speicher brauchen).

    Einfaches Beispiel, unter der Annahme, dass der Vektor wie folgt erstellt wurde und dass das Zielsystem nen 8bit Adressbus hat und sizeof(int) == 1 (Anm. auf i386-Architekturen ist das beides allerdings in Wirklichkeit 32bit breit, AFAIK, aber dann muss ich so viel tippen ):
    Code:
    int foo[2][2];
    
    foo[0][0] = 1;
    foo[0][1] = 2;
    foo[1][0] = 3;
    foo[1][1] = 4;
    Im Speicher würde das in etwa so aussehen (die Hexzahlen vor den Doppelpunkten sind die Adressen, die Zahlen dahinter die Werte, nach dem Nummernzeichen steht wie man den Wert und die Adresse ansprechen würde):
    Code:
    0x01: 0xa1 # wert = foo[0], adresse = &foo[0]
    0x02: 0xd1 # wert = foo[1], adresse = &foo[1]
    ...
    0xa1: 0x01 # wert = foo[0][0], adresse = &foo[0][0]
    0xa2: 0x02 # wert = foo[0][1], adresse = &foo[0][1]
    ...
    0xd1: 0x03 # wert = foo[1][0], adresse = &foo[1][0]
    0xd2: 0x04 # wert = foo[1][1], adresse = &foo[1][1]
    Die Lücken (...) hab ich bewusst da eingebaut, damits besser verständlich wird, was da passiert, diese können in der Realität da sein, müssen es aber nicht.
    Wie man also deutlich sehen kann würdest du mit deinem Vorschlag auf mein Beispiel bezogen 0xa1 an die Funktion übergeben, währen diese aber auf Grund der Deklarationen davon ausgeht, das sie im Speicher unter der Adresse 0xa1 einen Zeiger findet der zwar auf einen Bereich zeigt wo zwei Integerwerte liegen (und an der Folgeadresse 0xa2 wieder usf.), aber eben keine zwei Integer direkt. In 0x01, was der Wert an dieser Adresse ist, liegt aber in der angenommenen Konstellation eigentlich kein Integerwert sondern eben ein Zeiger (0xa1, dieser würde aber als Integer Interpretiert werden und als Ausgabe käme eine 161 statt der erwarteten 1. dann eine 209 statt der 2, dann wieder eine 209 und schliesslich wird versucht auf 0x03 zuzugreifen, wo wir jetzt nicht wissen was drin steht, weil das gar nicht zu unserem Programm gehört und wir haben nen schönen Seg-Fault...

    Also müsste das ganze so aussehen, dann würde korrekterweise 0x01 übergeben:
    Code:
    output(array);
    Wie auch immer @Sector1379, weil dich ja nun noch von den anderen Threads in Erinnerung habe wo du die gleiche oder ähnliche Fehler gemacht hast, wenn du so nen Speicherbereich oder Vektoren übergeben willst, dann musst du nicht array[][] oder array[max] oder sowas schreiben, sondern einfach sicherstellen, dass in array die Addresse des Anfangs dieses Bereichs, bzw. Vektors liegt (und das tus üblicherweise, wenn es das ein Ergebnis eines erfolgreichen malloc()s o. Ä bzw. ein fix deklarierter Vektor ist und man es nicht verändert) und einfach diesen Pointer (array) übergeben. Wegen der Deklarationen ist klar was damit gemacht werden muss, also ob das nun ein Integer, ein Character oder ein anderer Typ ist oder ob es ein-, zwei- oder n-dimensional ist.
    Also function(array) übergibt den geamten Vektor bzw. Speicherbereich, also eigentlich den Zeiger zum Anfang, aber wenn der Funktionsprototyp mit function(type** argument) dasteht ist bekannt, dass das zweidimensional ist.
    function(array[n][m]) übergibt genau ein Element im Vektor bzw. Bereich. Wenn der Typ von array also beispielsweise mit int **array deklariert wurde halt einen Integer, keinen Zeiger!
    Um einen Teilbereich bzw. -vektor zu übergeben kannst du function(array[n]) benutzen. Bei zwei Dimensionen würde dann eine Zeile übergeben werden, also beispielsweise wenn die Deklararion von array type **array lautet wäre dass dann ein Vektor bzw. Bereich des Typs type *.
    Man möge mich korregieren, wenn ich da ne Lücke hab aber AFAIK ist alles andere, also function(array[]) und function(array[][m]) usf. Bullshit und bringt ausser Syntaxfehlern gar nichts hervor, sowas klappt vielleicht in Java (meine da mal sowas gesehen zu haben, kann mich aber auch täuschen), aber nicht in C...
    Geändert von sticky bit (28-10-2006 um 04:11 Uhr)
    chmod -R +t /*

  6. #6
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Stimmt, dass der Compiler alignment machen kann zwischen den einzelnen Arrayteilen wenn er Freude hat, daran habe ich nicht gedacht. Mal abgesehen davon dass er sich da wohl selber in den Arsch beissen würde weil er dann da verdammt gut aufpassen muss dass die Funktion auch in jedem Falle das macht was sie soll, insbesondere auch dann wenn sie von sonstwo aufgerufen wird. Da sehe ich jetzt gerade ziemlich viel Verwaltungsaufwand auf den armen Compiler zukommen (eventuell kann er das auch gar nicht wirklich machen weil er ja die Dateien einzeln und unabhängig voneinander kompilieren können muss)

    Aber mit deinen Erläuterungen bin ich doch nicht ganz einverstanden.
    foo[0] ist schon eine adresse - kein Pointer, wie willst du davon die Speicheradresse nehmen? (Edit: Ok, scheint auch zu gehen, wobei das dann nichts ändert, interessant)
    Ausserdem sind bei allen System die mir bisher begegnet sind die Adressen foo, foo[0] und &foo[0][0] dieselbe - alles andere wäre reinste Speicherverschwendung. Der einzige Unterschied ist der Typ - foo ist die Adresse eines 2x2 Arrays, foo[0] die Adresse eines 2-Arrays und &foo[0][0] die Adresse eines ints.

    Oder anders gesagt - mein Speicher sieht so aus:
    Code:
    0xa1: 0x01 # wert = foo[0][0], adresse = &foo[0][0] = foo[0] = foo
    0xa2: 0x02 # wert = foo[0][1], adresse = &foo[0][1]
    0xa3: 0x03 # wert = foo[1][0], adresse = &foo[1][0] = foo[1]
    0xa4: 0x04 # wert = foo[1][1], adresse = &foo[1][1]
    Ich kenne jetzt den Standard nicht so genau - durchaus möglich dass eine Umgebung das irgendwie ganz merkwürdig implementieren kann und weiterhin Standardkonform bleibt...

    MfG Peschmä
    Geändert von peschmae (28-10-2006 um 12:01 Uhr)
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

  7. #7
    Registrierter Benutzer
    Registriert seit
    24.12.2001
    Ort
    anywhere before EOF
    Beiträge
    236
    @peschmae:
    Hast ja recht, da gibts einen Unterschied zwischen Vektoren fixer Länge und dynamisch allozieren Speicherbereichen an den ich nicht gedacht hab.

    Probier einfach mal folgendes Beispiel:
    Code:
    int main (int argc, char **argv)
     {
        int foo[2][2];
        int **bar;
    
        bar = (int**) malloc(2 * sizeof(int*));
        bar[0] = (int*) malloc(2 * sizeof(int));
        bar[1] = (int*) malloc(2 * sizeof(int));
    
        printf("foo: (%p == %p) == %i\n", (int*) foo, (int*) &foo[0][0], (int*) foo == (int*) &foo[0][0]);
        printf("bar: (%p == %p) == %i\n", (int*) foo, (int*) &bar[0][0], (int*) bar == (int*) &bar[0][0]);
    
        return 0;
    }
    Ausgabe bei mir (OpenBSD 3.6 i386):
    Code:
    foo: (0xcfbeeb5c == 0xcfbeeb5c) == 1
    bar: (0x3c005030 == 0x3c005040) == 0
    Wenns bei dir anders aussieht, dann wär das interessant was für ein System du benutzt?

    Ergo, meine Erklärung war falsch, weil ich von fix deklarierten Vektoren ausging, es sich aber genau da anders verhält. Sie würde aber auf dynamische Speicherbereiche absolut zutreffen.
    Folgender Code aus meinem vorangegangenen Post:
    Code:
    int foo[2][2];
    
    foo[0][0] = 1;
    foo[0][1] = 2;
    foo[1][0] = 3;
    foo[1][1] = 4;
    müsste also der Korrektheit halber mit diesem ausgetauscht werden:
    Code:
    int **foo;
    
    foo = (int**) malloc(2 * sizeof(int*));
    foo[0] = (int*) malloc(2 * sizeof(int));
    foo[1] = (int*) malloc(2 * sizeof(int));
    
    foo[0][0] = 1;
    foo[0][1] = 2;
    foo[1][0] = 3;
    foo[1][1] = 4;
    Im speziellen Falle des OP werden zwar in main() fixe Vektoren (Deklaration int array[S][C];) verwendet, so dass array == &array[0][0] tatsächlich gilt, aber der Parameter der an die Funktion output() übergeben werden soll ist mit int **feld deklariert, d. h. das passt eh hinten und vorne nicht zusammen weil dynamische Felder eben anders organisiert sind.
    Also hast du diese Deklaration kurzer Hand in int *feld umgeändert und den Zugriff über die Indices im Code der Funktion rausgeschmissen. Genau das hab ich aber übersehen und bin von gleich bleibender Funktion output() ausgegangen, Entschuldigund dafür.
    Also dein Vorschlag als ganzes ist natürlich korrekt! Ziehe meinen Einwand, dass das so nicht klappen würde also zurück möchte aber anmerken, dass es IMHO nicht elegant gelöst ist, aber das ist Ansichtssache...

    Allerdings, wenn man wie bei deinem Vorschlag die Funktion ändert, spricht trotzdem nichts dagegen einfach array statt &array[0][0] zu übergeben, ist ja ohnehin gleich, liesst sich einfacher und wenn man sowohl den Array in main() als auch die Funktion output() auf dynamische Felder umstellen möchte bleibt der Aufruf der gleiche...
    Geändert von sticky bit (28-10-2006 um 20:39 Uhr)
    chmod -R +t /*

  8. #8
    Registrierter Benutzer Avatar von peschmae
    Registriert seit
    14.03.2002
    Ort
    Schweizland
    Beiträge
    4.549
    Zitat Zitat von sticky bit Beitrag anzeigen
    Hast ja recht, da gibts einen Unterschied zwischen Vektoren fixer Länge und dynamisch allozieren Speicherbereichen an den ich nicht gedacht hab.

    Probier einfach mal folgendes Beispiel:
    ...
    Interessante Variante. Aber das hab ich bisher noch nie so benutzt - wennschon hab ich jeweils einfach ein grosses Speicherstück gemalloct und darauf mit pointern zugegriffen statt mit arrayindices.

    Ausgabe bei mir (OpenBSD 3.6 i386):
    Code:
    foo: (0xcfbeeb5c == 0xcfbeeb5c) == 1
    bar: (0x3c005030 == 0x3c005040) == 0
    Wenns bei dir anders aussieht, dann wär das interessant was für ein System du benutzt?
    Sieht bei mir genau (wenn man von den adressen absieht ) gleich aus (Debian Sid mit Linux 2.6.18)

    ...
    Also hast du diese Deklaration kurzer Hand in int *feld umgeändert und den Zugriff über die Indices im Code der Funktion rausgeschmissen. Genau das hab ich aber übersehen und bin von gleich bleibender Funktion output() ausgegangen
    Ich hab kreuz und quer geändert - darum hab ich dann am Ende auch den ganzen Code gepostet

    Allerdings, wenn man wie bei deinem Vorschlag die Funktion ändert, spricht trotzdem nichts dagegen einfach array statt &array[0][0] zu übergeben, ist ja ohnehin gleich
    Naja, das ist in dem Zusammenhang eine reine Typfrage. Spart eine Warnung bzw. einen Cast.

    MfG Peschmä
    The greatest trick the Devil ever pulled was convincing the world he didn't exist. -- The Usual Suspects (1995)
    Hey, I feel their pain. It's irritating as hell when people act like they have rights. The great old one (2006)

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •