Zum Inhalt springen
C Anfรคnger 25 min

Variablen & Datentypen

C's Typsystem: int, char, float, double plus die stdint-Typen, Konstanten, Enums und Typkonvertierungen.

Aktualisiert:
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

TypTypische GroesseBereich
char1 Byte-128 bis 127 (signed, meistens)
short2 Byte-32.768 bis 32.767
int4 Byteca. -2,1 Mrd. bis 2,1 Mrd.
long4 oder 8 Bytesystemabhaengig
long long8 Bytesehr 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

TypGroesseGenauigkeit
float4 Byte~7 Stellen
double8 Byte~15 Stellen
long double8-16 Bsystemabhaengig
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 - plus stdint.h fuer exakte Groessen
  • const ist typsicherer als #define
  • stdbool.h fuer echte Booleans
  • Arrays kennen ihre Groesse nicht - Groesse mitfuehren oder sizeof nutzen
  • Strings in C sind nullterminierte Char-Arrays
  • Scope ist block-basiert, static macht lokale Variablen langlebig

Im naechsten Kapitel: Kontrollstrukturen - if, switch und Schleifen.

Zurรผck zum C Kurs