Galileo Computing < openbook > Galileo Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

 << zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch für Linux, Unix und Windows
– 2., aktualisierte und erweiterte Auflage 2006
Buch: C von A bis Z

C von A bis Z
1.116 S., mit CD, Referenzkarte, 39,90 Euro
Galileo Computing
ISBN 3-89842-643-2
gp Kapitel 13 Arrays
  gp 13.1 Arrays deklarieren
  gp 13.2 Initialisierung und Zugriff auf Arrays
    gp 13.2.1 Gültigkeitsbereich von Arrays
  gp 13.3 Arrays vergleichen
  gp 13.4 Anzahl der Elemente eines Arrays ermitteln
  gp 13.5 Übergabe von Arrays an Funktionen
  gp 13.6 Arrays aus Funktionen zurückgeben
  gp 13.7 Programmbeispiel zu den Arrays
  gp 13.8 Einlesen von Array-Werten
  gp 13.9 Mehrdimensionale Arrays
  gp 13.10 Mehrdimensionale Arrays initialisieren
    gp 13.10.1 Tic Tac Toe
    gp 13.10.2 Dreidimensionale Arrays
  gp 13.11 Übergabe von zwei- bzw. mehrdimensionalen Arrays an Funktionen
  gp 13.12 Arrays in Tabellenkalkulation einlesen (*.CSV–Dateien)
  gp 13.13 Strings/Zeichenketten (char Array)
    gp 13.13.1 Vom String zur Binärzahl
  gp 13.14 Einlesen von Strings
  gp 13.15 Standard-Bibliothek <string.h>
    gp 13.15.1 strcat() – Strings aneinander hängen
    gp 13.15.2 strchr() – ein Zeichen im String suchen
    gp 13.15.3 strcmp() – Strings vergleichen
    gp 13.15.4 strcpy() – einen String kopieren
    gp 13.15.5 strcspn() – einen Teilstring ermitteln
    gp 13.15.6 strlen() – Länge eines Strings ermitteln
    gp 13.15.7 strncat() – String mit n Zeichen aneinander hängen
    gp 13.15.8 strncmp() – n Zeichen von zwei Strings miteinander vergleichen
    gp 13.15.9 strncpy() – String mit n Zeichen kopieren
    gp 13.15.10 strpbrk() – Auftreten bestimmter Zeichen suchen
    gp 13.15.11 strrchr() – das letzte Auftreten eines bestimmten Zeichens im String suchen
    gp 13.15.12 strspn() – erstes Auftreten eines Zeichens, das nicht vorkommt
    gp 13.15.13 strstr() – String nach Auftreten eines Teilstrings durchsuchen
    gp 13.15.14 strtok() – String anhand bestimmter Zeichen zerlegen


Galileo Computing - Zum Seitenanfang

13.10 Mehrdimensionale Arrays initialisieren  downtop

Werte bei mehrdimensionalen Arrays werden ähnlich übergeben wie bei einem eindimensionalen Array. Hier zum Beispiel eine Deklaration mit sofortiger Initialisierung von Werten:

/* 4 Zeilen 5 Spalten */
int Matrix[4][5] = { {10,20,30,40,50},
                     {15,25,35,45,55},
                     {20,30,40,50,60},
                     {25,35,45,55,65}};

Dadurch ergibt sich folgende Belegung des Feldes:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.7   Ein zweidimensionales Array, mit Werten initialisiert

Wie bei den normalen Arrays lassen sich die einzelnen Elemente mithilfe des Feldindex initialisieren. Wollen Sie beispielsweise das Element mit dem Wert 60 ändern in 100, dann geht das wie folgt:

Matrix[2][4] = 100;

Hier wurde zum Beispiel der Inhalt von Matrix[2][4] verändert. Wollen Sie das Element mit dem Wert 65 umändern in 66, dann wird folgender Feldindex verwendet:

Matrix[3][4] = 66;

Eine weitere Möglichkeit zur Initialisierung von mehrdimensionalen Arrays ist folgende:

int Matrix[4][4] = { {0},
                     {1},
                     {0,1},
                     {0,0,1} };

