Kapitel 9

Alle Codedateien dieses Kapitels herunterladen

09_6_1_WieVielByte.cpp

Datei herunterladen

/*
 * Lösung für Übung 9.6.1 - Wie viel Byte
 *
 * Für die Lösung mussten Sie keinen Code schreiben. Hier
 * folgt die ausgefüllte Tabelle, unten ist etwas Testcode dafür
 *
 *      Element               | Speicherbedarf      |       Erklärung
 * ================================================================================================
 *  int a = 17;               | 4 Byte              |
 * ------------------------------------------------------------------------------------------------
 *  size_t b = 17;            | 8 Byte              | size_t ist für größere Zahlen bestimmt
 * ------------------------------------------------------------------------------------------------
 *  std::string c = "Hola";   | 29 Byte (mindestens)| 24 Byte für den leeren String (8 für den
 *                            |                     | Zeiger, 8 für die Puffergröße, 8 für die Länge)
 *                            |                     | + 4 Zeichen + 1 End-Of-String Zeichen
 * ------------------------------------------------------------------------------------------------
 *  int* d = new int(17);     | 12 Byte             | 8 für den Zeiger, 4 für den int
 * ------------------------------------------------------------------------------------------------
 *  struct Test { int a; };   | 4 Byte              | 4 für den einzigen Member, das a
 * ------------------------------------------------------------------------------------------------
 *  bool e = false;           | 1 Bit / 1 Byte      | True oder False braucht nur ein einziges Bit,
 *                            |                     | Wenn Sie also "1 Bit" geantwortet haben, ist das
 *                            |                     | richtig. In der Realität wird aber meistens wegen
 *                            |                     | technischer Besonderheiten ein ganzes Byte reserviert
 */
#include <iostream>

struct Test
{
  int a;
};

int main()
{
  int a = 17;
  std::cout << "int a = 17;\t\t" << sizeof(a) << std::endl;

  size_t b = 17;
  std::cout << "size_t b = 17;\t\t" << sizeof(b) << std::endl;

  std::string c = "Hola";
  // Hinweis: sizeof(std::string) ist implementationsabhängig.
  // Für Fortgeschrittene gibt es hier eine ausgiebige Betrachtung: https://shaharmike.com/cpp/std-string/
  std::cout << "std::string c = \"Hola\";\t" << (24 + 4 + 1) << std::endl;

  int* d = new int(17);
  std::cout << "int* d = new int(17);\t" << sizeof(d) + sizeof(*d) << std::endl;
  delete d;

  std::cout << "struct Test { int a; };\t" << sizeof(Test) << std::endl;

  bool e = false;
  std::cout << "bool e = false;\t" << sizeof(e) << std::endl;

  return 0;
}

09_6_2_Zeigerfehler.cpp

Datei herunterladen

/*
 * Lösung für Übung 9.6.2 - Zeigerfehler
 * Diese Datei enthält drei Teile:
 * - Den auskommentierten fehlerhaften Code
 * - Eine Korrektur mittels normaler Zeiger
 * - Eine Korrektur mit Smart Pointern
 */
#include <iostream>
#include <string>
#include <memory>

