Variablen & Datentypen
C's Typsystem: int, char, float, double plus die stdint-Typen, Konstanten, Enums und Typkonvertierungen.
Inhaltsverzeichnis
Variablen & Datentypen in C
C ist statisch typisiert - jeder Variablentyp steht vor dem Namen. Die Sprache hat relativ wenige primitive Typen, aber einige Besonderheiten.
Variablen deklarieren
int alter = 28;
double pi = 3.14159;
char initial = 'A';
- Typ, dann Name, dann optional ein Wert
- Semikolon am Ende
Du kannst Variablen getrennt deklarieren und initialisieren:
int alter;
alter = 28;
Primitive Datentypen
Ganzzahlen
| Typ | Typische Groesse | Bereich |
|---|---|---|
char | 1 Byte | -128 bis 127 (signed, meistens) |
short | 2 Byte | -32.768 bis 32.767 |
int | 4 Byte | ca. -2,1 Mrd. bis 2,1 Mrd. |
long | 4 oder 8 Byte | systemabhaengig |
long long | 8 Byte | sehr gross |
Jeder hat eine unsigned-Variante (nur nicht-negativ, verdoppelt den positiven Bereich):
unsigned int zaehler = 0;
Achtung: Die Groessen sind nicht vom Standard festgelegt (ausser Mindestgroessen). Fuer genaue Groessen gibt es <stdint.h>:
#include <stdint.h>
int8_t i8 = 127;
int16_t i16 = 32767;
int32_t i32 = 2147483647;
int64_t i64 = 9000000000000LL;
uint8_t u8 = 255;
Im Embedded-Bereich nutzt man fast nur stdint-Typen.
Fliesskomma
| Typ | Groesse | Genauigkeit |
|---|---|---|
float | 4 Byte | ~7 Stellen |
double | 8 Byte | ~15 Stellen |
long double | 8-16 B | systemabhaengig |
float f = 3.14f; // Suffix f = float
double d = 3.14159; // Default
long double ld = 3.14159L;
Achtung mit Gleichheit: Fliesskomma-Vergleiche mit == sind unzuverlaessig wegen Rundungsfehlern. Besser:
#include <math.h>
if (fabs(a - b) < 0.0001) {
// fast gleich
}
char - Einzelzeichen
char c = 'A'; // wird als 65 gespeichert (ASCII)
char c2 = 65; // gleichwertig
char ist technisch eine kleine Ganzzahl. Ob signed oder unsigned standardmaessig, ist systemabhaengig.
Kein eingebauter bool
C hatte lange keinen echten Boolean. Heute gibt es _Bool und stdbool.h:
#include <stdbool.h>
bool aktiv = true;
bool fertig = false;
Ohne den Include nutzt man oft int:
int aktiv = 1;
int fertig = 0;
Literals
int dezimal = 42;
int hex = 0xFF; // 255
int oktal = 017; // 15 (Vorsicht: fuehrende 0!)
int binaer = 0b1010; // 10 (C23-Feature, nicht ueberall)
unsigned int gross = 4000000000U;
long lang = 1000000L;
long long sehr_lang = 1000000000000LL;
double d = 1.5e3; // 1500.0
float f = 3.14f;
Konstanten
#define (Preprocessor)
#define PI 3.14159
#define MAX_ARRAY 100
int arr[MAX_ARRAY];
double flaeche = PI * radius * radius;
Der Preprocessor ersetzt einfach den Text vor der Kompilierung.
const (typsicher)
const double PI = 3.14159;
const int MAX_ARRAY = 100;
const-Variablen werden typgeprueft - meist die bessere Wahl.
enum
Fuer zusammengehoerige Konstanten:
enum Richtung {
NORD,
OST,
SUED,
WEST
};
enum Richtung r = OST;
printf("%d\n", r); // 1 (NORD=0, OST=1, ...)
Du kannst explizite Werte vergeben:
enum HTTP {
OK = 200,
NOT_FOUND = 404,
SERVER_ERROR = 500
};
Arrays
int zahlen[5] = {10, 20, 30, 40, 50};
printf("%d\n", zahlen[0]); // 10
printf("%d\n", zahlen[4]); // 50
// Groesse bestimmen
size_t n = sizeof(zahlen) / sizeof(zahlen[0]);
printf("%zu Elemente\n", n); // 5
Wichtig: Arrays in C kennen ihre eigene Groesse nicht. Wenn du sie an Funktionen uebergibst, musst du die Groesse separat mitgeben.
Strings sind Arrays
char name[] = "Anna";
// entspricht: char name[] = {'A', 'n', 'n', 'a', '\0'};
Das \0 am Ende (Null-Byte) markiert das String-Ende. Pflicht fuer alle Funktionen wie printf("%s") oder strlen.
Typkonvertierung
Implizit
int i = 5;
double d = i; // OK - kleiner zu groesser
Explizit mit Cast
double d = 3.7;
int i = (int) d; // 3 - Nachkomma wird abgeschnitten
sizeof
Liefert die Groesse eines Typs oder einer Variable in Bytes:
printf("int hat %zu Byte\n", sizeof(int)); // meist 4
printf("double hat %zu Byte\n", sizeof(double)); // meist 8
int arr[100];
printf("%zu Bytes\n", sizeof(arr)); // 400
%zu ist der Format-Specifier fuer size_t.
Scope
Variablen haben einen Gueltigkeitsbereich - den Block ({ ... }), in dem sie deklariert wurden:
int main(void) {
int x = 10; // im main-Scope
if (x > 5) {
int y = 20; // nur im if-Scope
printf("%d\n", y);
}
// printf("%d\n", y); // FEHLER - y nicht sichtbar
return 0;
}
static fuer Langlebigkeit
Lokale Variablen verschwinden nach dem Block. static macht sie permanent:
void zaehler(void) {
static int n = 0; // nur einmal initialisiert
n++;
printf("%d\n", n);
}
int main(void) {
zaehler(); // 1
zaehler(); // 2
zaehler(); // 3
return 0;
}
Praktisches Beispiel
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
int main(void) {
enum Statuscode {
OK = 200,
NOT_FOUND = 404
};
const double STEUERSATZ = 0.19;
int32_t anzahl = 3;
double netto = 19.99;
double brutto = netto * (1 + STEUERSATZ);
double gesamt = brutto * anzahl;
bool teuer = gesamt > 100.0;
printf("Anzahl: %d\n", anzahl);
printf("Brutto: %.2f\n", brutto);
printf("Gesamt: %.2f (%s)\n", gesamt, teuer ? "teuer" : "okay");
printf("Status: %d\n", OK);
return 0;
}
Zusammenfassung
- Primitive Typen:
int,char,float,double- plusstdint.hfuer exakte Groessen constist typsicherer als#definestdbool.hfuer echte Booleans- Arrays kennen ihre Groesse nicht - Groesse mitfuehren oder
sizeofnutzen - Strings in C sind nullterminierte Char-Arrays
- Scope ist block-basiert,
staticmacht lokale Variablen langlebig
Im naechsten Kapitel: Kontrollstrukturen - if, switch und Schleifen.