Hiermit besitzen alle Feldelemente, die nicht ausdrücklich initialisiert wurden, automatisch den Wert 0. Die Belegung des Feldes sieht also folgendermaßen aus:

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.8   Ein zweidimensionales Array (4 x 4)

In der Praxis werden mehrdimensionale Arrays bei verschiedensten Arten von Berechnungen benötigt oder bei 2-D-Darstellungen von Grafiken. Das folgende Programm demonstriert die Anwendung eines mehrdimensionalen Arrays:

/* md_array1.c */
#include <stdio.h>
#include <stdlib.h>
#define VOL1 3   /* Anzahl Felder erste Dimension – Zeilen   */
#define VOL2 4   /* Anzahl Felder zweite Dimension – Spalten */
int main(void) {
   int i,j;
   int myarray[VOL1][VOL2];     /* [3][4] */
   /* Eingabe der Array-Elemente */
   for(i=0; i < VOL1; i++) {
      for(j=0; j < VOL2; j++) {
         printf("Wert für myarray[%d][%d]:", i, j);
         scanf("%d", &myarray[i][j]);
      }
   }
   printf("\nAusgabe von myarray[%d][%d]...\n\n", VOL1, VOL2);
   for(i=0; i < VOL1; i++) {
      for(j=0; j < VOL2; j++) {
         printf("\t%4d ",myarray[i][j]);
      }
      printf("\n\n");
   }
   return EXIT_SUCCESS;
}

Das Programm nimmt nichts anderes vor, als den Anwender nach Ganzzahlen abzufragen, um diese Werte im zweidimensionalen Array zu speichern und wieder auszugeben. Um dies zu realisieren, wird eine äußere und innere for-Schleife verwendet. Die äußere for-Schleife dient dabei der Inkrementierung der Variablen im linken Indizierungsoperator (oder, aus der Sicht einer Tabellenkalkulation, der Zeile). Die innere for-Schleife inkrementiert den Wert im rechten Indizierungsoperator (und somit der Spalte).

Im nächsten Beispielprogramm soll ein kleines Zeitkonto für einen Arbeitgeber verwaltet werden. Damit sollen einige Arbeitszeitberechnungen durchgeführt werden.

