← Startseite
📊

Vorlesung 7

Arrays & Strings
Viele Werte in einer Variablen — und Texte als Zeichenketten

Grundlagen der Programmierung
Prof. Dr. Alexandra Mikityuk
HTW Berlin

Arrays Strings string.h

Lernziele

  • Verstehen, warum Arrays existieren — und welche Probleme sie lösen
  • Arrays deklarieren, initialisieren und auf Elemente zugreifen (Index!)
  • Arrays mit Schleifen durchlaufen — die Standard-Kombination
  • Verstehen, dass Strings einfach char-Arrays sind — mit einem Trick (Null-Terminator)
  • Die wichtigsten Funktionen aus <string.h> kennen: strlen, strcpy, strcat, strcmp
  • Die typischen Fallen erkennen: Off-by-One, Buffer-Overflow, fehlende '\0'

Wozu brauchen wir Arrays?

Stellt euch vor, ihr sollt die Noten von 30 Studierenden speichern — ohne Arrays:

đŸ˜€ Ohne Array

int note1, note2, note3,
    note4, note5, note6,
    // ... 24 mehr ...
    note30;

30 Variablen. Durchschnitt berechnen? 30 Additionen einzeln tippen. Niemand macht das.

✹ Mit Array

int noten[30];   // eine Zeile!

for (int i=0; i<30; i++) {
    summe += noten[i];
}

Eine Zeile fĂŒr die Deklaration. Schleife lĂ€uft drĂŒber. Skaliert auf 30 oder 30 000 — egal.

Definition: ein Array ist eine Sammlung gleichartiger Werte unter einem Namen. Statt 30 einzelne Variablen hast du eine Variable mit 30 „Schubladen".

Array — die Idee visualisiert

Ein Array ist eine Reihe von Zellen — alle vom gleichen Typ. Jede Zelle hat einen Index (Position), beginnend bei 0.

int noten[5] = {2, 1, 3, 2, 4};
2
1
3
2
4
01234

← Indizes (Positionen) →

Wichtig — Indizes starten bei 0! Bei einem Array mit n Elementen sind die gĂŒltigen Indizes 0 bis n-1 — nicht 1 bis n. Bei noten[5] wĂ€re Index 5 außerhalb — gefĂ€hrlich!
Warum 0? Aus historischen GrĂŒnden (Index = Speicher-Offset vom Anfang). Mathematisch ist es auch praktisch: „i-tes Element" kann man als „i Schritte vom Anfang" lesen — und 0 Schritte = der Anfang selbst.

Arrays deklarieren

Drei Teile: Typ, Name, GrĂ¶ĂŸe in eckigen Klammern.

int noten[5];        // 5 Ganzzahlen — leer (MĂŒll-Werte!)

double preise[10];   // 10 Fließkommazahlen

char wort[20];       // 20 Zeichen — also ein String
Achtung: nach der Deklaration enthĂ€lt das Array MĂŒll-Werte (zufĂ€llige Bytes aus dem Speicher). Bevor man liest, muss man schreiben — entweder direkt mit Initialisierung, oder per Schleife mit Werten fĂŒllen.
GrĂ¶ĂŸe ist fest: int noten[5]; reserviert fĂŒr immer Platz fĂŒr genau 5 Werte. GrĂ¶ĂŸere Mengen brauchen ein grĂ¶ĂŸeres Array — oder dynamischen Speicher (kommt spĂ€ter).

Arrays initialisieren

Werte direkt bei der Deklaration setzen — spart die spĂ€tere Schleife.

📝 Mit konkreten Werten

int noten[5] = {2, 1, 3, 2, 4};
double preise[3] = {1.99, 2.50, 0.79};

Schreibst du weniger Werte als PlĂ€tze, werden die restlichen mit 0 gefĂŒllt.

0ïžâƒŁ Alles auf 0

int zaehler[10] = {0};   // alle 10 = 0