int main()
{
  /* FEHLERHAFTER CODE:
  
  std::string* stringPointer;
  bool* consoleOutput = new bool(false);
  int* intPointer = new int(0);
  if (consoleOutput)
  {
    std::cout << "consoleOutput ist wahr" << std::endl;
  }
  intPointer = 17;
  if (intPointer + 1 == 18)
  {
    bool otherValue = true;
    std::cout << "Diese Ausgabe sollte kommen";
    consoleOutput = &otherValue;
  }
  delete stringPointer;
  delete intPointer;

  */

  // Korrektur ohne Smart Pointer:
  {
    // Der Pointer war nicht auf nullptr initialisiert!
    // Das "delete stringPointer" später hätte zu einem riesen Problem geführt.
    // Völlig zufälliger Speicher wäre freigegeben worden
    std::string* stringPointer = nullptr;
    bool* consoleOutput = new bool(false);
    int* intPointer = new int(0);
    // Das Dereferenzieren (Sternchen) wurde vergessen. Ohne das Sternchen
    // war der Vergleich gleichbedeutend mit if (consoleOutput != nullptr) , was definitiv
    // nicht der hier beabsichtigte Vergleich war
    if (*consoleOutput)
    {
      std::cout << "consoleOutput ist wahr" << std::endl;
    }
    // Das Dereferenzieren des Zeigers wurde vergessen
    *intPointer = 17;
    // Hier ebenfalls.
    if (*intPointer + 1 == 18)
    {
      // Spitzfindigerweise könnte man sagen, hier fehle noch das std::endl. Ist aber nicht so wichtig.
      std::cout << "Diese Ausgabe sollte kommen" << std::endl;
      // Hier gab es zwei Probleme: Erstens wurde der Zeiger consoleOutput auf die Variable
      // otherValue umgebogen, die aber nach Verlassen des Bereichs ungültig wurde.
      // Zweitens muss vor dem Umbiegen des Zeigers auf einen neuen Speicherbereich der alte
      // erst mit delete aufgeräumt werden. Hier wurde das gemacht und danach dann mit new
      // ein neuer Speicherbereich belegt
      delete consoleOutput;
      consoleOutput = new bool(true);
    }
    // Das Aufräumen von consoleOutput fehlte
    delete intPointer;
    delete consoleOutput;
    // stringPointer ist zwar das ganze Programm hindurch nullptr geblieben,
    // zur Sicherheit räumen wir es aber trotzdem auf.
    delete stringPointer;
  }

  // Korrektur: mit Smart Pointern
  {
    std::shared_ptr<std::string> stringPointer;
    std::shared_ptr<bool> consoleOutput = std::make_shared<bool>(false);
    std::shared_ptr<int> intPointer = std::make_shared<int>(0);
    if (*consoleOutput)
    {
      std::cout << "consoleOutput ist wahr" << std::endl;
    }
    *intPointer = 17;
    if (*intPointer + 1 == 18)
    {
      std::cout << "Diese Ausgabe sollte kommen" << std::endl;
      // Kein vorheriges delete notwendig - wird automatisch erledigt.
      consoleOutput = std::make_shared<bool>(true);
    }
    // Keine delete Anweisungen notwendig - wird automatisch erledigt.
  }

  return 0;
}

09_6_3_Wiederholungstaeter.cpp

Datei herunterladen

/*
 * Lösung für Übung 9.6.3 - Wiederholungstäter
 *
 * - Sie können das einzelne Zeichen natürlich auch in ein
 *   char abspeichern, aber std::string ist einfacher zu benutzen.
 * - Sie können auch eine while(true)-Schleife verwenden, die im Falle
 *   einer korrekten Eingabe mit break; verlassen wird.
 */
#include <exception>
#include <iostream>
#include <string>

int main()
{
  std::string oneCharacter;
  bool inputMissing = true;
  while (inputMissing)
  {
    std::cout << "Geben Sie ein Zeichen ein: ";
    std::getline(std::cin, oneCharacter);
    inputMissing = (oneCharacter.size() != 1);
    if (inputMissing)
    {
      // Hier sollten Sie keinen Fehler mit throw schmeißen sondern schlicht
      // nach einer neuen Eingabe fragen.
      std::cerr << "Sie haben mehr als ein Zeichen eingegeben!" << std::endl;
    }
  }

  int number = 0;
  inputMissing = true;
  while (inputMissing)
  {
    std::cout << "Geben Sie die Anzahl von Wiederholungen ein: ";
    std::string input;
    std::getline(std::cin, input);
    try
    {
      number = std::stoi(input);
      inputMissing = false;
    }
    catch (std::exception& ex)
    {
      std::cerr << "Keine g\201ltige Zahl eingegeben!" << std::endl;
    }
  }
  for (int i = 0; i < number; i++)
  {
    std::cout << oneCharacter;
  }
  return 0;
}

09_6_4_DeklarationenUndDefinitionen

Plant.cpp

Datei herunterladen

/*
 * Lösung für Übung 9.6.4 - Deklarationen und Definitionen
 *
 * Die hinzugefügten Zeilen sind mit ## markiert
 */
#include <iostream>
#include "Plant.h"  // ## Fehlte in der Aufgabenstellung ##

// ## Fehlte in der Aufgabenstellung ##
Plant::Plant(const std::string& name)
  : name(name)
{
}

// ## Fehlte in der Aufgabenstellung ##
std::string Plant::getName() const
{
  return name;
}

void Plant::water()
{
  moisture++;
}

int main()
{
  Plant tulip("Tulpe");
  std::cout << tulip.getName() << std::endl;
  tulip.water();
  return 0;
}

Plant.h

Datei herunterladen

#pragma once  // ## Fehlte in der Aufgabenstellung ##
#include <string>

class Plant
{
 public:
  Plant(const std::string& name);
  std::string getName() const;
  void water();  // ## Fehlte in der Aufgabenstellung ##
 private:
  const std::string name;
  int moisture = 0;
};