/* md_array2.c */
#include <stdio.h>
#include <stdlib.h>
#define ARBEITER 3
#define TAGE     5
int zeitkonto[ARBEITER][TAGE];
/* Fehlerausgabe */
void error(int n) {
   printf("%d (?) Falsche Eingabe!!\n",n);
}
/* –1- Ausgabe der Wochenarbeitszeit je Arbeiter */
void ArbeiterWochenStunden(void) {
   int i,j,tmp;
   for(i=0; i < ARBEITER; i++) {
      tmp=0;
      printf("Wochenarbeitszeit von Arbeiter Nr. %d\n", i+1);
      printf("-------------------------------------\n");
      for(j=0; j < TAGE; j++) {
         printf("|%d Std.", zeitkonto[i][j]);
         tmp += zeitkonto[i][j];
      }
      printf("| = Ges. %d Std.\n\n",tmp);
   }
}
/* –2- Durchschnittszeiten pro Tag in der Woche je Arbeiter */
void ArbeiterTagesDurchschnitt(void) {
   int i,j,tmp;
   for(i=0; i < ARBEITER; i++) {
      tmp=0;
      printf("Durchschn. pro Tag/Woche Arbeiter: %d\n",i+1);
      printf("-------------------------------------------\n");
      for(j=0; j < TAGE; j++) {
         tmp+=zeitkonto[i][j];
      }
      printf("Durchschn. v. Arbeiter %d p. Tag: %.1f "
             "Std/Tag\n\n" , i+1, (float)tmp / TAGE);
   }
}
/* –3- Durchschnittszeit aller Arbeiter pro Tag */
void TeamTagesDurchschnitt(void) {
   int i,j,tmp;
   for(i=0; i < TAGE; i++) {
      tmp=0;
      printf("Durchschn. Arbeitszeit aller Mitarbeiter pro "
             "Tag %d = ", i+1);
      for(j=0; j < ARBEITER; j++) {
         tmp += zeitkonto[j][i];
      }
      printf("%.1f Std.\n\n",(float)tmp/ARBEITER);
   }
}
/* –4- Gesamtstunden aller Arbeiter in der Woche */
void TeamWochenStunden(void) {
   int i, j, tmp=0;
   printf("Gesamtstunden aller Arbeiter in der Woche\n");
   printf("-----------------------------------------\n");
   for(i=0; i < ARBEITER; i++) {
      for(j=0; j < TAGE; j++) {
         tmp+=zeitkonto[i][j];
      }
   }
   printf("Gesamtstunden aller Arbeiter i. d. Woche: "
          " %d Std.\n" , tmp);
}
/* Stundenübersicht eines einzelnen Arbeiters */
void ArbeiterStundenUebersicht(void) {
   int arb,tag;
   printf("Welcher Arbeiter: ");
   scanf("%d", &arb);
   printf("Welcher Tag: ");
   scanf("%d", &tag);
   if(arb > ARBEITER) {
      printf("Die Firma hat nur %d Arbeiter\n", ARBEITER);
      return;
   }
   else if(tag > TAGE) {
      printf("Es werden nur %d Tage gespeichert\n", TAGE);
      return;
   }
   printf("Arbeiter Nr.%d hat am Tag %d : ", arb, tag);
   printf("%d Stunden gearbeitet!\n\n", zeitkonto[arb-1][tag-1]);
}
int main(void) {
   int abfrage, i, j;
   for(i=0; i < TAGE; i++) {
      printf("\n\tTag %d in der Woche\n",i+1);
      printf("\t-------------------\n\n");
      for(j=0; j < ARBEITER; j++) {
         printf("Arbeiter Nr.%d in Std.: ",j+1);
         scanf("%d",&zeitkonto[j][i]);
         if(zeitkonto[j][i] > 24)
            printf("Ein Tag hat nur 24 Stunden?\n");
      }
   }
   do {
      printf("\n\n");
      printf("\t-1- Stundenwoche\n");
      printf("\t-2- Durchschnitt/Tag\n");
      printf("\t-3- Durchschnitt aller Arbeiter/Tag\n");
      printf("\t-4- Stunden aller Arbeiter/Woche\n");
      printf("\t-5- Einzelauswahl eines Arbeiters\n");
      printf("\t-6- ENDE\n");
      printf("\n\tIhre Wahl : ");
      scanf("%1d",&abfrage);
      printf("\n");
      switch(abfrage) {
         case 1  : ArbeiterWochenStunden();
                   break;
         case 2  : ArbeiterTagesDurchschnitt();
                   break;
         case 3  : TeamTagesDurchschnitt();
                   break;
         case 4  : TeamWochenStunden();
                   break;
         case 5  : ArbeiterStundenUebersicht();
                   break;
         case 6  : break;
         default : error(abfrage);
      }
   } while(abfrage != 6);
   return EXIT_SUCCESS;
}

Die Bildschirmausgabe des Programms könnte zum Beispiel folgendermaßen aussehen (siehe Abbildung 13.9).

Es fällt auf, dass die Funktionen immer in etwa gleich aufgebaut sind. Auf entsprechende korrekte Feldindexierung muss natürlich geachtet werden. In der Funktion ArbeiterStundenUebersicht() wird demonstriert, wie gezielt auf ein Element eines Arrays zugegriffen werden kann. Das Programm ist natürlich noch verbesserungswürdig. Warnungen, dass ein Arbeiter zu viel oder zu wenig arbeitet, ob ein Arbeiter krank war oder die Stunden als Gleitkommazahlen angegeben werden sollen, sind nur einige Vorschläge dazu.

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.9   Stundenverwaltung des Personals in Aktion

Tatsächlich sind Arrays zwar sehr komfortabel in der Anwendung, sie sind jedoch sehr unflexibel, was die Anzahl der Elemente angeht. Die Anzahl der Elemente muss zum Zeitpunkt der Implementierung schon festgelegt werden, da sich ein Feld nicht ohne Mehraufwand dynamisch zur Laufzeit des Programms vergrößern oder verkleinern lässt.

