C++ Tutorial

 Felder und C-Strings

Felder

Feld-Definition

Um mehrere zusammengehörige Daten eines Datentyps abzuspeichern, werden Felder verwendet. Ein Feld wird wie folgt definiert:

DTYP name[SIZE];

DTYP definiert den Datentyp der im Feld abzulegenden Daten und name ist der Name des Feldes. Danach folgt in eckigen Klammern die Feldgröße SIZE. Sie definiert die maximale Anzahl der Daten, die im Feld abgelegt werden können. SIZE muss eine zur Compilezeit berechenbare ganzzahlige Konstante sein.

int intArray[10];     // Feld fuer 10 int-Daten
constexpr int SIZE = 80;
char line[SIZE];    // Feld fuer 80 Zeichen

Außer eindimensionale Felder können auch mehrdimensionale Felder definiert werden. Dabei werden die einzelnen Dimensionen unmittelbar hintereinander jeweils in einer eckigen Klammer aufgeführt.

short table[2][3];  // short-Feld fuer 2x3 short-Daten

Felder können bei ihrer Definition mit Daten initialisiert werden. Dabei folgt nach der eckigen Klammer für die Feldgröße eine geschweifte Klammer und innerhalb dieser werden die Daten, durch Komma getrennt, aufgelistet. Soll das Feld genau so groß dimensioniert werden, dass die aufgelisteten Daten abgelegt werden können, kann die Angabe der Feldgröße bei eindimensionalen Felder entfallen. In diesem Fall ist nur die leere eckige Klammer anzugeben.

int intArray[5] {1,2,3,4,5};   // int-Feld mit 5 Elemente definieren/initialisieren
char text[] {'a','b','c'};     // char-Feld mit 3 Elemente definieren/initialisieren

Zugriff auf Feldelemente

Um auf ein Feldelement zuzugreifen, wird zuerst der Feldname angegeben, gefolgt von einer eckigen Klammer. Innerhalb der Klammer steht der Index des Feldelements, auf das zugegriffen wird, wobei das erste Element den Index 0 besitzt und das letzte Element demzufolge den Index SIZE-1. Bei mehrdimensionalen Feldern werden entsprechend mehrere Indizes hintereinander angegeben.

#include <iostream>

#include <format>

int main()
{
   // Eindimensionales char-Feld definieren
   constexpr int CSIZE=5;
   char alpha[CSIZE];
   // 2-dimensionales int-Feld definieren
   constexpr int ROW=2, COL=3;
   int table[ROW][COL];

   // char-Feld mit Buchstaben fuellen
   // beginnend mit dem Buchstaben A
   char buchst='A';
   for (int index=0; index<CSIZE; index++)
      alpha[index]=buchst++;

   // 2-dimensionales Feld befuellen
   for (int arow=0; arow<ROW; arow++)
      for (int acol=0; acol<COL; acol++)
         table[arow][acol] = arow*10+acol;

   // char-Feld ausgeben
   for (int index=0; index<CSIZE; index++)
      std::cout << std::format("{}, ",alpha[index]);
   std::cout << "\n\n";

   // 2-dimensionale Feld ausgeben
   for (int arow=0; arow<ROW; arow++)
   {
      for (int acol=0; acol<COL; acol++)
         std::cout << std::format("{:3}, ",table[arow][acol]);
      std::cout << '\n';
   }
}

Anstelle des indizierten Zugriffs kann auf die Elemente in einem eindimensionalen Feld auch mittels eines Zeigers zugegriffen werden. Der Zeiger muss dann den gleichen Datentyp wie das Feld besitzen. Um in einem Zeiger die Adresse eines Feldelements abzulegen, wird rechts vom Zuweisungsoperator der Adressoperator gefolgt vom Feldelement angegeben, z.B. ptr = &array[3];. Eine Sonderstellung nimmt dabei der Verweis auf den Beginn eines eindimensionalen Feldes ein. In diesem Fall genügt die alleinige Angabe des Feldnamens (ptr = array;).

int intArray[10]; // Feld fuer 10 int-Daten
char line[80];    // Feld fuer 80 Zeichen

int main()
{
   int *intPtr = &intArray[4];   // Zeiger auf 5. Element
   char *charPtr = line;         // Zeiger auf 1. Element (Feldanfang)
}

Der Zugriff auf mehrdimensionale Felder mittels Zeiger ist etwas komplizierter (Zeiger auf Feld mit Zeigern!) und soll an dieser Stelle nicht weiter betrachtet werden. Mehr dazu erfahren Sie im Internet unter ' c++ pointer multidimensional array' oder in meinem Buch.

C-Strings und Felder

