24. Arrays II

Arrays und Funktionen

Die Längenangabe von Arrays kann unterbleiben, wenn sie an eine Funktion übergeben werden. Funktionen, die Arrays nehmen, sollten in aller Regel auch ein Argument haben, in dem die Zahl der Einträge im Array steht.

void printHistogram(int vals[], int numVals)
{
  int i, j;

  for (i=0; i<numVals; i++) {
    printf("%3d ", vals[i]);
    for (j=0; j<vals[i]; j++) {
      printf("#");
    }
    printf("\n");
  }
}

Diese Funktion könnte beispielsweise so verwendet werden:

#include <stdio.h>

#define MAX_VALS 20

int main(void)
{
  int vals[MAX_VALS];
  int i;

  for (i=0; i<MAX_VALS; i++) {
    if (scanf("%d", &(vals[i]))!=1) {
      break;
    }
  }
  if (i==MAX_VALS) {
    fprintf(stderr, "Can't handle more than %d values.  Raise MAX_VALS"
      " if you need to.\n", MAX_VALS);
  }
  printHistogram(vals, i);
  return 0;
}

Der Effekt einer Deklaration ohne Längenangabe ist jedenfalls, dass die Funktion Arrays “beliebiger” Länge verarbeiten kann. Davon haben wir vorderhand noch nicht viel, da wir uns immer noch zur Compilezeit festlegen müssen, wie groß die Arrays sind – Abhilfe schafft da erst die dynamische Speicherverwaltung.

Tatsächlich definiert der jüngste C-Standard, meist C99 genannt, variable length arrays, deren Größe erst zur Laufzeit bestimmt wird. So etwas kann manchmal praktisch sein, ich rate aber vorläufig von ihrer Verwendung ab.

Mehrdimensionale Arrays

Häufig hat man zweidimensionale Daten, z.B. die Übergangshäufigkeit von einem Buchstaben 1 auf einen Buchstaben 2. Dann können in C zweidimensionale Arrays verwendet werden. Deklaration etwa durch

int langmodel[NUM_ALPHA][NUM_ALPHA];

Verwendung wie

int loadLangmodel(int langmodel[][NUM_ALPHA])
{
  int i,j;

  for (i=0; i<NUM_ALPHA; i++) {
    for (j=0; j<NUM_ALPHA; j++) {
      if (1!=scanf("%d", &(langmodel[i][j]))) {
        return -1;
      }
    }
  }
  return 0;
}

int getTransFreq(int langmodel[][NUM_ALPHA],
  char c1, char c2)
{
  return langmodel[c1-'A'][c2-'A'];
}

Diese Funktionen ließen sich in ein Programm wie

#include <stdio.h>

#define NUM_ALPHA 26

int main(void)
{
  int langmodel[NUM_ALPHA][NUM_ALPHA];

  if (loadLangmodel(langmodel)) {
    printf("Oops...\n");
    return 1;
  }
  printf("Übergang von A auf R: %d\n",
    getTransFreq(langmodel, 'A', 'R'));
  return 0;
}

einbauen.

Wenn die Dimensionen nicht von vorneherein so fixiert sind wie in diesem Beispiel, ist es meistens besser, eindimensionale Arrays zu verwenden und die zweidimensionale Struktur selbst zu machen. Will man beispielsweise ein Array mit N Zeilen und M Spalten, geht das so:

int arr[M*N];

arr[N*j+i] = 5; /* Setze Zeile j, Spalte i auf 5 */

Auf die Weise kann unter anderem das Problem umgangen werden, dass alle Dimensionen bis auf die letzte in jedem Prototypen angegeben werden müssen. Eine weitere Alternative, die je nach Zugriffsmuster bequemer sein kann, ist die “Python-Methode” – in Python würde man mehrdimensionale Daten durch verschachtelte Sequenzen repräsentieren. Eine Liste, in der andere Listen “stehen”, ist ja in Wirklichkeit nur eine Sammlung von Referenzen auf andere Objekte. Analog kann man in C Arrays von Pointern auf Arrays der eigentlichen Nutzdaten definieren. Wir werden dieser Methode begegnen, wenn wir Arrays von Strings verwalten wollen.

Übungen zu diesem Abschnitt

Ihr solltet euch wenigstens an den rötlich unterlegten Aufgaben versuchen

(1)

Die oben gezeigte Funktion getTransFreq enthält eine böse Falle: Sie prüft nicht, ob ihre Argumente im Definitionsbereich der Funktion liegen (d.h. in diesem Fall zwischen ’A’ und ’A’+NUM_ALPHA – unterlässt man diese Prüfung, gibt die Funktion für unzulässige Argumente kompletten Unsinn zurück, was zwar aus einer theoretischen Perspektive (“partielle Funktion”) nicht schlimm sein mag, aber in realistischen Programmen zu den wüstesten Fehlern führen wird.

Seht nach, was mit dieser “naiven” Funktion bei unzulässigen Argumenten passiert und ergänzt eine Prüfung der Argumente – die Funktion muss dann einen Fehlercode zurückgeben, der hier naheliegenderweise -1 sein könnte, denn natürlich kann eine “richtige” Übergangsfrequenz nie -1 sein.


Markus Demleitner

Copyright Notice