Das bedeutet, dass die Menge der im Array zu speichernden Daten schon vor Ablauf des Programms bekannt sein oder zumindest überdimensioniert werden muss.

Wenn das Array im vorgestellten Beispiel für 1000 Mitarbeiter dimensioniert würde, wäre das Programm nicht mehr benutzbar, sobald mehr als 1000 Mitarbeiter verwaltet werden sollen.

Eine Lösungsmöglichkeit besteht darin, das Array sehr groß zu dimensionieren, um von vorneherein sehr große Grenzen vorzugeben, etwa MitarbeiterArray[100000].

Dieser Ansatz kostet aber sehr viel (möglicherweise) ungenutzten Arbeitsspeicher, der das Programm unter Umständen stark verlangsamt.

Da aus Performance-Gründen generell stets möglichst wenig Arbeitsspeicher von Programmen belegt werden soll, gelten Arrays bei großen Datenmengen oder stark wechselnder Anzahl der Daten als nicht so effizient wie etwa verkettete Listen.

In Kapitel 23, Dynamische Datenstrukturen, wird auf die Datenverwaltung mit verketteten Listen näher eingegangen.


Galileo Computing - Zum Seitenanfang

13.10.1 Tic Tac Toe  downtop

Ein weiteres interessantes Beispiel zur Demonstration von zweidimensionalen Arrays ist das wohl allseits bekannte Spiel »Tic Tac Toe«. Sie benötigen dabei lediglich ein Kästchen von 3 x 3 Feldern. Dies lässt sich prima mit einem zweidimensionalen Array darstellen: eine Dimension für die Reihe und eine weitere für die Spalte.

char TicTacToe[3][3] = { {' ',' ',' '},
                         {' ',' ',' '},
                         {' ',' ',' '} };

Ein kurze Beschreibung des Spiels: Ein Spieler hat das Zeichen X und ein anderer das Zeichen O. Nach einem Zug ist der andere Spieler an der Reihe. Gewonnen hat der Spieler, der zuerst drei gleiche Zeichen (X oder O) in der Waagerechten, in der Senkrechten oder in der Diagonalen hat. Es gibt insgesamt acht Stellungsmöglichkeiten, um das Spiel zu gewinnen. Diese gilt es zu überprüfen. Es gibt außerdem noch eine neunte Möglichkeit, nämlich die, dass alle Felder besetzt sind, und keiner der beiden Spieler hat gewonnen. Hier der vollständige Quellcode dazu:

/* tictactoe.c */
#include <stdio.h>
#include <stdlib.h>
#ifdef __unix__
    #define clrscr() printf("\x1B[2J")
#elif __BORLANDC__ && __MSDOS__
    #include <conio.h>
#elif __WIN32__ || _MSC_VER
    #define clrscr() system("cls")
#else
    #define clrscr() printf("clrscr() – Fehler!!\n")
#endif
#define X 'X'
#define O 'O'
#define LEER ' '
#define GAME_OVER 0
#define A_WINNER 1
#define CONTINUE 2
/* Inhalt des 3 x 3 grossen Felds */
char TicTacToe[3][3] = { {' ',' ',' '},
                         {' ',' ',' '},
                         {' ',' ',' '} };