HĂ€ufig fĂŒr ZĂ€hler / Akkumulatoren. Klassischer Trick: ein {0} reicht, der Rest wird auch 0.

GrĂ¶ĂŸe automatisch: bei der Initialisierung kann man die GrĂ¶ĂŸe weglassen — der Compiler zĂ€hlt selbst:
int noten[] = {2, 1, 3, 2, 4};   // GrĂ¶ĂŸe wird zu 5

Auf Array-Elemente zugreifen

Mit name[index] — sowohl zum Lesen als auch zum Schreiben.

noten[]:
2
1
3
2
4
01234
// Lesen
int erste_note = noten[0];        // → 2
int dritte_note = noten[2];        // → 3

// Schreiben (Wert verÀndern)
noten[1] = 5;                       // 2. Element wird 5
noten[3] = noten[3] + 1;             // 4. Element um 1 erhöhen
Schreibweise: die eckigen Klammern werden hier zum Indexieren verwendet — bei der Deklaration zeigten sie die GrĂ¶ĂŸe. Gleiche Syntax, unterschiedliche Bedeutung je nach Kontext.

⚠ Off-by-One — der typische Array-Fehler

Bei einem Array der GrĂ¶ĂŸe n gibt es nur die Indizes 0 bis n-1. Index n liegt außerhalb!

int noten[5] — gĂŒltige Indizes:
2
1
3
2
4
❌
012345 ✗
Was passiert bei noten[5]? C prĂŒft nicht die Grenzen — das Programm liest oder ĂŒberschreibt einfach Speicher, der zu was anderem gehört. Möglicherweise Absturz, möglicherweise verfĂ€lschte Daten, möglicherweise eine SicherheitslĂŒcke. Immer selbst aufpassen.
Faustregel fĂŒr Schleifen ĂŒber Arrays:
for (int i = 0; i < n; i++) {     // '< n', NICHT '<= n'!
    ... noten[i] ...
}

Arrays + Schleifen = die Standard-Kombi

Mit einer for-Schleife lĂ€uft man alle Elemente einmal durch — das ist das Standardmuster.

đŸ–šïž Alle Elemente ausgeben

int noten[5] = {2, 1, 3, 2, 4};

for (int i = 0; i < 5; i++) {
    printf("%d ", noten[i]);
}
// Ausgabe: 2 1 3 2 4

⌚ Alle Elemente einlesen

int noten[5];

for (int i = 0; i < 5; i++) {
    printf("Note %d: ", i+1);
    scanf("%d", &noten[i]);
}
Merke: der SchleifenzĂ€hler i ist gleichzeitig der Index ins Array. Bei scanf brauchst du &noten[i] — die Adresse des einzelnen Elements.

Beispiel: Notendurchschnitt

#include <stdio.h>

int main(void) {
    int noten[5] = {2, 1, 3, 2, 4};
    int summe = 0;

    for (int i = 0; i < 5; i++) {
        summe = summe + noten[i];
    }

    double schnitt = (double)summe / 5;   // Cast nötig fĂŒr Float-Division
    printf("Durchschnitt: %.2f\n", schnitt);   // → 2.40

    return 0;
}
Achtung — der Cast (double) ist wichtig: ohne ihn wĂ€re 12 / 5 eine Ganzzahl-Division → Ergebnis 2 (nicht 2.4). Der Cast zwingt eine Operand auf double, dann wird mit Fließkomma gerechnet.

Strings: Arrays von Zeichen

Ein String in C ist nichts Besonderes — es ist einfach ein char-Array, das mit einem Null-Zeichen '\0' endet.

char wort[6] = "Hallo";
'H'
'a'
'l'
'l'
'o'
'\0'
012345

← 5 Buchstaben + 1 Null-Terminator = 6 PlĂ€tze →

