#include <stdio.h> // Verwende den Baukasten stdio (fĂĽr printf)
int main() { // Einstiegspunkt jedes C-Programms
printf("Hello World");
printf("");
printf("");
return 0;
}
main() ist der Einstiegspunkt jedes C-Programmsprintf und main() → Rest folgt!Aber: Wie werden Informationen im Computer abgebildet?
Hier: Der Text (String) "Hello World"
Name:
Matrikelnummer:
Temperatur:
Anordnung von Buchstaben (Zeichenkette)
nicht-negative ganze Zahl
nicht-negative reelle Zahl
Dies alles nennt man Datentypen
Computer speichert Informationen im Binärformat:
1 oder 0 (= genannt Bit)
Kombination von mehreren Ziffern bildet Binärzahl: 1001
Jede Stelle der Binärzahl steht für eine Zweierpotenz:
\(2^0 = 1, 2^1 = 2, 2^2 = 4, 2^3 = 8, ...\)
Summe der einzelnen Werte ergibt Zahl im Dezimalsystem
79 = 64 + 8 + 4 + 2 + 1 = 26 + 23 + 22 + 21 + 20| 27 = 128 | 26 = 64 | 25 = 32 | 24 = 16 | 23 = 8 | 22 = 4 | 21 = 2 | 20 = 1 |
|---|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 |
8 Bits ergeben dabei 1 Byte →28 = 256 mögliche Werte pro Byte
| 512 | 256 | 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|---|---|
| 1 | 0 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 1 |
591 =0000 0010 x 256 +0100 1111| 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 |
|---|---|---|---|---|---|---|---|
| 0 (MSBit) | 1 | 0 | 0 | 1 | 1 | 1 | 1 (LSBit) |
110 (Binär) ≠110 (Dezimal)110B = 6D32D = 20H = 0010 0000B255D = FFH = 1111 1111B1000D = 3E8H = 11 1110 1000B| Dez. | Hex. | Dez. | Hex. |
|---|---|---|---|
| 0 | 0 | 8 | 8 |
| 1 | 1 | 9 | 9 |
| 2 | 2 | 10 | A |
| 3 | 3 | 11 | B |
| 4 | 4 | 12 | C |
| 5 | 5 | 13 | D |
| 6 | 6 | 14 | E |
| 7 | 7 | 15 | F |
Vorteile der hexadezimalen Darstellung:
16 Werte → \(2^4\) → 4 Bit zur Darstellung → 2 x 4 Bit → 1 Byte
→ Darstellung von 1 Byte mit nur zwei Zeichen
Deutlich leserlicher als eine Binärzahl!
Hexadezimal ist vielfaches von Binärsystem → einfache Umwandlung
FF FFH besser als 1111 1111 1111 1111BBei Bytes gibt es oft Verwirrung bei den Präfixen für Einheiten: Kilo, Mega, …
Hersteller verwenden Dezimalsystem!
→ 1000 Bytes = 1 Kilobyte
Programmierer:innen denken hingegen im Binärsystem
→ 210 = 1024 Bytes = 1 Kilobyte
Daher Unterscheidung über zusätzliches Präfix
→ Beispiel: Anstatt Kilobyte, nun Kibibyte
Faustformel: Erweiterung um 10 Bits ist eine Erhöhung um den Faktor ~1000 (gut für ungefähre Größenabschätzung) 106
| Bytes (dezimal) | Bezeichnung | Bytes (binär) | Bezeichnung |
|---|---|---|---|
| 103 | Kilobyte (KB) | 210 | Kibibyte (KiB) |
| 106 | Megabyte (MB) | 220 | Mebibyte (MiB) |
| 109 | Gigabyte (GB) | 230 | Gibibyte (GiB) |
| 1012 | Terabyte (TB) | 240 | Tebibyte (TiB) |
| 1015 | Petabyte (PB) | 250 | Pebibyte (PiB) |
| 1018 | Exabyte (EB) | 260 | Exbibyte (EiB) |
#include <stdio.h>
int main() {
int i = 3; // Befehl 1: Erzeuge Variable mit Ganzzahl (Integer)
i = i + 5; // Befehl 2: Addiere 5, weise die Summe i zu
printf("%d", i); // Befehl 3: Nun gib i aus
return 0;
}
;)Anlegen der Variable num: int num = 3;
int: Typ der Variablenum: Bezeichner, führt den Namen num ein3: Initialisierung, initialisiert num mit 3int)num ist von nun an eine Variablenum kann ab Deklaration „abwärts” weiterverwendet werdenEinfache Datentypen sind elementar → nicht auf andere Typen zurückführbar
(pod = plain old datatypes)
Beispiele:
int i = 3;float f = 3.14;char c = 'c';Achtung: verzeichenlos ↔︎ verzeichenbehaftet
unsigned int num = 3;signed wird ein Bit geopfert fĂĽr das Vorzeichen| Bits | Bytes | Werte | Name in C/C++ | Min. Breite | Typ. Breite | Feste Breite |
|---|---|---|---|---|---|---|
| 8 | 1 | 0…255 | unsigned char | 8 | 8 | uint8_t |
| 16 | 2 | 0…65 535 | unsigned short | 16 | 16 | uint16_t |
| 32 | 4 | 0…4 294 967 295 | unsigned int | 16 | 32 | uint32_t |
| 64 | 8 | 0…4 294 967 295 | unsigned long int | 32 | 32 | uint32_t |
| 64 | 8 | 0…18 446 744 073 709 551 615 | unsigned long long int | 64 | 64 | uint64_t |
🚨 Breite in Bits ist abhängig von der Hardwarearchitektur! 🚨
| Bits | Bytes | Werte | Name in C/C++ | Min. Breite | Typ. Breite | Feste Breite |
|---|---|---|---|---|---|---|
| 8 | 1 | -128…127 | char | 8 | 8 | int8_t |
| 16 | 2 | -32768…32767 | short | 16 | 16 | int16_t |
| 32 | 4 | -2 147 483 648…2 147 483 647 | int | 16 | 32 | int32_t |
| 64 | 8 | -2 147 483 648…2 147 483 647 | long int | 32 | 32 | int32_t |
| 64 | 8 | -263 … 263-1 | long long int | 64 | 64 | int64_t |
🚨 Breite in Bits ist abhängig von der Hardwarearchitektur! 🚨
| Zulässig | Nicht zulässig |
|---|---|
| Winkel | nichtOk! |
| EinkomSteuer | 7CR |
| einkom_steuer | x-2 |
| wichtigeVariable | wichtige Variable |
| _OK | int |
| x3 | float |
| __x3_und_x4_ | |
| _99 |
Schlüsselwörter sind reservierte Wörter der jeweiligen Programmiersprache!
| auto | break | case | char | const | continue |
| default | do | double | else | enum | extern |
| float | for | goto | if | inline | int |
| long | register | restrict | return | short | signed |
| sizeof | static | struct | switch | typedef | union |
| unsigned | void | volatile | while | true (C23) | false (C23) |
Zusätzliche Schlüsselwörter in C++ (auszugsweise, siehe cppreference.com)
| and | and_eq | asm | bitand | bitor | catch |
| class | compl | constexpr | const_cast | delete | dynamic_cast |
| explicit | for | friend | false | namespace | new |
| noexcept | not | not_eq | nullptr | operator | or |
| or_eq | private | protected | public | reinterpret_cast | static_cast |
| template | this | throw | true | try | typename |
| using | virtual | xor | xor_eq |
Es gibt zahlreiche Möglichkeiten für die Benennung
Am weitesten verbreitete Konventionen
Snake Case
int count_variable_1 = 0;Konstante Variablen, deren Wert sich nicht verändert, werden nur groß geschrieben
(Bsp.: const int RESISTOR_VAL_470 = 470;)
int countVariable2 = 0;_| Operation | Operator |
|---|---|
| Addition | + |
| Subtraktion | - |
| Multiplikation | * |
| Division | / |
| Division mit Rest (Modulo) | % |
Modulo-Operation: Division zweier Zahlen, Ergebnis entspricht dem Rest
Beispiel: Ăśberlauf abfangen bei einer Uhr
#include <stdio.h>
int main() {
int stunde = 22;
int minute = 59;
minute = (minute + 1) % 60;
stunde = (stunde + 1) % 24;
printf("%d:%d", stunde, minute);
return 0;
}
#include <stdio.h>
int main() {
int i = 3;
i = i + 13; // 16
i = i * 5; // 80
i = i / 8; // 10
i = i % 3; // 1 => 9/3 und Rest 1
printf("%d", i);
return 0;
}
Arithmetische Operation und Zuweisung in einem
| Operation | Operator |
|---|---|
| Addition | += |
| Subtraktion | -= |
| Multiplikation | *= |
| Division | /= |
| Division mit Rest (Modulo) | %= |
#include <stdio.h>
int main() {
int i = 3;
i += 13;
i *= 5;
i /= 8;
i %= 3;
printf("%d", i);
return 0;
}
++ (Increment)-- (Decrement)++ii++--i, i--#include <stdio.h>
int main() {
int i = 0;
++i;
++i;
++i;
--i;
printf("%d", i);
return 0;
}
#include <stdio.h>
int main() {
int i = 3;
i = ((i + 13) * 5) / 8) % 3;
printf("%d", i);
return 0;
}
( Hier sind Klammern wichtig, die Operatoren haben wie in der Mathematik auch eine unterschiedliche Wichtigkeit)
Spielt eine Rolle, wenn keine Klammerung vorhanden ist
Beschreibt die Bindung an Operanden
Operatoren sind in Gruppen eingeteilt
Je höher die Präzedenz, desto stärker binden sie an die Werte / Variablen
(=„je größer die Präzedenz, desto stärker die Anziehungskraft”)
Vollständige Tabelle aller Operatoren findet sich hier unter cppreference.com
Muss nicht auswendig gelernt werden!
Die meisten Präzendenzen ergeben sich intuitiv,
aber am Anfang muss man ggf. häufiger nachschauen
Tipp: Im Zweifelsfall Klammern setzen (erhöht auch meistens die Lesbarkeit)
#include <stdio.h>
int main() {
int i = 1;
i = i++;
printf("%d", i);
return 0;
}
132Angenommen eine Variable hat den höchsten darstellbaren Wert
und wird dann erhöht: uint16_t i = 65535; ++i;
Was wird passieren?
01 0000 0000 0000 0000)-65535Verlasst euch nie auf undefiniertes Verhalten!
#include <stdio.h>
int main() {
int wert = 22;
wert = wert / 5 * 5;
printf("%d", wert);
return 0;
}
Auch Teilschritte sind betroffen!
| Bits | Bytes | Werte | Name in C/C++ |
|---|---|---|---|
| 32 | 4 | \(+/- 3.4 * 10^{38}\) | float |
| 64 | 8 | \(+/- 1.7 * 10^{308}\) | double |
floatdouble#include <stdio.h>
int main() {
float f = 3.11231231231231231231231f;
double d = 3.11231231231231231231231;
printf("%.20f\n", f);
printf("%.20f\n", d);
}
| \(8^3\) | \(8^2\) | \(8^1\) | \(8^0\) |
|---|---|---|---|
| 0 | 2 | 0 | 2 |
→ \(2 \cdot 8^2 + 2 \cdot 8^0 = 2 \cdot 64_D + 2 \cdot 1 = 130_D\)
0x an: 0x42 = 66D0: 042 = 34D0b: 0b101 = 5D (nur C++; seit C++14)' zwecks Leserlichkeit: 10'500'000#include <stdio.h>
int main() {
int i = 3;
i = i + 5;
printf("%d", i);
return 0;
}
Jetzt fehlt nur noch printf()
char repräsentiert: char c = 'a';'\n''\0'| Zeichen | Bedeutung |
|---|---|
\t |
Horizontaler TAB |
\0 |
NUL |
\n |
New line |
\" |
AnfĂĽhrungszeichen |
\' |
Hochkomma |
\\ |
Backslash |
#include <stdio.h>
int main() {
char c1 = 'A';
char c2 = 'a';
printf("%d\n", c1);
printf("%d\n", c2);
return 0;
}
int a = 'A' - 'a';'a' == 65"char * text = "Hello World";char * → Kapitel 9NULL-terminiert
NULL-Byte ('\0')"Hello World"
"Hello World\0"Wir waren hiermit gestartet …
#include <stdio.h>
int main() {
int i = 3;
i = i + 5;
printf("%d", i);
return 0;
}
ZurĂĽck zu printf()!
printf()printf() verwendet sogenannten Formatstring, um an entsprechenden Stellen den Inhalt von Variablen einzusetzen| Spezifizierer | Umwandlung |
|---|---|
%d |
Ganzzahl (Dezimal) |
%x |
Ganzzahl (Hexadezimal) |
%s |
String |
%c |
Character |
%f |
Float |
printf() wandelt die gegebenen Variablen in Text um/ fügt sie in den Formatstring einprintf("%.2f", 3.14159); → 3.14| Spezifizierer | Umwandlung |
|---|---|
%d |
Ganzzahl (Dezimal) |
%x |
Ganzzahl (Hexadezimal) |
%s |
String |
%c |
Character |
%f |
Float |
scanf()Wir können nun mit unserem Programm interagieren 🥳
int num_array; → ein Integerint num_array[5]; → ein Feld mit fünf Integernchar a = "Hello World"; → geht nicht!char a[] = "Hello World";int num_array[5];
Erstellt Variable namens num_array als
aufeinanderfolgende und zusammenhängende Menge von 5 int-Werten
Zugriff auf einzelne Elemente ĂĽber Index
0[0, n-1][0,4]Zugriff auf erstes Element mit [0] → printf("%d", num_array[0]);
Schreiben ist äquivalent dazu: num_array[0] = 1;
int num_array[5];
num_arrays[0] = 1;int num_arras[5] = {1, 2, 3, 4, 5};int num_arras[5] = {1, 2};#include <stdio.h>
int main() {
float f[3] = {1.0, 2.3};
printf("f[0] = %.1f\n", f[0]);
printf("f[1] = %.1f\n", f[1]);
printf("f[2] = %.1f\n", f[2]);
return 0;
}
Grund dafĂĽr ist einfach:
Menge an benötigtem Speicher muss vorher bekannt sein
(→ aufeinanderfolgend und zusammenhängend)
Denkt vorher über die Array-Größe nach!
(), {}, [])() → Parentheses (Parenthesen){} → Braces / Curly Braces (Akkoladen)[] → Brackets (Eckige Klammern)<>) (Winkelklammern)Hello World-Beispiel die Grundzüge