/* Spieler1 hat das Zeichen 'X' */
char Spieler1 = X;
/* Spieler2 hat das Zeichen 'O' */
char Spieler2 = O;
/* Anzahl der Felder, die besetzt werden können */
unsigned int felder = 9;
/* Funktionsprototypen */
void print_spielfeld(void);
char neuer_zug(char);
int if_win(void);
/* Gibt den aktuellen Zustand des Spielfelds aus */
void print_spielfeld(void) {
   int i;
   clrscr();
   printf("       1   2   3  \n     +---+---+---+\n");
   for(i = 0; i < 3; i++) {
      printf("  %d  | ",i+1);
      printf("%c",TicTacToe[i][0]);
      printf(" | ");
      printf("%c",TicTacToe[i][1]);
      printf(" | ");
      printf("%c",TicTacToe[i][2]);
      printf(" | \n");
      if(i != 2) {
         printf("     +---+---+---+\n");
      }
      else {
         printf("     +---+---+---+\n");
      }
   }
}
/* Führt einen neuen Zug aus.
 * char ch: Zeichen des Spielers, der an der Reihe ist, 'X'
 * oder 'O'
 * Rückgabewert: Zeichen des Spielers, der eben an der Reihe war
 * falls ein Feld besetzt ist, wird der Rückgabewert vertauscht,
 * damit der aktuelle Spieler nochmals seinen Zug machen kann.
 * Hat ein Spieler gewonnen, gibt die Funktion die
 * symb. Konstante GAME_OVER zurück
 */
char neuer_zug(char ch) {
   unsigned int row, colum;
   printf("\nSpieler \"%c\" ist an der Reihe\n\n",ch);
   printf("Zeile  (1–3): ");
   scanf("%d",&row);
   printf("Spalte (1–3): ");
   scanf("%d",&colum);
   if(TicTacToe[row-1][colum-1] == LEER) {
      /* Zeichen in das mehrdim. Array */
      TicTacToe[row-1][colum-1] = ch;
      print_spielfeld();
      /* Haben wir schon einen Gewinner? */
      if(if_win() == A_WINNER)
         return GAME_OVER;
   }
   else { /* Ein bereits besetztes Feld */
      print_spielfeld();
      printf("\n!!! Feld ist bereits gesetzt !!!\n");
      return (ch == X) ?O :X;
   }
   /* Sind bereits alle Felder besetzt? */
   if(--felder > 0)
      return ch;
   else {
      printf("\nAlle Felder sind besetzt – Unentschieden\n");
      return GAME_OVER;
   }
}
/* Auswertung aller Möglichkeiten, um einen Gewinner zu ermitteln
 * Rückgabewert: symb. Konstante A_WINNER falls ein Gewinner
 * ermittelt wurde oder die symb. Konstante CONTINUE zum
 * Weiterspielen.
 */
int if_win(void) {
  /* Zuerst Spieler1 'X' */
  if(TicTacToe[0][0] == Spieler1 &&
     TicTacToe[0][1] == Spieler1 &&
     TicTacToe[0][2] == Spieler1 ||
     TicTacToe[1][0] == Spieler1 &&
     TicTacToe[1][1] == Spieler1 &&
     TicTacToe[1][2] == Spieler1 ||
     TicTacToe[2][0] == Spieler1 &&
     TicTacToe[2][1] == Spieler1 &&
     TicTacToe[2][2] == Spieler1 ||
     TicTacToe[0][0] == Spieler1 &&
     TicTacToe[1][0] == Spieler1 &&
     TicTacToe[2][0] == Spieler1 ||
     TicTacToe[0][1] == Spieler1 &&
     TicTacToe[1][1] == Spieler1 &&
     TicTacToe[2][1] == Spieler1 ||
     TicTacToe[0][2] == Spieler1 &&
     TicTacToe[1][2] == Spieler1 &&
     TicTacToe[2][2] == Spieler1 ||
     TicTacToe[0][0] == Spieler1 &&
     TicTacToe[1][1] == Spieler1 &&
     TicTacToe[2][2] == Spieler1 ||
     TicTacToe[0][2] == Spieler1 &&
     TicTacToe[1][1] == Spieler1 &&
     TicTacToe[2][0] == Spieler1) {
        printf("Spieler1 hat gewonnen\n");
        return A_WINNER;
  }
  /* Jetzt Spieler2 'O' */
  else if( TicTacToe[0][0] == Spieler2 &&
           TicTacToe[0][1] == Spieler2 &&
           TicTacToe[0][2] == Spieler2 ||
           TicTacToe[1][0] == Spieler2 &&
           TicTacToe[1][1] == Spieler2 &&
           TicTacToe[1][2] == Spieler2 ||
           TicTacToe[2][0] == Spieler2 &&
           TicTacToe[2][1] == Spieler2 &&
           TicTacToe[2][2] == Spieler2 ||
           TicTacToe[0][0] == Spieler2 &&
           TicTacToe[1][0] == Spieler2 &&
           TicTacToe[2][0] == Spieler2 ||
           TicTacToe[0][1] == Spieler2 &&
           TicTacToe[1][1] == Spieler2 &&
           TicTacToe[2][1] == Spieler2 ||
           TicTacToe[0][2] == Spieler2 &&
           TicTacToe[1][2] == Spieler2 &&
           TicTacToe[2][2] == Spieler2 ||
           TicTacToe[0][0] == Spieler2 &&
           TicTacToe[1][1] == Spieler2 &&
           TicTacToe[2][2] == Spieler2 ||
           TicTacToe[0][2] == Spieler2 &&
           TicTacToe[1][1] == Spieler2 &&
           TicTacToe[2][0] == Spieler2)  {
              printf("Spieler2 hat gewonnen\n");
              return A_WINNER;
   }
   return CONTINUE;
}
int main(void) {
   char check = X;
   /* Leeres Spielfeld ausgeben */
   print_spielfeld();
   do { /* War Spieler mit dem Zeichen 'X' gerade dran ... */
      /* ... dann ist jetzt Spieler mit dem Zeichen 'O' dran */
      if(check==X) {
            check=neuer_zug(O);
      }
      else { /* ... ansonsten der Spieler mit dem Zeichen 'X' */
        check=neuer_zug(X);
      }
   } while( check != GAME_OVER );
   return EXIT_SUCCESS;
}