Warum das '\0'? C-Strings haben keine gespeicherte LĂ€nge — die Funktionen lesen einfach Zeichen fĂŒr Zeichen, bis sie das '\0' finden. Ohne '\0' wĂŒssten sie nicht, wo der String endet → sie wĂŒrden in fremden Speicher weiterlesen.
Praktische Konsequenz: ein Wort mit n Buchstaben braucht ein Array der GrĂ¶ĂŸe n + 1 — Platz fĂŒr den Terminator.

Strings initialisieren

📝 Mit String-Literal

char name[10] = "Anna";

Der Compiler hÀngt automatisch das '\0' an. Hier: A, n, n, a, \0, dann 5 PlÀtze ungenutzt.

🔱 Zeichen fĂŒr Zeichen

char name[5] = {
    'A', 'n', 'n', 'a', '\0'
};

Funktioniert auch — aber selten genutzt. Achtung: das '\0' muss man hier selbst setzen.

GrĂ¶ĂŸe großzĂŒgig wĂ€hlen: mach dein String-Array grĂ¶ĂŸer als gerade nötig — z.B. char name[50]; auch wenn der Name kurz ist. Sonst lĂ€uft die Eingabe ĂŒber und das Programm stĂŒrzt ab (Buffer-Overflow).

Strings ein- und ausgeben

char name[50];

// Eingabe — mit %s, OHNE & vor name (Arrays sind schon „Adresse")
printf("Wie heißt du? ");
scanf("%s", name);

// Ausgabe — auch %s
printf("Hallo, %s!\n", name);
scanf("%s", ...) hat zwei SchwÀchen:
  • liest nur bis zum ersten Leerzeichen — „Anna MĂŒller" wird nur als „Anna" gelesen
  • keine LĂ€ngen-PrĂŒfung — bei zu langer Eingabe gibt's Buffer-Overflow
Sicher mit fgets:
fgets(name, 50, stdin);   // liest bis zu 49 Zeichen + '\0'
Liest eine ganze Zeile inklusive Leerzeichen — und garantiert, dass die Array-GrĂ¶ĂŸe nicht ĂŒberschritten wird.

Die String-Bibliothek <string.h>

Vier Funktionen, die ihr fast immer braucht:

FunktionMacht was?Beispiel
strlen(s)LĂ€nge des Strings (ohne '\0')strlen("Anna") == 4
strcpy(ziel, src)String kopierenstrcpy(name, "Anna")
strcat(ziel, src)String anhĂ€ngenstrcat(gruss, " MĂŒller")
strcmp(s1, s2)vergleichen — 0 wenn gleichstrcmp("abc","abc") == 0
Wichtig: Strings vergleicht man nicht mit ==! name == "Anna" vergleicht Adressen, nicht Inhalt. Immer strcmp(name, "Anna") == 0 benutzen.

Beispiel: BegrĂŒĂŸungs-Programm

#include <stdio.h>
#include <string.h>

int main(void) {
    char name[50];
    char gruss[100] = "Hallo, ";

    printf("Dein Name: ");
    scanf("%s", name);

    strcat(gruss, name);          // gruss = "Hallo, " + name
    strcat(gruss, "!");

    printf("%s\n", gruss);            // → "Hallo, Anna!"
    printf("(LĂ€nge: %lu)\n", strlen(gruss));

    return 0;
}
Wichtige Punkte:
  • gruss muss groß genug sein, um „Hallo, " + Name + „!" aufzunehmen — daher 100
  • strcat hĂ€ngt am Ende an — das '\0' wird automatisch versetzt

Bonus: 2D-Arrays

Ein Array von Arrays — z.B. eine Tabelle, ein Schachbrett, eine Matrix.

int brett[3][3] = {
    {1, 2, 3},     // Zeile 0
    {4, 5, 6},     // Zeile 1
    {7, 8, 9}      // Zeile 2
};

// Zugriff: [Zeile][Spalte]
int mitte = brett[1][1];      // → 5
Durchlaufen mit zwei verschachtelten Schleifen:
for (int z = 0; z < 3; z++)
    for (int s = 0; s < 3; s++)
        printf("%d ", brett[z][s]);

