\documentclass[a4paper, fontsize = 8pt, landscape]{scrartcl} \usepackage[german]{babel} \usepackage[landscape, margin=0.5cm]{geometry} \usepackage[dvipsnames]{xcolor} % Hyperref links, pdf metadata \usepackage{hyperref} \usepackage{amscd, amsmath, amssymb, blindtext, empheq, enumitem, multicol} \usepackage{mathtools} \usepackage{graphicx} \usepackage{tikz} \usepackage{array} %for bigger tabular spacings \usepackage{multirow} % for multirow cells in tabular %% Formal tables \usepackage{booktabs} %% Colorbox \usepackage[most]{tcolorbox} % make document compact \parindent 0pt \pagestyle{empty} \setlength{\unitlength}{1cm} \setlist{leftmargin = *} % define some colors \definecolor{title}{RGB}{229,140,140} \definecolor{subtitle}{RGB}{234,165,165} \definecolor{subsubtitle}{RGB}{249,210,210} \definecolor{text}{RGB}{0,0,0} \definecolor{formulabox}{RGB}{182,225,189} % section color box \setkomafont{section}{\mysection} \newcommand{\mysection}[1]{\vspace*{-3pt}% Space before Box \Large\normalfont \sffamily \bfseries% \setlength{\fboxsep}{0cm}%already boxed \colorbox{title}{% \begin{minipage}{\linewidth}% \vspace*{2pt}%Space before \leftskip2pt %Space left \rightskip\leftskip %Space right {\color{text} #1} \vspace*{1pt}%Space after \end{minipage}% }} %subsection color box \setkomafont{subsection}{\mysubsection} \newcommand{\mysubsection}[1]{\vspace*{-3pt}% Space before Box \normalsize \normalfont \sffamily \bfseries% \setlength{\fboxsep}{0cm}%already boxed \colorbox{subtitle}{% \begin{minipage}{\linewidth}% \vspace*{2pt}%Space before \leftskip2pt %Space left \rightskip\leftskip %Space right {\color{text} #1} \vspace*{1pt}%Space after \end{minipage}% }} %subsubsection color box \setkomafont{subsubsection}{\mysubsubsection} \newcommand{\mysubsubsection}[1]{\vspace*{-5pt}% Space before Box \normalsize \normalfont \sffamily % \setlength{\fboxsep}{0cm}%already boxed \colorbox{subsubtitle}{% \begin{minipage}{\linewidth}% \vspace*{2pt}%Space before \leftskip2pt %Space left \rightskip\leftskip %Space right {\color{text} #1} \vspace*{1pt}%Space after \end{minipage}% }} % equation box \newcommand{\eqbox}[1]{\fcolorbox{black}{white}{#1}} %For tables orientation WIHT linebreaks \newcolumntype{L}[1]{>{\raggedright\let\newline\\\arraybackslash\hspace{0pt}}m{#1}} \newcolumntype{C}[1]{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}m{#1}} \newcolumntype{R}[1]{>{\raggedleft\let\newline\\\arraybackslash\hspace{0pt}}m{#1}} %code snippet \newcommand{\code}[1]{\texttt{#1}} \begin{document} \setcounter{secnumdepth}{0} %no enumeration of sections \begin{multicols*}{3} \begin{center} \Large{Informatik I} \\ \tiny{von P.Bölsterli, Fehler bitte an \href{mailto:pbolsterli@student.ethz.ch}{pbolsterli@student.ethz.ch}} \end{center} \section{Basics} \begin{center} \begin{minipage}{0.34 \linewidth} \begin{center} \eqbox{\begin{tabular}{l} \code{int main()} \{ \\ \code{\quad Programm} \\ \} \\ \end{tabular}} \end{center} \end{minipage} \begin{minipage}{0.65 \linewidth} \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{r l} \toprule \multicolumn{2}{l}{\textbf{Ein- und Ausgabe}: } \\ \midrule Bibliothek: & \hspace*{-10pt} \code{\#include } \\ Eingabe: & \hspace*{-10pt} \code{std::cin >> var;} \\ Ausgabe: & \hspace*{-10pt} \code{std::cout << "Yeet} $\backslash$\code{n";} \\ \bottomrule \end{tabular} \end{center} \end{minipage} \end{center} \subsection{Variablen} \begin{center} \begin{minipage}{0.49 \linewidth} \begin{center} \begin{tabular}{r l} \toprule Name: & \hspace*{-10pt} ree \\ Typ: & \hspace*{-10pt} int \\ Wert: & \hspace*{-10pt} i) undefiniert \\ & \hspace*{-10pt} ii) 10 \\ Adresse: & \hspace*{-10pt} bestimmt Compiler \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.5 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} Deklaration: & \code{int ree;} \\ Definition: & \code{int ree = 10;} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsubsection{Konstanten} Konstanten sind Variablen mit unveränderbarem Wert. \begin{center} \begin{minipage}{0.49 \linewidth} \begin{center} \textbf{Präfix}: \code{const} \end{center} \end{minipage} \begin{minipage}{0.5 \linewidth} \begin{center} \eqbox{\code{const int c = 3e+8;}} \end{center} \end{minipage} \end{center} \emph{const-Richtlinie}: Wenn eine Variable im Verlauf des Programmes seinen Wert nie ändert, dann sollte sie als Konstante definiert sein. \subsection{Fundamentale Datentypen} \begin{center} \begin{tabular} {l l c l} \toprule \textbf{Typ} & \textbf{Was} & \textbf{Werte} & \textbf{Bits} \\ \midrule \code{double} & Approximiert $\mathbb{R}$ & $F^*(2,53, -1022,1023)$ & 64 \\ \code{float} & Approximiert $\mathbb{R}$ & $F^*(2,24,-126,127)$ & 32 \\ \code{unsigned int} & Natürliche Zahlen & 0 bis $ 2^{32}-1$ & 32 \\ \code{int} & Ganze Zahlen & $-2^{31}$ bis $2^{31}-1$ & 32 \\ \code{bool} & Wahrheitswerte & true (1) oder false (0) & 8 \\ \hline \code {char} & Zeichen (ASCII) & 0 bis 255 & 8 \\ \bottomrule \end{tabular} \end{center} Arithmetische Operationen: Gemischte Ausdrücke sind vom ''allgemeineren'' Typ (in der Tabelle der höhere Typ). \medskip Konverter von Zahlen in ASCII (typ char) zum Typ int: x - '0' \subsubsection{Über- und Unterlauf} i) Über-/Unterlauf mit Typ \emph{int} sind undefiniertes Verhalten, d.h. keine Fehlermeldungen, keine Garantien für das Ergebnis. \medskip ii) Mit Typ \emph{unsigned int} sind Über-/Unterlauf klar definiert, durch Rechnung modulo $2^B$ - 1. Beispiel: $0-1 =2^{32}-1$, bzw. $(2^{32} - 1) + 1 = 0$ \subsection{std::string} Der Typ für Zeichenketten ist std::string. Ein paar Basics: \begin{center} \begin{tabular}{r l} \toprule Bibliothek: & \code{\#include } \\ Initialisierung: & \code{std::string text = ''To'';} \\ Zugriff auf i-tes Zeichen: & \code{text.at(i);} \\ Konkatenieren: & \code{text += ''gether'';} \\ Länge abfragen: & \code{text.length();} \\ \bottomrule \end{tabular} \end{center} \vfill\null \columnbreak \subsection{Fliesskommazahlen} Fliesskommazahlen besitzen 'Löcher' in ihrem Wertebereich, d.h. es wird immer auf die nächste darstellbare Zahl gerundet. \subsubsection{Normalisierte Darstellung} \begin{center} \begin{minipage}{0.55\linewidth} \begin{center} \begin{tabular}{r l} \toprule \textbf{$\beta$} & \hspace*{-10pt} Basis ($\beta \geq 2$) \\ \textbf{$p$} & \hspace*{-10pt} Präzision (Stellenanzahl) \\ \textbf{e$_{min}$} & \hspace*{-10pt} Kleinster mögliche Exponent \\ \textbf{e$_{max}$} & \hspace*{-10pt} Grösster mögliche Exponent \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.44 \linewidth} \begin{center} \renewcommand{\arraystretch}{1.5} \eqbox{\begin{tabular}{l} $F^*(\beta, p, e_{min}, e_{max}$) \\ $\pm d_0. d_1 \dots d_{p-1} \cdot \beta^e$ \\ \end{tabular}} $e \in \{e_{min}, \dots e_{max}\}, \, d_0 \neq 0$ \end{center} \end{minipage} \end{center} \begin{center} \includegraphics[width=0.9\linewidth]{Bilder/Floatingpoint.JPG} \end{center} \subsubsection{Fliesskomma-Richtlinien} i) Teste keine Fliesskommazahlen auf Gleichheit. ii) Addiere keine Fliesskommazahlen sehr unterschiedlicher Grösse. iii) Subtrahiere keine Fliesskommazahlen ähnlicher Grösse. \subsection{Literale} Literale besitzen einen festen Wert und Typ. Verschiedene Literale: \begin{center} \begin{tabular}{r l c r l} \toprule int: & \hspace*{-10pt} 10 & \hspace*{+10pt} & double: & \hspace*{-10pt} 20.0 \\ unsigned int: & \hspace*{-10pt} 10u & \hspace*{+10pt} & float: & \hspace*{-10pt} 20.0f \\ char: & \hspace*{-10pt} 'a' & \hspace*{+10pt} & string: & \hspace*{-10pt} ''Help me'' \\ \bottomrule \end{tabular} \end{center} \subsubsection{Verschiedene Zahlendarstellungen} \begin{center} \begin{minipage}{0.49 \linewidth} \begin{center} \begin{tabular}{r l} \toprule \multicolumn{2}{l}{\textbf{Präfixe}:} \\ \midrule Hexadezimal: & \hspace*{-10pt} \code{0x} \\ Oktal: & \hspace*{-10pt} \code{0} \\ Binär: & \hspace*{-10pt} \code{0b} \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.5 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} Dezimal: & \code{255} \\ Hexadezimal: & \code{0xff} \\ Oktal: & \code{0377} \\ Binär: & \code{0b11111111} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsection{L-Wert und R-Wert} \begin{center} \begin{minipage}{0.49 \linewidth} \begin{center} \begin{tabular}{r l} \toprule \multicolumn{2}{l}{\textbf{L-Wert}:} \\ \midrule i) & \hspace*{-10pt} besitzt Adresse \\ ii) & \hspace*{-10pt} Wert veränderbar \\ iii) & \hspace*{-10pt} Bsp: Variablen \\ \bottomrule \end{tabular} \end{center} \textbf{L}inks vom Zuweisungsoperator. \end{minipage} \begin{minipage}{0.5 \linewidth} \begin{center} \begin{tabular}{r l} \toprule \multicolumn{2}{l}{\textbf{R-Wert:}} \\ \midrule i) & \hspace*{-10pt} besitzt \emph{keine Adresse} \\ ii) & \hspace*{-10pt} Wert konstant \\ iii) & \hspace*{-10pt} Bsp: Literale \\ \bottomrule \end{tabular} \end{center} \textbf{R}echts vom Zuweisungsoperator. \end{minipage} \end{center} \begin{center} \eqbox{L-Werte können als R-Werte benutzt werden, aber nicht umgekehrt!} \end{center} \subsection{Assertions} Assertions sind ein simples Tool um Laufzeitfehler aufzufangen. \begin{center} \begin{minipage}{0.49 \linewidth} \begin{center} \begin{tabular}{r p{0.75\linewidth}} \toprule 1: & \hspace*{-10pt} Assertions abschalten \\ 2: & \hspace*{-10pt} Bibliothek \\ 3: & \hspace*{-10pt} Programm wird angehalten, wenn \code{expr} nicht wahr ist. \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.5 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{\#define NDEBUG} \\ 2 & \code{\#include } \\ 3 & \code{assert(expr)}; \\ \end{tabular}} \end{center} \end{minipage} \end{center} \vfill\null \columnbreak \subsection{Operatoren} Die Auswertung erfolgt nach Präzedenz, beginnend mit Präzedenz 17! \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{l c c l l} \toprule \textbf{Operator} & \hspace*{-10pt} \textbf{Symbol} & \hspace*{-10pt} \textbf{Präz.} & \hspace*{-10pt} \textbf{Assoz.} & \hspace*{-10pt} \textbf{L/R-Werte} \\ \midrule \multicolumn{3}{l}{\textbf{Arithmetische Operatoren}} \\ \midrule Negation & \hspace*{-10pt} \code{-} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} R $\to$ R \\ Multiplikation & \hspace*{-10pt} \code{*} & \hspace*{-10pt} 14 & \hspace*{-10pt} rechts & \hspace*{-10pt} RxR $\to$ R \\ Division & \hspace*{-10pt} \code{/} & \hspace*{-10pt} 14 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Modulo & \hspace*{-10pt} \code{\%} & \hspace*{-10pt} 14 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Addition & \hspace*{-10pt} \code{+} & \hspace*{-10pt} 13 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Substraktion & \hspace*{-10pt} \code{-} & \hspace*{-10pt} 13 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Zuweisung & \hspace*{-10pt} \code{=} & \hspace*{-10pt} 4 & \hspace*{-10pt} rechts & \hspace*{-10pt} R $\to$ L \\ \midrule \multicolumn{3}{l}{\textbf{In-/Dekrement Operatoren}} \\ \midrule Post-Inkrement & \hspace*{-10pt} \code{expr++} & \hspace*{-10pt} 17 & \hspace*{-10pt} links & \hspace*{-10pt} L $\to$ R \\ Post-Dekrement & \hspace*{-10pt} \code{expr--} & \hspace*{-10pt} 17 & \hspace*{-10pt} links & \hspace*{-10pt} L $\to$ R \\ Prä-Inkrement & \hspace*{-10pt} \code{++expr} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} L $\to$ L \\ Prä-Dekrement & \hspace*{-10pt} \code{--expr} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} L $\to$ L \\ \midrule \multicolumn{3}{l}{\textbf{Relationale Operatoren}} \\ \midrule Kleiner als & \hspace*{-10pt} \code{<} & \hspace*{-10pt} 11 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Grösser als & \hspace*{-10pt} \code{>} & \hspace*{-10pt} 11 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Kleiner gleich & \hspace*{-10pt} \code{<=} & \hspace*{-10pt} 11 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Grösser gleich & \hspace*{-10pt} \code{>=} & \hspace*{-10pt} 11 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Gleich & \hspace*{-10pt} \code{==} & \hspace*{-10pt} 10 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Ungleich & \hspace*{-10pt} \code{!=} & \hspace*{-10pt} 10 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ \midrule \multicolumn{3}{l}{\textbf{Logische Operatoren}} \\ \midrule Logisches AND & \hspace*{-10pt} \code{\&\&} & \hspace*{-10pt} 6 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Logisches OR & \hspace*{-10pt} \code{||} & \hspace*{-10pt} 5 & \hspace*{-10pt} links & \hspace*{-10pt} RxR $\to$ R \\ Logisches NOT & \hspace*{-10pt} \code{!} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} R $\to$ R \\ \midrule \multicolumn{3}{l}{\textbf{Ein- und Ausgabe}} \\ \midrule Eingabeoperator & \hspace*{-10pt} \code{>>} & \hspace*{-10pt} 12 & \hspace*{-10pt} links & \hspace*{-10pt} L $\to$ L \\ Ausgabeoperator & \hspace*{-10pt} \code{<<} & \hspace*{-10pt} 12 & \hspace*{-10pt} links & \hspace*{-10pt} R $\to$ L \\ \midrule \multicolumn{3}{l}{\textbf{Zeiger}} \\ \midrule Adressoperator & \hspace*{-10pt} \code{\&} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} L $\to$ R \\ Dereferenz-Operator & \hspace*{-10pt} \code{*} & \hspace*{-10pt} 16 & \hspace*{-10pt} rechts & \hspace*{-10pt} L $\to$ R \\ \bottomrule \end{tabular} \end{center} \subsubsection{Ergänzungen: Division (\code{/}) und Modulo (\code{\%})} i) Falls zwei Ganze Zahlen (\code{int} oder \code{unsigned int}) dividiert werden, so rundet der Operator ganzzählig! \medskip ii) Modulo gibt es nur für \code{int} und \code{unsigned int}. Bei negativen Zahlen übernimmt \code{\%} das Vorzeichen des linken Operanden. \subsubsection{Kurzschlussauswertung} Logische Operatoren werten den linken Operanden zuerst aus. Steht das Ergebnis schon fest, wird der rechte Operand \emph{nicht} mehr ausgewertet. \subsubsection{Richtlinie} Vermeide das Verändern von Variablen, welche im selben Ausdruck noch einmal verwendet werden! \vfill\null \columnbreak \subsection{Sonstiges} \subsubsection{Standardbibliothek: \code{\#include}} \begin{tabular}{r l p{0.375\linewidth}} \toprule Was & \hspace*{-10pt} Code & \hspace*{-10pt} Beschreibung \\ \midrule Potenzieren & \hspace*{-10pt} \code{std::pow(2.5,2);} & \hspace*{-10pt} $2.5^2 = 6.25$ \\ Quadratwurzel & \hspace*{-10pt} \code{std::sqrt(14.0625);} & \hspace*{-10pt} $\sqrt{14.0625} = 3.75$ \\ Absolutbetrag & \hspace*{-10pt} \code{std::abs(-3);} & \hspace*{-10pt} $|-3| = 3$ \\ Minimum & \hspace*{-10pt} \code{std::min(z, 1.0);} & \hspace*{-10pt} Minimum zweier Argumente \emph{gleichen Typs} \\ Maximum & \hspace*{-10pt} \code{std::max(z, 1.0);} & \hspace*{-10pt} Maximum zweier Argumente \emph{gleichen Typs} \\ \bottomrule \end{tabular} \subsubsection{Funktionalität(en) auslagern} i) Funktionen und Typen in eigene Datei schreiben (test.cpp). ii) Dateien ins Arbeitsverzeichnis der Hauptdatei speichern. iii) In der Hauptdatei Header inkludieren: \code{\#include ''test.cpp''}. \medskip Nachteil: Compiler muss Funktionsdefinition immer neu übersetzen (Zeitaufwand). \subsubsection{Getrennte Übersetzung} i) Funktionen und Typen in eigene Datei schreiben (test.cpp). ii) test.cpp seperat kompilieren $\Rightarrow$ test.o. iii) Deklaration aller benötigten Symbole in Headerdatei (test.h). iv) Headerdatei im Arbeitsverzeichnis speichern. v) In der Hauptdatei inkludieren: \code{\#include ''test.h''}. \medskip Vorteil: Quellcode muss nur einmal übersetzt werden und ist vor Einblick geschützt. \section{Kontrolflussanweisungen} \subsection{Blöcke} \begin{center} \begin{minipage}{0.6 \linewidth} Ein Block gruppiert mehrere Anweisungen zu formell einer Anweisung. Normalerweise wird überall ein Block verwendet, anstelle von einer einzigen Anweisung. \end{minipage} \begin{minipage}{0.39 \linewidth} \begin{center} \eqbox{\begin{tabular}{l} \{ \\ \quad \code{statements} \\ \quad \vdots \\ \} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsubsection{Gültigkeitsbereich von lokalen Variablen} i) Variablen, die in einem Block deklariert sind (''lokale Variablen''), sind ausserhalb des Blocks nicht gültig. Kontrollanweisungen verhalten sich in diesem Zusammenhang wie Blöcke. \medskip ii) Haben mehrerer Variablen den gleichen Namen, dann wird immer die Variable mit der am stärksten verschachtelten Deklaration gewählt. \subsection{if-else Anweisung} \begin{center} \begin{minipage}{0.5 \linewidth} 1) Ist \code{condition} wahr, dann wird \code{statement1} ausgeführt. \medskip 2) Ist \code{condition} falsch, dann wird \code{statement2} ausgeführt. \end{minipage} \begin{minipage}{0.39 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{if (condition)} \\ 2 & \code{\quad statement1} \\ 3 & \code{else } \\ 4 & \code{\quad statement2} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \vfill\null \columnbreak \subsection{for Schleife} Eine for-Schleife iteriert eine Anweisung mit einer Laufvariable, solange \code{condition} erfüllt ist. \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{for (init statement; condition; expression)} \\ 2 & \code{\quad body statement} \\ \end{tabular}} \end{center} \begin{tabular}{r l l} \toprule \code{init statement}: & \hspace*{-10pt} Deklaration Laufvariable & (Bsp: \code{int i = 0}) \\ \code{condition}: & \hspace*{-10pt} Iterationsbedingung & (Bsp: \code{i < 10}) \\ \code{expression}: & \hspace*{-10pt} Manipulation Laufvariable & (Bsp: \code{++i}) \\ \bottomrule \end{tabular} \medskip Die Manipulation der Laufvariable wird \emph{immer am Ende} der jeweiligen Iteration durchgeführt. \subsection{while Schleife} Eine while-Schleife iteriert eine Anweisung, solange \code{condition} erfüllt ist. \begin{center} \begin{minipage}{0.54 \linewidth} \begin{center} \begin{tabular}{r p{0.5\linewidth}} \toprule \code{condition}: & \hspace*{-10pt} Iterationsbedingung \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.45 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{while (condition)} \\ 2 & \code{\quad statement} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsection{do-while Schleife} Einziger Unterschied zur while Schleife ist, dass die Anweisungen mindestens einmal ausgeführt werden. Dies ist so, da \code{condition} erst am Ende der Iteration geprüft wird. \begin{center} \begin{minipage}{0.54 \linewidth} \begin{center} \begin{tabular}{r p{0.5\linewidth}} \toprule \code{condition}: & \hspace*{-10pt} Iterationsbedingung \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.45 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{do} \\ 2 & \code{\quad statement} \\ 3 & \code{while (condition)} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsection{Sprunganweisungen} \begin{center} \begin{minipage}{0.7 \linewidth} \begin{center} \begin{tabular}{r p{0.75\linewidth}} \toprule 1: & \hspace*{-10pt} Die umschliessende Iterationsschleife wird sofort beendet. \\ 2: & \hspace*{-10pt} Überspringt den Rest der Anweisungen der jetzigen Iteration. Die Iteration wird aber \textbf{nicht} abgebrochen! \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.29 \linewidth} \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{break;} \\ 2 & \code{continue;} \\ \end{tabular}} \end{center} \end{minipage} \end{center} \subsection{switch Anweisung} Die switch Anweisung eignet sich um eine Fallunterscheidung zu treffen. Der Ausdruck \code{expr} wird ausgewertet und springt, falls ein entsprechender Fall vorhanden ist, zu diesem, ansonsten zum \code{default}-Fall. \begin{center} \begin{minipage}{0.65 \linewidth} \begin{center} \begin{tabular}{r p{0.62\linewidth}} \toprule \code{expr} & \hspace*{-10pt} Muss zu \code{int} konvertierbar sein! \\ \code{case} & \hspace*{-10pt} Definiert einen Fall mit einem \emph{konstanten} int Wert (hier 1). \\ \code{break;} & \hspace*{-10pt} Springt aus dem switch-case \\ \code{default:} & \hspace*{-10pt} Standardfall \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.34 \linewidth} \begin{center} \eqbox{\begin{tabular}{l} \code{switch (expr)} \{ \\ \code{\quad case 1:} \\ \code{\quad\quad statement} \\ \code{\quad\quad break;} \\ \code{\quad default:} \\ \code{\quad\quad statement2} \\ \} \\ \end{tabular}} \end{center} \end{minipage} \end{center} Wird ein Fall nicht mit \code{break;} beendet, werden darunterliegende Fälle auch ausgeführt (genannt ''durchfallen''), bis ein \code{break;} erreicht wird. \vfill\null \columnbreak \section{Funktionen} \subsection{Definition} Eine Funktionsdefinition gehört oberhalb von \code{main()} hin. Die Argumente einer Funktion verhalten sich wie lokale Variablen im Funktionsblock. \begin{center} \begin{minipage}{0.375\linewidth} \begin{center} \begin{tabular}{r l} \toprule \code{T} & \hspace*{-10pt} Rückgabetyp \\ \code{fname} & \hspace*{-10pt} Funktionsname \\ \code{T$_i$} & \hspace*{-10pt} Argumenttypen \\ \code{pname$_i$} & \hspace*{-10pt} Argumente \\ \bottomrule \end{tabular} \end{center} \end{minipage} \begin{minipage}{0.615 \linewidth} \begin{center} \eqbox{\begin{tabular}{l} \code{T fname(T$_1$ pname$_1$,$\dots$,T$_n$ pname$_n$)}\{ \\ \code{\quad statements} \\ \code{\quad return expr;} \\ \} \\ \\ \code{int main()} \{ \\ \code{\quad /* Funktionsaufruf */} \\ \code{\quad fname(expr$_1$, $\dots$, expr$_n$);} \\ \} \\ \end{tabular}} \end{center} \end{minipage} \end{center} Der Rückgabetyp kann auch vom Typ \code{void} sein, welcher der Typ mit leerem Wertebereich ist, d.h. keine Rückgabe. \subsubsection{Rückgabewert} Jede Funktion, die nicht den Rückgabetyp \code{void}, hat, \textbf{muss} ein \code{return} besitzen. Der Rückgabewert wird immer zum Rückgabetyp konvertiert und ergibt den Wert des Funktionsaufruf. \subsection{Vor- und Nachbedingungen} Es ist sinnvoll Funktionen gut zu dokumentieren mit PRE-/POST-Conditions (Vor- und Nachbedingungen). \begin{center} \begin{tabular}{r l} \toprule Vorbedingungen: & \hspace*{-10pt} Spezifiziert den Definitionsbereich der Funktion. \\ & \hspace*{-10pt} - Sollten immer mit asserts geprüft werden. \\ Nachbedingungen: & \hspace*{-10pt} Spezifiziert Wert und Effekt der Funktion. \\ & \hspace*{-10pt} - Kann oft einfach mit asserts überprüft werden. \\ \bottomrule \end{tabular} \end{center} \subsection{Forward Declarations} Eine Funktion kann im Programm nur in Zeilen verwendet werden, welche nach der Deklaration der Funktion kommen. Eine Forward Declaration ist einfach der Funktionskopf ohne den Funktionskörper: \begin{center} \eqbox{\code{T fname(T$_1$ pname$_1$,$\dots$,T$_n$ pname$_n$);}} \end{center} \subsection{Namensräume (namespace)} Mit namespaces kann man Funktionen, Typen, etc. katalogisieren. Ausserdem kann man bei grösseren Projekten mit namespaces verschiedenste Namenskonflikte verhindern. \begin{center} \eqbox{\begin{tabular}{l} \code{namespace boring}\{ \code{// neuer Namensraum} \\ \code{\quad void func() // gehört zum Namensraum 'boring'} \\ \} \\ \code{main()} \{ \\ \code{\quad boring::func(); // Zugriff auf Element im Namensraum} \\ \} \\ \end{tabular}} \end{center} \vfill\null \columnbreak \section{Vektoren} Vektoren dienen zum Speichern gleichartiger Daten (gleicher Typ). Ein Vektor kann aus beliebigen Typen bestehen. \subsection{Initialisierung} \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{l} \toprule \code{auto vec = std::vector(5);} \\ \qquad - Vektor mit 5 Elementen auf Wert 0 initialisiert. \\ \code{auto vec = std::vector(5,2);} \\ \qquad - Vektor mit 5 Elementen auf Wert 2 initialisiert. \\ \code{std::vector vec = }\{\code{3,2,1}\}\code{;} \\ \qquad - Vektor wird mit einer Liste von Werten initialisiert. \\ \code{std::vector empty;} \\ \qquad - Deklariert und initialisert einen leeren Vektor. \\ \bottomrule \end{tabular} \end{center} \subsection{Funktionalität} Nicht vergessen, dass der Index bei Vektoren mit 0 beginnt! \begin{center} \begin{tabular}{r l} \toprule Bibliothek: & \hspace*{-10pt} \code{\#include} \\ Zugriff auf Element \code{i} ohne Index-Check: & \hspace*{-10pt} \code{vec[i]} \\ Zugriff auf Element \code{i} mit Index-Check: & \hspace*{-10pt} \code{vec.at(i);} \\ Fügt \code{x} hinten an: & \hspace*{-10pt} \code{vec.push\_back(x);} \\ Die Länge vom Vektor: & \hspace*{-10pt} \code{vec.size();} \\ Ändert die Länge zu \code{v}: & \hspace*{-10pt} \code{vec.resize(v);} \\ \midrule Prüft, ob Vektor leer ist: & \hspace*{-10pt} \code{vec.empty();} \\ Löscht den Inhalt: & \hspace*{-10pt} \code{vec.clear();} \\ \bottomrule \end{tabular} \end{center} \subsection{Mehrdimensionale Vektoren} Funktioniert im Prinzip gleich wie ein 1D-Vektor. \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{r l} \toprule Leere Matrix: & \hspace*{-10pt} \code{std::vector> matrix;} \\ Initialisierung: & \hspace*{-10pt} \code{auto matrix = std::vector>(} \\ & \hspace*{-10pt} \code{rows, std::vector(cols, value));} \\ Definition: & \hspace*{-10pt} \code{std::vector> matrix(} \\ & \hspace*{-10pt} \code{rows, std::vector(cols, value));} \\ Zugriff: & \hspace*{-10pt} \code{matrix.at(i).at(j);} \\ \bottomrule \end{tabular} \end{center} \begin{center} \includegraphics[width=0.75\linewidth]{Bilder/Matrix.png} \end{center} \subsubsection{Einschub: Typ-Alias} Für lange Typen kann es sich lohnen eine Typ-Alias zu definieren: \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{r l} \toprule Allgemein: & \hspace*{-10pt} \code{using newName = Typ;} \\ Beispiel: & \hspace*{-10pt} \code{using matrix = std::vector>;} \\ & \hspace*{-10pt} \code{matrix m = ...;} \\ \bottomrule \end{tabular} \end{center} \vfill\null \columnbreak \section{Referenzen} Eine Referenz funktioniert wie ein Alias für ein anderes Objekt. Intern ist eine Referenz die Adresse vom referenzierten Objekt, d.h. eine Zuweisung auf eine Referenz ändert das ursprüngliche Objekt. \begin{center} \begin{tabular}{r l} \toprule Referenz vom Typ T: & \hspace*{-10pt} \code{T\& rname = lvalue;} \\ const-Referenz vom Typ T: & \hspace*{-10pt} \code{const T\& rname = rvalue;} \\ \bottomrule \end{tabular} \end{center} \subsubsection{Const-Referenzen} Eine const-Referenz setzt \textbf{nicht} vorraus, dass das ursprüngliche Objekt auch const ist. Es sagt einfach aus, dass man über die Referenz nur \emph{read-only} Zugriff auf die ursprüngliche Variable hat. \medskip Bemerkung: Eine const-Referenz kann ausserdem mit einem R-Wert initialisiert werden, in diesem Fall erzeugt der Compiler ein tempörares Objekt mit ausreichender Lebensdauer. \subsection{Anwendung: Pass by Reference} Referenzen sind sehr nützlich um Funktionen nicht fundamental Datentypen wie Vektoren zu übergeben, da sie es erlauben die Werte des Aufrufargument zu ändern. \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{void func(std::vector\& i)} \{ \\ 2 & \code{\quad statements} \\ 3 & \} \\ \end{tabular}} \end{center} \subsubsection{Pass by const Reference (\code{const T\&})} Überall wo es möglich ist, sollte man nicht fundamentale Typen als \code{const T\&} übergeben. Dies spart Ressourcen und stellt klar, dass man das Argument nicht mit der Funktion verändert. \subsubsection{Pass by Value} Bei Pass by Value, d.h. das Argument hat kein Referenztyp, wird eine \emph{Kopie des Objekts} übergeben. \subsection{Anwendung: Return by Reference} Return by Reference ermöglicht es, dass der Rückgabewert ein L-Wert ist anstelle von einem R-Wert. \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{int\& increment(int\& i)} \{ \\ 2 & \code{\quad return ++i;} \\ 3 & \} \\ \\ 4 & increment(increment(x)); \\ \end{tabular}} \end{center} Eine Funktion, welche eine Referenz als Argument nimmt, kann man nur mit sich selbst als Argument anwenden (Zeile 4), falls der Rückgabetyp auch eine Referenz ist. Sonst gibt die Funktion im Argument einen R-Wert zurück, obwohl ein L-Wert benötigt wird. \subsection{Referenz-Richtlinie} Wenn man eine Referenz erzeugt, muss das Objekt, auf das sie verweist, mindestens so lange ''leben'' wie die Referenz selbst. \vfill\null \columnbreak \section{Ein- und Ausgabeströme} \subsection{Generische Ströme (Abstrakter Typ)} Man muss für eine Funktion nicht unbedingt genau spezifizieren, was für eine Eingabeart (Konsole, File, etc.) notwendig ist. Man interagiert mit den generischen Strömen auch über den Eingabe- und Ausgabeoperator. \begin{center} \eqbox{\begin{tabular}{l} \code{\#include } \\ \code{void func(std::istream\& in, std::ostream\& out)} \\ \end{tabular}} \end{center} Man muss die Argumente als normale Referenz deklarieren, da sie den Eingabestrom bzw. Ausgabestrom verändern durch lesen bzw. schreiben. \subsubsection{Filestream} Ein Beispiel mit Dateien zur Ein- und Ausgabe: \begin{center} \eqbox{\begin{tabular}{l} \code{\#include } \\ \code{std::ifstream from = std::ifstream(''source.txt'');} \\ \code{std::ofstream to = std::ofstream(''destination.txt'');} \\ \\ \code{int main ()} \\ \code{\qquad func(from, to);} \\ \end{tabular}} \end{center} \subsubsection{Stringstream} Ein weiteres Beispiel für einen Eingabestrom ist der Stringstream: \begin{center} \eqbox{\begin{tabular}{l} \code{\#include } \\ \code{std::string text = ''Text!'';} \\ \code{std::istringstream from = std::istringstream(text);} \\ \\ \code{int main ()} \\ \code{\qquad func(from, std::cout);} \\ \end{tabular}} \end{center} \subsection{Whitespaces} Per default ignorieren die Eingabeströme Whitespaces (Leerschläge, Zeilenumbrüche, Tabs, etc.). Dies kann man durch \code{std::noskipws} ändern (Zeile 1), nichtdestotrotz kann man Whitespaces entfernen durch \code{std::ws} (Zeile 2). \begin{center} \eqbox{\begin{tabular}{r l} 1 & \code{std::cin >> std::noskipws;} \\ 2 & \code{std::cin >> std::ws;} \\ \end{tabular}} \end{center} \subsection{Eingabestrom als Bedingung für Kontrollanweisungen} Ist eine Eingabe im Eingabestrom vorhanden, dann kann man den nächsten Wert des Eingabestroms in eine Variable auslesen und die Bedingung evaluiert als 'true'. Sind keine Eingaben mehr vorhanden im Eingabestrom, dann evaluiert die Bedingung als 'false'. \begin{center} \eqbox{\begin{tabular}{l} \code{char input;} \\ \code{while(std::cin >> input)} \\ \quad ... \\ \end{tabular}} \end{center} Dasselbe geht natürlich auch für z.B. eine if-else-Bedingung! \vfill\null \columnbreak \section{Rekursion} Rekursion passiert, wenn eine Funktion sich selbst aufruft. Der Grundaufbau einer (funktionierenden) Rekursion ist, wie folgt: \begin{itemize} \item \textbf{Basecase}: Abbruchsbedingung, welche die Rekursion stoppen soll. Grundsätzlich muss sich die Rekursion diesem Fall stetig annähern, ansonst gibt es eine unendliche Rekursion und einen \emph{stack overflow}. \item \textbf{Rekursiver Teil}: Hier wird die Aufgabe der Funktion gelöst durch einen Aufruf der Funktion selbst, d.h. die Funktion führt etwas aus und ruft sich dann selbst auf (oder umgekehrt). \end{itemize} \subsection{Der Aufrufstapel} Jeder rekursive Funktionsaufruf hat seine eigenen, unabhängigen Variablen und Argumente. Darstellung als Aufrufsstapel: \begin{center} \includegraphics[width=0.8\linewidth]{Bilder/Aufrufstapel.png} \end{center} \subsection{Anwendungsbeispiele} Ein einfacheres Beispiel: \includegraphics[width=0.9\linewidth]{Bilder/Rekursion_bsp.png} \medskip Ein etwas komplexeres Beispiel: \includegraphics[width=1\linewidth]{Bilder/Rekursion_bsp2.png} \section{Extended Backus Naur Form (EBNF)} EBNF ist eine formale Grammatik. Man kann sie benutzen um Sätze zu produzieren oder um Sätze zu Parsen (überprüfen). \subsection{Sätze} Sätze bestehen aus folgenden Bestandteilen. Der Unterschied zwischen nicht-terminalen Symbolen und terminalen Symbolen ist, dass terminale Symbole keine weitere Funktionsaufrufe enthalten. \begin{center} \begin{tabular}{r l} \toprule Nichtterminale Symbole: & \hspace*{-10pt} Kann weiter zerlegt werden \\ Terminale Symbole: & \hspace*{-10pt} Kann nicht weiter zerlegt werden \\ Alternative: & \hspace*{-10pt} \code{|} \\ optionale Repetition: & \hspace*{-10pt} \{ \dots \} \\ optional Einmal: & \hspace*{-10pt} [ \dots ] \\ Satz beendet: & \hspace*{-10pt} . \\ \bottomrule \end{tabular} \end{center} Beispielssatz: \, factor = number $|$ ''('' expression '')'' $|$ ''-'' factor. \medskip In Worten: \emph{factor} besteht aus \emph{number} ODER dem Zeichen ''('' gefolgt von \emph{expression} und '')'' ODER dem Zeichen ''-'' und \emph{factor} selbst. \subsection{Parsing} Parsing ist das überprüfen, ob und wie ein Satz aus einer formellen Grammatik erzeugt werden kann. Grundsätzlich gilt: \begin{center} \begin{tabular}{r l} \toprule \textbf{EBNF} & \hspace*{-10pt} \textbf{Parser} \\ \midrule Satz: & \hspace*{-10pt} Funktion \\ Alternative: & \hspace*{-10pt} if-Anweisung \\ Nichtterminales Symbol: & \hspace*{-10pt} Funktionsaufrufe \\ optionale Repetition: & \hspace*{-10pt} while-Anweisung \\ \bottomrule \end{tabular} \end{center} \subsubsection{Einschub: peek() (\code{\#include })} Die Funktion peek() erlaubt es das nächste Zeichen im Inputstream anzuschauen, \emph{ohne es zu entfernen}. Dies ist notwendig für Parsing. \begin{center} \eqbox{\begin{tabular}{l} \code{std::istringstream s1(''Hello, world.'');} \\ \code{char c1 = s1.peek();} // c1 = 'H' \\ \end{tabular}} \end{center} Die Funktion ignoriert Whitespaces \emph{nie} (unabhängig von std::noskipws). \subsubsection{Einschub: \code{lookahead(std::istream\& is)}} Diese Funktion gibt den nächsten \emph{non-whitespace} Charakter vom Eingabestrom, d.h. es funktioniert wie peek, aber es ignoriert Whitespaces. \subsubsection{Einschub: consume(std::istream\& is, char expected)} Diese Funktion findet man in \code{ebnf\_helpers.h}. Es ist wichtig zu überprüfen, welche Variante der Funktion drinnen ist, da es bisher zwei verschiedene gab. Die neuere Variante hat folgende Charakterisierung: \begin{itemize} \item Liest den nächsten Charakter vom Inputstream und gibt \emph{True} zurück, falls es der gleiche Charakter ist, wie der Charakter im Argument der Funktion. Ausserdem wird der Charakter vom Inputstream \textbf{entfernt}. \item Ist es nicht der gleiche Charakter, dann gibt die Funktion \emph{False} zurück und der Charakter wird in den Inputstream \textbf{zurückgelegt}! \end{itemize} Bem: Bei der älteren Variante ist der grosse Unterschied, dass der Charakter beim Fall \emph{False} nicht zurückgelegt wird in den Inputstream. \subsection{Anwendung: Codebeispiele von Parsing} Für die \emph{neuere} Version von \code{consume()} gibt es folgendes Beispiel: \includegraphics[width=0.85\linewidth]{Bilder/EBNF.png} \medskip Für die \emph{ältere} Version von \code{consume()} gibt es folgendes Beispiel: \includegraphics[width=0.92\linewidth]{Bilder/EBNF_2.png} \vfill\null \columnbreak \section{Structs \& Klassen} \subsection{Structs} Structs sind Container für Datentypen. Die zugrundeliegende Typen können fundamentale aber auch benutzerdefinierte Typen sein. \begin{center} \renewcommand{\arraystretch}{1.1} \begin{tabular}{r l} \toprule Definition: & \hspace*{-10pt} \code{struct strName} \{ \\ & \hspace*{-10pt} \code{\quad int mem1;} \\ & \hspace*{-10pt} \code{\quad bool mem2;} \\ & \hspace*{-10pt} \}\code{;} \\ Default-Initialisierung: & \hspace*{-10pt} \code{strName obj1;} \\ Initialisierung mit Startwerten: & \hspace*{-10pt} \code{strName obj2 = }\{\code{3,true}\}\code{;} \\ Initialisierung mit anderem Objekt: & \hspace*{-10pt} \code{strName obj3 = obj2;} \\ Zugriff auf Member: & \hspace*{-10pt} \code{obj1.mem1 = 10;} \\ \bottomrule \end{tabular} \end{center} Achtung: Bei Default-Init werden alle Member einzeln default-initialisiert, dies bedeutete für fundamentale Typen, dass sie uninitialisiert sind. Zugriff bevor einer Zuweisung ist undefined behavior! \subsection{Überladen von Funktionen} Es ist möglich mehrere Funktionen gleichen Namens zu definieren und deklarieren. Die 'richtige' Version wird aufgrund der Signatur der Funktion (Typ, Anzahl und Reihenfolge der Argumente) ausgewählt. \begin{center} \begin{tabular}{r l} \toprule Funktion: & \hspace*{-10pt} \code{int pow(int b, int e)} \{ \dots \} \\ Bsp. einer Überladung: & \hspace*{-10pt} \code{int pow(int e)} \{ return pow(2,e); \} \\ \bottomrule \end{tabular} \end{center} Achtung: Die Argumentnamen haben \emph{keinen} Einfluss auf die Signatur! \subsubsection{Operator overloading} Operatoren (\code{+, -, *, /, +=, <<}, etc.) können auch überladen werden und so für eigene Structs und Classes definiert werden. \begin{center} \eqbox{\begin{tabular}{l} \code{cname operator+(cname a, cname b)} \\ \code{cname operator-(cname a)} \\ \code{cname\& operator+=(cname\& a, cname b)} \\ \code{std::ostream\& operator<<(std::ostream\& o, const cname\& r)} \\ \code{std::istream\& operator>>(std::istream\& in, cname\& r)} \\ \end{tabular}} \end{center} \subsection{Klassen} Eine Klasse erlaubt Kapselung via Zugriffkontrolle (private, public). Nur auf public Member kann von aussen zugegriffen werden. Der Gültigkeitsbereich von Membern in einer Klasse ist die ganze Klasse, unabhängig von der Deklarationsreihenfolge. \begin{center} \eqbox{\begin{tabular}{l} \code{class className} \{ \\ \code{public:} \\ \code{\quad int getHidden();} \\ \code{private:} \\ \code{\quad int hidden;} \\ \}\code{;} \\ \end{tabular}} \end{center} Einziger Unterschied gegenüber structs ist, dass Members in structs per default public sind, während sie in classes per default private sind. \vfill\null \columnbreak \subsection{Memberfunktionen} Memberfunktionen stellen die Funktionalität einer Klasse bereit. Die Deklaration erfolgt immer in der Klassendefinition, die Definition der Memberfunktion ist auch extern möglich über den ::Operator. \begin{center} \eqbox{\code{int className::getHidden()} \{\code{return hidden;} \}} \end{center} Aufruf einer Memberfunktion: \begin{center} \eqbox{\code{className.gethidden();}} \end{center} \subsubsection{const Memberfunktionen} Man kann durch \code{const} in der Funktionsdefinition versprechen, dass eine Memberfunktion nichts an der Objektinstanz verändert: \begin{center} \eqbox{\code{int className::getHidden const()} \{\code{return hidden;} \}} \end{center} \subsection{Konstruktoren} Konstruktoren sind spezielle Memberfunktionen einer Klasse, die den Namen der Klasse tragen. Sie werden bei der Variablendeklaration aufgerufen (müssen public sein). \begin{center} \begin{tabular}{r l} \toprule Konstruktor: & \hspace*{-10pt} \code{className(int a): hidden(a)} \{ \dots \} \\ Default-Konstruktor: & \hspace*{-10pt} \code{className(): hidden(0)} \{ \dots \} \\ \midrule Objektinitialisierung: & \hspace*{-10pt} \code{auto myclass = className();} \\ \midrule Default-Konstruktor löschen: & \hspace*{-10pt} \code{className() = delete;} \\ \bottomrule \end{tabular} \end{center} Ein Default-Konstruktor (kein Argument) wird automatisch erzeugt, falls eine Klasse keinen Konstuktor definiert hat. \subsection{\code{this} Zeiger} Member einer Klasse haben ein implizites Argument, nämlich das aufrufende Objekt. Mittels dem \code{this} Zeiger kann man explizit auf das Aufruferobjekt zugreifen. \begin{center} \begin{tabular}{r l} \toprule Implizit: & \code{return hidden;} \\ Explizit umständlich: & \code{return (*this).hidden;} \\ Explizit: & \code{return this->hidden;} \\ \bottomrule \end{tabular} \end{center} Dies macht nur Sinn, falls der zu zugreifende Name lokal nicht eindeutig ist oder wenn man z.B. eine Referenz auf das implizite Aufruferobjekt zurückgeben will: \begin{center} \eqbox{\begin{tabular}{ l} \code{Complex\& operator+= (const Complex\& b)} \{ \\ \code{\quad real += b.real; // Manipulierung implizites Aufrufobjekt} \\ \code{\quad imag += b.imag; // Manipulierung implizites Aufrufobjekt} \\ \code{return *this;} \} \\ \end{tabular}} \end{center} \vfill\null \columnbreak \section{Allgemeine Ergänzungen} \subsection{Pointy Vektor} Ist ein Funktionsargument: \code{std::vector* v}, so funktioniert: \medskip i) \code{v->size()}; ii) \code{v->at(i)}; \subsection{Substrings von Strings} Mit der Funktion \code{substr(pos, count)} der Klasse \code{std::string} kann man einen beliebigen Substring vom String nehmen. Beispiel: \begin{center} \eqbox{\begin{tabular}{l} \code{std::string test = "Hello";} \\ \code{std::cout << test.substr(2,3); // Ausgabe: llo} \\ \end{tabular}} \end{center} Gibt man der Funktion nur \code{pos} (Startposition) ohne \code{count} (Anzahl Charakter), dann gibt sie den ganzen Rest vom string aus. \vfill\null \pagebreak \section{Zeiger (Pointers)} Ein Zeiger enthält die Adresse eines Speicherplatzes. \begin{center} \begin{tabular}{r l} \toprule Variable vom Typ \code{T}: & \hspace*{-10pt} \code{T var;} \\ Zeiger vom Typ \code{T*}: & \hspace*{-10pt} \code{T* ptr = \& var;} \\ Uninitialiserter Zeiger: & \hspace*{-10pt} \code{T* ptr = nullptr;} \\ Zugriff auf Speicherinhalt: & \hspace*{-10pt} \code{std::cout << *ptr;} \\ Memberzugriff über Pointer: & \hspace*{-10pt} \code{pointer->member;} \\ \bottomrule \end{tabular} \end{center} Das Dereferenzieren eines \code{nullptr} führt zu undefined behavoir! \subsection{Const und Zeiger} Am besten liest man die Deklaration von rechts nach links: \begin{center} \begin{tabular}{r p{0.58\linewidth}} \toprule \code{int const* p2;} & Zeiger auf eine konstante Ganzzahl \\ \code{int* const p3;} & const-Zeiger auf eine Ganzzahl \\ \code{int const* const p4;} & const-Zeiger auf eine konstante Ganzzahl \\ \bottomrule \end{tabular} \end{center} Bem: Ein Zeiger auf \code{const T} kann auch auf \code{T} zeigen. Der Zeiger behandelt \code{T} dann einfach wie eine Konstante (Wie bei Referenzen). \subsection{Array} Dynamisch allozierte Liste, welche von der Grösse \code{size} ist und einen Zeiger zum ersten Element zurückgibt. Der Speicher dafür alloziert man selbst \emph{und muss ihn auch selbst wieder deallozieren}. \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Speicher allozieren: & \hspace*{-10pt} \code{T* ptr = new T[size];} \\ Speicher deallozieren: & \hspace*{-10pt} \code{delete[] ptr;} \\ \bottomrule \end{tabular} \end{center} \subsubsection{Zeigerarithmetik} Im Prinzip gleich wie bei Variablen, d.h. \code{++ptr} führt zu einer Inkrementation vom Pointer und z.B. \code{ptr + 3} ändert den Pointer an sich nicht. \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Array: & \hspace*{-10pt} \code{int* ptr = new int[3]}\{\code{1,2,3}\}\code{;} \\ Beispiel 3. Element: & \hspace*{-10pt} \code{int* ptr2 = ptr + 2; // Zeigt auf '3'} \\ Wahlfreier Zugriff: & \hspace*{-10pt} \code{*(ptr + 2) == ptr[2];} \\ \bottomrule \end{tabular} \end{center} Bem: Achten, dass kein 'Out of bounds' Zugriff stattfindet! Wahlfreier Zugriff ist 'teurer' (mehr Operationen), als einen Zeiger zu iterieren. \subsubsection{Anwendung: Sequentielle Iteration} Normaler Anwendungsfall für Zeigerarithmetik ist Iteration eines Array: \begin{center} \eqbox{\begin{tabular}{l} \code{int* ptr = new int[3]}\{\code{1,2,3}\}\code{;} \\ \code{for (int* itr = ptr; itr != ptr + 3; ++itr)} \\ \code{\quad std::cout << *itr << ' ';} \\ \end{tabular}} \end{center} \subsubsection{Konvention: Übergabe eines Arrays an Funktionen} Es ist Konvention immer zwei Zeiger zu übergeben, einer zum ersten Elemente und einer zum Element \textbf{nach} dem letzten. \begin{center} \eqbox{\begin{tabular}{l} \code{int* function(int* begin, int* end)} \{ \} \\ \code{int* ptr = new int[3]}\{\code{1,2,3}\}\code{;} \\ \code{function(ptr, ptr + 3);} // ptr+3 ist Element nach dem letzten \\ \end{tabular}} \end{center} \vfill\null \columnbreak \subsection{Dynamische Allokation} Objekte welche mit dem \code{new} Operator erstellt werden, leben solange, bis sie mit \code{delete} gelöscht werden (dynamischer Lebensdauer). \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Speicher allozieren: & \hspace*{-10pt} \code{myclass* ptr = new myclass();} \\ Speicher deallozieren: & \hspace*{-10pt} \code{delete ptr;} \\ \bottomrule \end{tabular} \end{center} \textbf{Richtlinie}: Wird ein Objekt gelöscht, dann sollte man alle Pointer, welche auf dieses Objekt zeigen, auf \code{nullptr} setzen. \subsubsection{Memory leaks} Wird ein Element nicht korrekt durch \code{delete} gelöscht, führt dies zu Speicherlecks, im schlimmsten Fall zu einem Heap Overflow. \subsubsection{Hängende Zeiger (dangling pointers)} Dereferenzieren oder deallozieren von einem Zeiger, welcher auf ein freigegebenes Objekt zeigt führt zu einem Programmabstürz, da man auf nicht allokierten Speicher zugreift. \subsection{Die Dreierregel} Klassen, welche dynamisch allokierte Membervariablen besitzen, sollten alle der folgenden drei Funktionen definiert haben. \subsubsection{Destruktor} Wird implizit aufgerufen, wenn die Speicherdauer eines Objekts endet. \begin{center} \eqbox{\begin{tabular}{l} \code{\texttildelow className();} \\ \end{tabular}} \end{center} Wenn kein Destruktor definiert ist, wird er automatisch erzeugt und ruft die Destruktoren für die Membervariablen auf. \subsubsection{copy-Konstruktor} Wird bei jeder Initialisierung, auch bei \emph{pass-by-value}, aufgerufen. \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{l} \toprule \hspace*{-10pt} \code{className(const className\& other) : var(\dots), \dots} \{ \\ \hspace*{-10pt} \quad \dots // Dynamische Membervariable(n) allokieren \\ \hspace*{-10pt} \quad \dots // Alle Variablen kopieren \\ \hspace*{-10pt} \} \\ \bottomrule \end{tabular} \end{center} Falls kein Copy-Konstruktor deklariert ist, wird er automatisch erzeugt mit memberweiser initialisierung. \subsubsection{Zuweisungsoperator} Wird bei allfälligen Zuweisungen \emph{nach} der Initialisierung aufgerufen. \begin{center} \begin{tabular}{l} \toprule \code{stack\& stack::operator=(const stack\& s)} \{ \\ \code{\quad if (topn != s.topn)} \{ // Keine Selbstzuweisung \\ \code{\quad\quad stack copy = s;} // Aufruf copy-Konstruktor \\ \code{\quad\quad std::swap(topn, copy.topn);} // copy hat nun den Müll \\ \code{\quad\quad \dots ;} \qquad // Bei mehr Variablen, mehr swaps \\ \quad \} // copy wird aufgeräumt \\ \code{\quad return *this;} // Rückgabe als L-Wert (Konvention) \\ \} \\ \bottomrule \end{tabular} \end{center} \subsubsection{Einschub: std::swap (Bibliothek \code{\#include})} Inhalte von zwei Variablen einfach tauschen: \code{std::swap(a,b);}. \vfill\null \columnbreak \subsection{Anwendung: Verkettete Listen (linked list)} Eine verkettete Liste ist ein Speicherlayout, bei welchem kein zusammenhängender Speicherbereich vorhanden ist. \subsubsection{Grundelement} \begin{center} \eqbox{\begin{tabular}{l} \code{struct llnode} \{ \\ \code{\quad int value;} \\ \code{\quad llnode* next;} \\ \code{\quad llnode(int v, llnode* n): value(v), next(n)} \{ \} \\ \}\code{;} \\ \end{tabular}} \end{center} \subsubsection{Implementation} Eine sehr simple Implementation einer verketteten Liste ist: \begin{center} \eqbox{\begin{tabular}{l} \code{class llvec} \{ \\ \code{\quad llnode* head; // Zeigt auf das erste Element} \\ \code{public:} \\ \code{\quad int\& operator[](unsigned int i);} \\ \code{\quad void push\_front(int e);} \\ \code{\quad llvec(unsigned int size); // Konstruktor} \\ \}\code{;} \\ \end{tabular}} \end{center} Der Zugriff ist bei einer verketteten Liste ineffizienter: \begin{center} \eqbox{\begin{tabular}{l} \code{int\& operator[](unsigned int i)} \{ \\ \code{\quad llnode* n = head;} \\ \code{\quad for(int j = 0; j < i; ++j)} \\ \code{\quad\quad n = n->next;} \\ \code{\quad return n->value;} \\ \} \\ \end{tabular}} \end{center} Ein grosser Vorteil ist das einfache Anfügen von Elementen: \begin{center} \eqbox{\begin{tabular}{l} \code{void llvec::push\_front(int e)} \{ \\ \code{\quad head = new llnode(e,head);} \\ \} \\ \end{tabular}} \end{center} Der Konstruktor kann man so definieren: \begin{center} \eqbox{\begin{tabular}{l} \code{llvec::llevc(unsigned int size)} \{ \\ \code{\quad head = nullptr;} \\ \code{\quad for(unsigned int i = 0; i < size; ++i)} \\ \code{\quad\quad push}$\_$\code{front(0);} \\ \} \\ \end{tabular}} \end{center} \subsection{Bäume} Bäume sind verallgemeinerte Listen, d.h. Knoten könen mehrere Nachfolger besitzen. \vfill\null \pagebreak \section{Container} Jeder Container hat charakteristische Eigenschaften, d.h. bestimmte Sachen macht er besonders effizient bzw. ineffizient. Es lohnt sich also einen geeigneten Container zu wählen. \subsection{Iteratoren} Iteration erfordert vom Prinzip her unabhängig vom Container die gleichen Schritte. In C++ gibt es deswegen zu jedem Container einen passenden Iterator. Implementierung vom Iterator ist für den Nutzer nicht relevant (Abstraktion). \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Iterator für vector: & \hspace*{-10pt} \code{std::vector::iterator it;} \\ Iterator aufs erste Element: & \hspace*{-10pt} \code{it = vec.begin();} \\ Iterator \textbf{hinters} letzte Element: & \hspace*{-10pt} \code{it = vec.end();} \\ Zugriff auf aktuelles Element: & \hspace*{-10pt} \code{*it;} \\ Iterator inkrementieren: & \hspace*{-10pt} \code{++it;} \\ \bottomrule \end{tabular} \end{center} \subsubsection{Anwendung: Sequentielle Iteration} \begin{center} \eqbox{\begin{tabular}{l} \code{using Iterator = std::vector::iterator;} // Alias \\ \code{for (Iterator it = vec.begin(); it != vec.end(); ++it)} \{ \\ \quad\code{\dots} // Anweisungen \\ \} \\ \end{tabular}} \end{center} \subsubsection{const Iterator} Neben einem Iterator sollte jeder Container auch einen Const-Iterator bereitstellen, welcher kein Schreibzugriff gewährleistet: \begin{center} \eqbox{\begin{tabular}{l} \code{std::vector::const\_iterator itr = vec.begin();} \\ \end{tabular}} \end{center} \subsubsection{Bereichsbasierte for-Schleife} Für die Iteration über einen ganzen Container gibt es auch folgende Möglichkeit: \begin{center} \begin{tabular}{l} \toprule \code{for(int element: container\_name)} \\ \code{\quad std::cout << element;} // Ausgabe von allen Werten \\ \bottomrule \end{tabular} \end{center} \subsection{Anwendung: Set (\code{\#include})} Ein Set kann \emph{kein} Element doppelt enthalten und besitzt keine bestimmte Reihenfolge (kein indexbasierter Zugriff). Es ist aber sehr effizient im überprüfen, ob ein Element enthalten ist und im einfügen bzw. löschen eines Elements. \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Bibliothek: & \hspace*{-10pt} \code{\#include} \\ Ungeordnetes Set: & \hspace*{-10pt} \code{std::unordered\_set setname;} \\ Geordnetes Set: & \hspace*{-10pt} \code{std::set setname;} \\ Element hinzufügen: & \hspace*{-10pt} \code{setname.insert(value);} \\ Intervall Initialisierung [b,e): & \hspace*{-10pt} \code{std::set setname(b,e);} \\ \bottomrule \end{tabular} wobei \code{b = vec.begin()} und \code{e = vec.end()} \end{center} \subsubsection{Element in ungeordnetem Feld suchen} Der Vergleich \code{set.find(e) == set.end()} gibt \textbf{wahr} zurück, wenn \code{e} im Set enthalten ist. \vfill\null \columnbreak \subsection{Eigener Iterator definieren} Der Iterator ist eine \emph{innere Klasse}, d.h. sie wird innerhalb einer Klasse definiert (hier innerhalb der Klasse \code{llvec}). Um einen eigenen Iterator zu definieren benötigt man folgende Funktionalitäten: \begin{center} \begin{tabular}{l} \toprule \code{class iterator} \{ \\ \code{\quad llnode* node; // Zeiger auf aktuelles Element} \\ \code{public:} \\ \code{\quad iterator(llnode* n);} \\ \code{\quad iterator\& operator++();} \\ \code{\quad int\& operator*() const;} \\ \code{\quad bool operator!=(const iterator\& other) const;} \\ \}\code{;} \\ \bottomrule \end{tabular} \end{center} Sowie folgende Memberfunktionen in der Klasse selbst: \begin{center} \begin{tabular}{l} \toprule \code{class llvec} \{ \\ \code{public:} \\ \code{\quad class iterator} \{\dots\}; \\ \code{\quad iterator begin();} // Gibt erstes Element \\ \code{\quad iterator end();} // Zeigt hinter das letzte Element \\ \}\code{;} \\ \bottomrule \end{tabular} \end{center} \subsection{Nützliche Funktionen für Container} Für alle Container kann man, solange es ihre charakteristischen Eigenschaften es erlauben, folgende Funktionen benutzen: \begin{center} \renewcommand{\arraystretch}{1.25} \begin{tabular}{r l} \toprule Bibliothek: & \hspace*{-10pt} \code{\#include} \\ Bereich [b,p) mit 5 füllen: & \hspace*{-10pt} \code{std::fill(b,p,5);} \\ Den Bereich [b,e) sortieren: & \hspace*{-10pt} \code{std::sort(b,e);} \\ Iterator auf Minimum im Bereich [b,p): & \hspace*{-10pt} \code{std::min\_element(b,p);} \\ Iterator auf den ersten Wert (2) in [b,p): & \hspace*{-10pt} \code{std::find(b,p,2);} \\ \bottomrule \end{tabular} \end{center} \vfill\null \columnbreak \section{Objekt orientierte Programmierung} \subsection{Kapselung} Kapselung ist das Verbergen der Implementierungsdetails von Typen (privater Bereich) vor Benutzern. Anstelle vom direkten Zugriff definiert man eine Schnittstelle (öffentlicher Bereich) zum kontrollierten Zugriff auf Werte und Funktionalität. Kapselung ermöglicht das Sicherstellen von Invarianten, sowie den Austausch von Implementierungen ohne Anpassungen von Benutzercode. \subsection{Subtyping (nicht prfgs relevant)} Typhierarchien mit Super- und Subtypen können Verwandtschaftbeziehungen sowie Abstraktionen und Spezialisierungen modellieren. \medskip Ein Subtyp unterstützt mindestens die Funktionalität, die auch der Supertyp unterstützt - in der Regel aber mehr, d.h. Subtypen erweitern die Schnittstellen ihrer Supertypen (Spezialisierung). Daher können Subtypen überall dort eingesetzt werden, wo Supertypen verlangt sind und Funktionen, die auf Supertypen operieren können, können auch auf Subtypen operieren. \begin{center} \eqbox{\begin{tabular}{l} \code{struct Exp} \{ ... \} \\ \code{struct BinExp : public Exp} \{ .. \} \\ \end{tabular}} \end{center} Subtyprelationen sind transitiv, d.h. ein Subtyp von \code{BinExp} wäre auch ein Subtyp von \code{Exp}. Man sagt: - \code{BinExp} ist eine von \code{Exp} \emph{abgeleitete Klasse} (oder Subklasse, Kindklasse). - \code{Exp} ist die \emph{Basisklasse} (oder Superklasse, Elternklasse) von \code{BinExp}. \subsubsection{Vererbung} Abgeleitete Klassen erben die Funktionalität, d.h. die Implementierungen von Memberfunktionen, ihrer Elternklassen. Dies ermöglicht es, gemeinsam genutzten Code wiederverwenden zu können und vermeidet so Codeduplikation. \medskip Geerbte Implementierungen können auch überschrieben werden, um zu erreichen, dass eine abgeleitete Klasse sich anders verhält als ihre Elternklasse. \subsection{Polymorphie und dynamische Bindung (nicht prfgs relevant)} Ein Zeiger vom \emph{statischen Typ} \code{T}$_1$ kann zur Laufzeit auf Objekte vom \emph{dynamischen Typ} \code{T}$_2$ zeigen, falls \code{T}$_2$ ein Subtyp von \code{T}$_1$ ist. Wird eine virtuelle Memberfunktion von einem solchen Zeiger aus aufgerufen, so entscheidet der dynamische Typ darüber, welche Funktion ausgeführt wird (dynamische Bindung). \medskip Zusammen mit Subtyping kann man so neue konkrete Typen zu einem bestehenden System hinzuzufügen, ohne dieses abändern zu müssen! Bei Memberfunktionen ohne \code{virtual} wird immer die Memberfunktion des statischen Typ (hier \code{Exp}) ausgeführt. \begin{center} \eqbox{\begin{tabular}{l} \code{struct Exp} \{ \\ \code{\quad virtual int size() const = 0;} \\ \} \\ \end{tabular}} \end{center} Das \code{= 0} erzwingt eine Implementierung durch abgeleitete Klassen. Solange es in einer Klasse eine Memberfunktion mit \code{= 0} gibt, ist es eine \emph{abstrakte Klasse}, welche nicht als Objekt instanziert werden kann. \end{multicols*} \setcounter{secnumdepth}{2} \begin{center} \includegraphics[width=1\linewidth]{Bilder/ASCII-Table-wide.png} \end{center} \end{document}