Für C-Strings wurden bisher stets Literale verwendet. Ein solcher C-String kann auch in einem Feld abgelegt werden und da C-Strings in der Regel aus 1 Byte großen ASCII-Zeichen bestehen, sind sie in einem char-Feld abzulegen.

Ein char-Feld kann bei seiner Definition mit einem C-String initialisiert werden, so wie nachfolgend dargestellt.

char myText[] {"C-String"};

Das char-Feld wird dann so groß dimensioniert, dass der C-String, einschließlich der abschließenden 0, darin Platz findet.

Um einen C-String in ein char-Feld zu kopieren wird die Funktion

strcpy_s(pDest, maxcopy, pSource);

verwendet. pDest ist ein char-Zeiger auf den Speicherbereich, in den der durch pSource adressierte C-String kopiert wird und maxcopy bestimmt die maximale Anzahl der zu kopierenden Zeichen. maxcopy muss größer als "Länge des zu kopierenden C-Strings+1" sein und die Bereiche von pDest und pSource dürfen sich nicht überlappen.

Wird strcpy_s() verwendet, ist die Header-Datei <cstring> einzubinden.

constexpr int SIZE=80;
char text[SIZE];
strcpy_s(text,SIZE,"Hallo!");

Die Funktion

auto len = strlen(pString);

liefert die Anzahl der Zeichen im C-String auf den der char-Zeiger pString verweist. Auch hierfür ist die Header-Datei <cstring> einzubinden.

// Umwandlung von Kleinbuchstaben in Grossbuchstaben

#include <iostream>
#include <format>

int main()
{
   // char-Feld definieren und mit C-String belegen
   char alpha[] {"Dies ist ein C-String"};

   // Alle Buchstaben durchlaufen
   for (size_t index=0; index<std::strlen(alpha); index++)
   {
      // Wenn Kleinbuchstabe gefunden, 0x20 subtrahieren
      // z.B. a=0x61 -> A=0x41
      if ((alpha[index]>='a') && (alpha[index]<='z'))
         alpha[index] -= 0x20;
   }

   // Gewandelten C-String ausgeben
   std::cout << std::format("String in Grossbuchstaben: {}\n",alpha);
}

range-for-Schleife

Zum sequentiellen Durchlaufen u.a. eines Feldes stellt C++ eine besondere Schleife zur Verfügung, die range-for-Schleife. Sie hat folgende Syntax:

for ([INIT;] DTYP var: array)
   ANWEISUNG;

Alle Feldelemente des Feldes array werden nacheinander in var abgelegt und dabei die Anweisung ANWEISUNG ausgeführt. Hierbei muss DTYP mit dem Datentyp des Feldes übereinstimmen oder sich in diesen konvertieren lassen. Am einfachsten erfolgt die Definition des Datentyps mittels auto. Soll der Inhalt des Feldelements innerhalb der Schleife verändert werden, ist für var eine entsprechende Referenzvariable einzusetzen.

Sollen mehrere Anweisungen ausgeführt werden, sind diese wieder in einem Block {...} einzuschließen.

int intArray[] {1,2,3,4};
for (auto elem: intArray)
{
   std::cout << elem << ',';
}

#include <iostream>
#include <format>

// Definition der Konstanten für die Feldgrösse
constexpr auto ZEILEN = 10;
constexpr auto SPALTEN = 10;
// Tabelle definieren
int tabelle[ZEILEN][SPALTEN];

int main()
{
   // Tabelle mit Zufallszahlen fuellen
   for (auto& zeile : tabelle)
      for (auto& elem : zeile)
         elem = std::rand() % 10;
   // Hilfsfeld für Spaltensummen anlegen und mit 0 initialisieren
   int spaltenSumme[SPALTEN]{};
   // Alle Zeilen durchlaufen
   for (auto& zeile : tabelle)
   {
      // Zeilensumme auf 0 setzen
      auto zeilenSumme = 0;
      // Alle Spalten der akt. Zeile durchlaufen
      for (auto spalte = 0; auto elem: zeile)
      {
         // Tabellenwert ausgeben
         std::cout << std::format("{:4}", elem);
         // Zeilensumme aktualisieren
         zeilenSumme += elem;
         // Spaltensumme aktualisieren
         spaltenSumme[spalte++] += elem;
      }
      // Zeilensumme ausgeben
      std::cout << std::format(" : {:4}\n", zeilenSumme);
   }
   // Zum Schluss Spaltensummen ausgeben
   std::cout << "------------------------------------------\n";
   for (auto element : spaltenSumme)
      std::cout << std::format("{:4}", element);
   std::cout << '\n';
}