⚠ Die hĂ€ufigsten Array-/String-Fehler

1ïžâƒŁ Off-by-One

int a[5];
for (int i=0; i<=5; i++)
    a[i] = 0;   // ✗ i=5 illegal!

Lösung: i < 5 statt i <= 5.

2ïžâƒŁ '\0' vergessen

char s[4] = {'A','n','n','a'};
printf("%s", s);  // liest weiter
              // → MĂŒll am Ende

Lösung: Array um 1 grĂ¶ĂŸer, '\0' anhĂ€ngen.

3ïžâƒŁ Buffer-Overflow

char name[5];
scanf("%s", name);
// User tippt "Christian"
// → ĂŒberschreibt fremden Speicher

Lösung: Array groß genug + fgets().

Bonus-Falle: Strings mit == vergleichen funktioniert nicht. Es vergleicht Adressen, nicht Inhalte. Immer strcmp nutzen!

đŸ€” Mini-Quiz

Welche der folgenden Zeilen ist fehlerhaft?

int werte[10];

werte[0] = 1;                            (A)
werte[9] = 9;                            (B)
werte[10] = 10;                          (C)
for (int i=0; i<10; i++) werte[i] = 0;   (D)
A) erste Zeile
B) zweite Zeile
C) dritte Zeile
D) vierte Zeile
Warum C? Das Array hat 10 Elemente → gĂŒltige Indizes sind 0 bis 9. Index 10 liegt außerhalb — Off-by-One-Fehler. C erkennt das nicht, das Programm ĂŒberschreibt Fremd-Speicher.

Zusammenfassung

  • Arrays = viele gleichartige Werte unter einem Namen, fest in GrĂ¶ĂŸe, indiziert ab 0.
  • Zugriff mit name[index] — Index 0 bis n-1, NIE name[n].
  • Schleife + Array ist das Standard-Muster fĂŒr „mach was mit allen Elementen".
  • Strings sind char-Arrays mit '\0' am Ende — daher braucht ein 5-Buchstaben-Wort 6 PlĂ€tze.
  • <string.h> liefert strlen, strcpy, strcat, strcmp — vier Funktionen, die ihr immer wieder brauchen werdet.
  • Die Top-Fallen: Off-by-One, fehlendes '\0', Buffer-Overflow, Strings mit == vergleichen.

📚 Übung & Hausaufgabe

Lab 6 (im Anschluss)

Arrays + Funktionen kombinieren: ein Array einlesen, Maximum/Minimum finden, Durchschnitt rechnen, sortieren-light.

Hausaufgabe bis nÀchste Woche

  • Notenrechner: liest 10 Noten in ein Array ein und gibt Durchschnitt + beste + schlechteste Note aus.
  • Palindrom-Check: lies einen String mit fgets ein und prĂŒfe, ob er vorwĂ€rts und rĂŒckwĂ€rts gleich gelesen wird (z.B. „anna").
  • Bonus: implementiere strlen selbst — also eine Funktion, die zĂ€hlt, wie viele Zeichen vor dem '\0' stehen.

Vorblick: nÀchste Vorlesung

In Vorlesung 8 kommt der nĂ€chste große Baustein: Funktionen.

  • Eigene Funktionen schreiben (statt alles in main)
  • Parameter ĂŒbergeben — auch Arrays!
  • Werte zurĂŒckgeben
  • Code strukturieren und wiederverwenden
Spoiler: mit Funktionen werden eure Programme um GrĂ¶ĂŸenordnungen ĂŒbersichtlicher. Bisher war jedes Programm „alles in main" — das Ă€ndert sich.

Vielen Dank!

Fragen?

Prof. Dr. Alexandra Mikityuk

HTW Berlin · BĂŒro Raum 308

Tel +49 30 5019-2664

NĂ€chste Woche: Funktionen — Code modular gestalten

1 /