Abbildung
Hier klicken, um das Bild zu Vergrößern

Abbildung 13.10   Das Spiel Tic Tac Toe für die Konsole

Wenn Sie jetzt noch Lust und viel Zeit haben, können Sie sich ja hinsetzen und eine Funktion basteln, um gegen den Computer antreten zu können, also eine eigene KI programmieren. Dabei können Sie so ähnlich vorgehen wie bei der Funktion if_win(), nur dass Sie auch handeln müssen. Sie sollten aber dabei beachten, dass Sie die KI so programmieren, dass der menschliche User auch noch gewinnen kann.


Hinweis   KI steht für künstliche Intelligenz. Gemeint ist damit die Möglichkeit einer Maschine, sich Funktionen des Menschen, wie Denken oder Bewegungsabläufe, mithilfe von Programmen anzueignen (simulieren).



Galileo Computing - Zum Seitenanfang

13.10.2 Dreidimensionale Arrays  toptop

Zur Veranschaulichung ein weiteres Beispiel, wie ein dreidimensionales Array direkt mit Werten initialisiert werden kann:

int dreid[2][3][4]={{{6,7,4,3},{6,4,6,9},{3,4,6,7}},
                    {{7,8,6,4},{5,99,3,5},{4,6,7,8}}};

Hier ist eine geschweifte Klammer hinzugekommen:

int dreid[][][]= {1.Feldindex{2.Feldindex{3.Feldindex}}};

Wenn zum Beispiel auf die erste Zahl zugegriffen werden soll, geschieht das folgendermaßen:

dreid[0][0][0]    /* erste Zahl 6 */

Oder auf die Zahl 99:

dreid[1][1][1]    /* die Zahl 99 */

Ein Beispiel dazu erspare ich mir, da Sie in der Regel selten mit einem solchen Array zu tun haben. Außerdem lässt sich so etwas nur recht schwer vorstellen.

 << zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z
C von A bis Z
bestellen
 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: Shell-Programmierung






 Shell-Programmierung


Zum Katalog: Linux-UNIX-Programmierung






 Linux-UNIX-Programmierung


Zum Katalog: C/C++






 C/C++


Zum Katalog: UML 2.0






 UML 2.0


Zum Katalog: Reguläre Ausdrücke






 Reguläre Ausdrücke


Zum Katalog: Linux






 Linux


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo





Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Galileo Computing]

Galileo Press, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, info@galileo-press.de