31. Pointer III

In Strings operieren:

int readText(char *buf, int len)
{
  char *cp=buf; int c;

  while (((c=fgetc(stdin))!=EOF)
     && cp-buf<len-1) {
    *cp++ = c;
  }
  *cp = 0;
  return cp-buf;
}

Arrays von Strings macht man in C fast immer als Arrays von Pointern, char *strarray[15];  (und nicht als zweidimensionale Arrays von chars char strarray[15][STR_LEN];)

Dies ist einer der Fälle, in denen die Deklaration char *a nicht äquivalent zu char a[] ist. Im zweiten Fall wird tatächlich Speicher angefordert, und zwar STR_LEN pro String, und die Strings müssen auch tatsächlich dort liegen. Im ersten Fall haben wir keinen Speicher für die tatsächlichen Strings und können die Strings hinlegen, wo wir wollen (natürlich brauchen wir dafür irgendwo Platz – wie wir ihn bekommen, werden wir in Kürze sehen). Der Vorteil ist natürlich die Flexibilität. Wenn wir Wörter in Natursprache speichern wollen (es gibt sehr lange, die meisten sind aber ziemlich kurz), ist Methode (2) furchtbare Speicherverschwendung – außerdem sind Operationen (z.B. Sortieren) auf solchen String-arrays schwierig und langsam.

Die Kommandozeilenargumente kommen als solche Arrays von Strings:

int main(int argc, char *argv[])
{
  int i;

  for (i=0; i<argc; i++) {
    printf("%s\n", argv[i]);
  }
}

gibt die Kommandozeilenargumente aus.

Anwendung: Einen Text in Einzelwörter zerlegen. Idee: Den Text in den Speicher lesen, alles, was kein Buchstabe ist, durch Null ersetzen und Pointer auf die ersten Buchstaben der übrig bleibenden Worte sammeln. Ein Programm, das das tut, befindet sich im Anhang.

Rechts das Ergebnis, wenn der String “Hier steh’ ich nun, ich” (armer Tor) ist.

Auf Pointer kann auch der []-Operator angewandt werden, auf Arrays wirkt + wie auf Pointer.

Technik: Adressierungsarten

Wer sich ein wenig mit den Adressierungsarten auseinandergesetzt hat, wird wohl schon ahnen, dass + und [] auf Pointer schlicht der indirekten Adressierung mit Displacement entspricht. Wenn wir unseren (char-) Pointer ptr im Register ax haben, lassen sich sowohl ptr[2] oder *(ptr+2) einfach in 2(%eax) übersetzen.

Wenn wir jetzt etwas wir ptr[i] haben, müsste das Displacement variabel sein, in der Realität wohl aus einem Register kommen. Da aber ohnehin noch die Größe des Basistyps (bei int-Pointern auf 32-bit-Systemen beispielsweise typischerweise 4) eingerechnet werden muss, gibt es eine unabhängige Art des Verschiebens, und zwar über index (das darf ein Register sein) und scale (1, 2, 4 oder 8), so dass Adressen wie 4(%ebp,%eax,4) möglich sind. Das entspricht der Adresse, die herauskommt, wenn man 4+ebp+4×eax ausrechnet.

Hat der Compiler z.B. dafür gesorgt, dass i in eax ist und int *arr in edi, so kann arr[i] schlicht nach (%edi, %eax, 4) kompiliert werden. Das Displacement ist nützlich, wenn Arrays auf dem Stack liegen oder wir Arrays von Structs haben. Dinge, die die CPU schon selbst kann, werden in der Regel auch schnell ausgeführt werden.

Auch andere CPU-Architekturen unterstützen vergleichbare Adressierungen. C-ProgrammiererInnen ist das Studium der 68000-Architektur anempfohlen – sie ist auf C zugeschnitten wie kaum eine zweite.

Übungen zu diesem Abschnitt

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

(1)

Erweitert das auf der Webseite verlinkte Programm lexWords.c so, dass es ein Wort von der Kommandozeile nimmt und dann zählt, wie oft das betreffende Wort in seiner Eingabe vorkommt. Das soll etwa so aussehen:

examples> lexWords < lexWords.c
Usage: lexWords <WordToCount>
examples> lexWords char < lexWords.c
char kam 18 mal vor

Die Taktik dafür ist recht schlicht: Das Wort, das ihr zählen sollt, ist in argv[1] – das werden wir an die Zählfunktion übergeben, es ist ja praktischerweise schon ein char*. Die Zählfunktion muss jetzt nur noch durch das words-Array gehen, bis *words irgendwann NULL wird und derweil ein *words nach dem anderen zusammen mit dem gesuchten Wort strcmp vorlegen. Wenn strcmp die beiden Wörter für gleich hält, wird ein Zähler inkrementiert.

Dateien zu diesem Abschnitt


Markus Demleitner

Copyright Notice