Einstieg in C
C wird vor dem Start komplett übersetzt. Jede Variable hat einen festen Typ, und das Programm startet immer in main.
2.1.1
Vom Quelltext zum Programm
#include <stdio.h> int main(void) { printf("Hallo\n"); return 0; }
- Präprozessor → Compiler → Linker
- Fehlermeldungen von oben abarbeiten,
-Wallfür Warnungen - Python interpretiert, C übersetzt vorab
gcc hallo.c -o hallo · ./hallo2.1.2
Datentypen und printf
int,double,float,char('A')- deklarieren vor Gebrauch, Typ bleibt fest
7 / 2= 3,7 % 2= 1,7.0 / 2= 3.5- Cast:
(double) a / b %d %f %.2f %c %5d %%,\n,\t
printf("%8.2f", x) → 8 Zeichen breit2.1.3
Kontrollstrukturen
if / else if / else,switchmitbreak== != < <= && || !; 0 = falsch, sonst wahr- Falle:
if (x = 5)ist immer wahr whileprüft vorher,do … whilemind. einmal
for (int i = 0; i < n; i++) ≙ range(n)2.1.4
Funktionen und Header
- Rückgabetyp, Name, Parameter;
void= kein Rückgabewert - Parameter sind Kopien (call by value)
- Prototyp vor
mainoder in der.h #include "rechner.h"+ Include-Guard
gcc main.c rechner.c -o rechnerWarum 7 / 2 nicht 3,5 ist
Der Typ des Ergebnisses richtet sich nach den Operanden, nicht nach der Zielvariable. Zwei int ergeben ein int — erst ein Cast oder 2.0 macht daraus eine Kommarechnung.
Nah an der Hardware
C gibt direkten Zugriff auf den Speicher: Adressen, Zeiger, Arrays — und läuft auf Mikrocontrollern.
2.2.1
Speicher und Adressen
- Speicher = Folge von Bytes mit Adressen (hex)
- typisch: char 1, int 4, double 8 Byte —
sizeofmisst nach &x= Adresse, Ausgabe mit%p- Adressen ändern sich bei jedem Start
scanf("%d", &x);2.2.2
Zeiger
int x = 4; int *p = &x; // p zeigt auf x *p = 7; // x ist jetzt 7
NULL= zeigt auf nichts- Zeigertyp passt zum Variablentyp
- Zeigerparameter ändern Variablen des Aufrufers
void tausche(int *a, int *b) · tausche(&x, &y)2.2.3
Arrays und Zeichenketten
int w[5] = {…};→ Indizes 0 … 4, keine Grenzprüfung- Anzahl:
sizeof(w) / sizeof(w[0]) - Array-Name = Adresse des ersten Elements
char s[] = "Lena";belegt 5 Byte (mit\0)strlen,strcpy,strcmpaus<string.h>
strcmp(a, b) == 0 statt a == b2.2.4
Mikrocontroller
- Arduino Uno: ATmega328P, 16 MHz, 2 KB RAM, 32 KB Flash
setup()einmal,loop()endlospinMode,digitalWrite,digitalRead,delay(ms)INPUT_PULLUP: gedrückt =LOW
&x liefert die Adresse, *p den Wert dortint *p = &x; — der * gehört dann zur Deklaration, nicht zum Dereferenzieren.Warum C keine Array-Grenzen prüft
C übersetzt einen Zugriff a[i] direkt in „Startadresse + i · Elementgröße“. Das ist schnell, aber niemand kontrolliert, ob i passt. Ein Zugriff daneben ist undefiniertes Verhalten — kein Compilerfehler.
Von C zu C++
C++ erweitert C um Streams, Zeichenketten, Referenzen und Klassen — fast jeder C-Code läuft weiter.
2.3.1
Was C++ ergänzt
#include <iostream> #include <string> using namespace std; string name; cin >> name; cout << "Hi " + name << endl;
string:+verketten,.length(),==vergleicht Inhaltboolmittrue/false- Referenz
int &r = x;, Referenzparameter ohne&beim Aufruf using namespace std;nicht in Header
g++ prog.cpp -o prog2.3.2
Klassen in C++
class Lampe { private: bool an; public: Lampe() { an = false; } void schalten() { an = !an; } }; // Semikolon!
- Objekt ohne
new:Lampe l;, Aufrufl.schalten(); - Kapselung: Attribute private, Methoden public
- außerhalb:
void Lampe::schalten(), Aufteilung .h / .cpp struct= Klasse, standardmäßig public
class Name { private: … public: … };2.3.3
Ein Konsolenspiel bauen
- Zufallszahl, Schleife bis Treffer, Hinweise größer/kleiner, Versuche zählen
#include <cstdlib>,<ctime>srand(time(0))genau einmal- Halbieren: höchstens 7 Tipps für 1 … 100, da 27 = 128 ≥ 100
a + rand() % (b - a + 1) → a … brand() % n → 0 … n − 1, also a + rand() % (b - a + 1) → a … b1 + rand() % 6 liefert 1 … 6.Referenz oder Zeiger?
Beide erlauben einer Funktion, die Variable des Aufrufers zu ändern. Die Referenz ist bequemer (kein *, kein & beim Aufruf) und zeigt immer auf dieselbe Variable; ein Zeiger kann umgesetzt werden oder NULL sein.
Die Regeln, an denen die Punkte hängen
Diese Punkte kosten in Arbeiten zu C und C++ am häufigsten Punkte — prüfe sie bei jeder Aufgabe.
Ausgaben Zeile für Zeile verfolgen
Bei „Was gibt das Programm aus?“ eine Tracetabelle mit allen Variablen anlegen. Bei jeder Division prüfen: Sind beide Operanden int? Dann wird abgeschnitten.
Kopie, Adresse oder Referenz?
Vor jedem Funktionsaufruf klären: Wird ein Wert kopiert (int x), eine Adresse übergeben (int *x, Aufruf mit &) oder eine Referenz (int &x)? Nur die letzten beiden ändern die Variable des Aufrufers.
Grenzen und Endezeichen
Indizes laufen von 0 bis n − 1, Zeichenketten brauchen ein Byte für \0. Bei INPUT_PULLUP heißt gedrückt LOW, und srand steht nur einmal im Programm.
