Anzeige

VBA
Programmierer
gesucht?
 
Anzeige
VBA Programmierer gesucht?
 

C/C++ Grundlagen und Zusammenfassung für Anfänger!

Nützliche Daten, Begriffe und Fakten mit vielen Quelltextbeispielen in einem Tutorial zusammengefasst. Für Neueinsteiger und Anfänger geeignet.

Dieses Tutorial ist eine kostenlose stichwortartige Zusammenfassung wichtiger Fakten, Fachbegriffe, Grundlagen und Beispiele für Anfänger! Es ersetzt auf keinen Fall eine professionelle Schulung, ein Seminar oder ein Lehrbuch. Als Ergänzung zu Ihrem Lernprozess ist diese Zusammenfassung, als kleines Nachschlagewerk, jedoch ein geeignetes Mittel.




Inhaltsverzeichnis




Grundaufbau eines Programms

Mehrzeilige Kommentarzeilen werden durch /* und */ gekennzeichnet,
dagegen werden einzelne Kommentarzeilen durch führende // gekennzeichnet.

Die Präprozessoranweisungen werden durch ein # Zeichen eingeleitet. #include <stdio.h> bindet Standardfunktionen aus der Bibliothek stdio.h (Header) und der dazugehörigen stdio.cpp (Quelldatei) in unser Programm ein. Die Funktionen der Bibliothek können somit von uns als Programmierer verwendet werden.

Mit Prototyp-Deklarationen wird dem Compiler angezeigt, welche Funktionen im Anschluss an das Hauptprogramm ausprogrammiert zu finden sind. Alternativ kann die vollständige Funktion vor dem Hauptprogramm codiert werden.

Das Hauptprogramm wird durch void main() definiert.

void bedeutet, dass die Funktion keinen Rückgabewert erzeugt.


Wichtiger Hinweis: Bei allen Beispielen in diesem Tutorial sind die #include Anweisungen weggelassen worden. Bitte binden Sie die entsprechend benötigten Dateien ein, wenn Sie die Quelltexte testen möchten.


/* Mehrzeilige
    Kommentarzeilen */


// Einzelne Kommentarzeile

// Präprozessoranweisungen
#include <stdio.h>

// Prototypen-Deklarationen für Funktionen
void meinefunktion ();

// Hauptprogramm
void main()
{
    // Funktionsrumpf
}

// Weitere Funktionen
void meinefunktion () // Funktions-Definition
{

}




Variablen und Konstanten

Definition Variable
Eine Variable ist ein festgelegter Speicherplatz einer bestimmten Größe und eines bestimmten Typs, der über einen eindeutigen Namen und einer eindeutigen Adresse im Arbeitsspeicher angesprochen werden kann.

Definition Konstanten
Speichern von konstanten Werten im Arbeitsspeicher. Vorstellbar als schreibgeschützte Variable.

Datentypen Beschreibung Wertebereich Speicherbedarf
char Zeichen 0 bis 255 (ASCII-Zeichen) 1 Byte
int Ganzzahl Ausgeschrieben: Integer 2 (16 Bit) oder
4 (32 Bit) Bytes
short int
short
Ganzzahl -32768 bis 32767 2 Bytes
long int
long
Ganzzahl -2.147.483.648 bis 2.147.483.647 4 Bytes
float Fließkommazahl 3,4E-37 bis 3,4E+38
Dezimal bis 7 Ziffern Genauigkeit
4 Bytes
double Fließkommazahl 1,7E-307 bis 1,7E+308
Dezimal bis 15 Ziffern Genauigkeit
8 Bytes

Unsigned / Signed Datentypen
unsigned = Vorzeichenlose Datentypen
   Beispiel: unsigned short int (Wertebereich: 0 bis 65535)

signed = Datentypen mit Vorzeichen
   Beispiel: short int (Wertebereich: -32768 bis 32767)

Rechnen und Arbeiten mit Variablen und Konstanten
Die Deklaration legt die Variable im Arbeitsspeicher an.
Bei der Initialisierung wird der Variablen nach der Anlage ein vorbelegter Wert zugewiesen.
Die Wertzuweisung erfolgt über den Operator "=".
Konstanten werden mit dem Präfix const deklariert.
Konstanten werden üblicherweise in Großbuchstaben geschrieben um diese im Quelltext erkenntlich zu machen.

Grundregeln:
1. Alle Variablen müssen deklariert werden
2. Alle Variablen sollten initialisiert werden

// Deklaration einer int Variablen mit dem Namen iZahl1
int iZahl1;

// Deklaration und Initialisierung
int iZahl1 = 47;

// Kettendeklaration
int a, b = 5, c = b;

// Wertzuweisung
iZahl1 = 11;

// Deklaration einer Konstanten
const double PI = 3.141;


Arithmetische Operatoren
Operator Erklärung
= Zuweisung
+ Addition
- Subtraktion
* Multiplikation
/ Division
% Modulo-Division (Restwert)

Zusammengesetzte Operatoren
Operator Beispiel Kurzschreibweise Beispiel Langschreibweise
+= i += 2 i = i + 2
*= i *= 3 i = i * 3
/= i /= 4 i = i / 4
-= i -= 5 i = i - 5

Explizite Typumwandlung durch Casting
Mit der Typenumwandlung können Variableninhalte in einen anderen Datentyp umgewandelt werden.

double dZahl1 = 5.1234;   // Dezimaltrennzeichen ist ein Punkt
double dErgebnis;

int iZahl2 = 10;
int iErgebnis;

iErgebnis = (int) dZahl1 + 3;   // iErgebnis = 8 (5+3)

dErgebnis = (float) iZahl2;   // dErgebnis = 10.0




Pointer (Zeiger)

Definition Pointer
Ein Pointer ist ein Variablentyp, welcher die Adresse einer anderen Variablen (eines bestimmten Datentyps) aufnehmen kann.

Erklärung
Pointer-Deklaration * nach einem Datentyp
Adressoperator & vor einer Variablen
Ergibt die Speicheradresse zur Variablen
Inhaltsoperator * vor einer Variablen
Gibt den Inhalt an der Adresse im Pointer

Verwendung z.B. bei Referenzübergabe oder verketteten Listen.

int iZahl1;   // Deklaration einer int Variablen mit dem Namen iZahl1

int* ipZ1;   // Deklaration Pointer

ipZ1 = &iZahl1;   // Zuweisung mit Adress-Operator &

iZahl1 = *ipZ1;   // Zugriff auf Inhalt an Adresse im Pointer

*ipZ1 = 17;   // Inhalt an Adresse im Pointer ändern

int iZahl2 = 47;
int* ipZ2 = &iZahl2;
int* ippZ2 = &ipZ2;
int* ipppZ2 = &ippZ2;

/* iZahl2 hat den Inhalt 47
Der Pointer ipZ2 hat den Wert 0011 DC04
Der Pointer ippZ2 hat den Wert 0011 DC12
Der Pointer ipppZ2 hat den Wert 0011 DC20
*ipZ2, **ippZ2 und **ipppZ2 haben den Wert 47 */



Mehrfach-Pointer
Abbildung 1 - Mehrfach-Pointer




Ein- und Ausgabebefehle - Teil 1

Einfache Ausgabe: printf
Befehl: printf("Ihre Eingabe: %i und %i", iZahl1, iZahl2);

Formatangaben für printf:

Erklärung
%d Dezimalzahl
%i Dezimalzahl
%c Zeichen (char)
%s Zeichenkette (string)
%f Gleitkommazahl

Steuerzeichen bei der Textausgabe:
Erklärung
\n Neue Zeile ASCII Wert 10
\r Carriage Return (Zeilenanfang) ASCII Wert 13
\t Horizontaler Tabulator ASCII Wert 9
\\ Backslash \
\b Backspace
\? Ergibt das Zeichen: ?
\' Ergibt das Zeichen: '
\" Ergibt das Zeichen: "

Einfache Eingabe: scanf
Befehl: returncode = scanf("%i %i", &iZahl1, &iZahl2);
returncode == EOF;   // STRG+Z wurde gedrückt
returncode == 0;   // Es wurde nichts eingelesen
returncode >= 1;   // Es wurden >= 1 Wert eingelesen

Formatangaben für scanf:
Erklärung
%d Dezimalzahl
%i Dezimalzahl
%c Zeichen (char)
%s Zeichenkette (string)
%f Gleitkommazahl

Leeren des Eingabepuffers: fflush(stdin);
Zeichenweise einlesen: char c = getchar();
Zeichen direkt einlesen: char c = getch();   // Keine Eingabetaste notwendig




Kontrollstrukturen

Es gibt grundlegend vier Kontrollstrukturen um eine strukturierte Programmierung sicherzustellen. Sie dienen der Ablaufsteuerung.
1. Sequenz, Folge von Befehlen und Anweisungen
2. Verzweigung, Alternativen
3. Wiederholungen, Iterationen, Schleifen
4. Aufruf weiterer Algorithmen

Verzweigungen, Alternativen
Es gibt mehrere Möglichkeiten.

Die einfache Verzweigung mit if.
Eine Bedingung gilt als erfüllt, wenn der Ausdruck der Bedingung erfüllt ist / wahr ist. Alle Zeilen innerhalb der geschweiften Klammern werden bei zutreffender Bedingung ausgeführt.

Verzweigung mit if und einem else-Zweig.
Der else-Zweig wird ausgeführt, wenn die Bedingung nicht erfüllt ist!

Verzweigung mit if und else sowie einem zusätzlichen Zweig und eigener Bedingung else if (Sonderfall)!

Mit logischen Operatoren können Bedingungen verknüpft oder invertiert (umgedreht, verneint) werden.

Vergleichsoperatoren Erklärung
== gleich
<, > kleiner, größer
<= kleiner gleich
>= größer gleich
!= ungleich

Logische Operatoren Erklärung
&& Konjunktion (UND)
|| Disjunktion (ODER)
! Negation (NICHT)

Und es geht auch noch kürzer!
?   Kurzform für if
:   Kurzform für else

// einfache Verzweigung
if (Bedingung1)
{
   Befehl1;
}

// Mit ELSE Zweig
if (Bedingung1)
{
   Befehl1;
}
else
{
   Befehl2;
}

// Kurzschreibweise
if (Bedingung1)
   Befehl1;
else
   Befehl2;

// Mit zusätzlicher (Sonderfall-) Bedingung2
if (Bedingung1)
{
   Befehl1;
}
else if (Bedingung2)
{
   Befehl2;
}
else
{
   Befehl3;
}

// 2 Bedingungen, die beide erfüllt sein müssen
if (Bedingung1 && Bedingung2)   // Konjunktion, UND
   Befehl1;

// Noch kürzere Schreibweise
Variable = (Zahl1 > Zahl2) ? Zahl1 : Zahl2;
// Dieses Beispiel bewirkt: Wenn Zahl1 kleiner als Zahl2 ist, so wird die Zahl1 in der
//    Variablen gespeichert. Ansonsten wird die Zahl2 in der Variablen gespeichert.


Mehrfachverzweigung
switch kann grundsätzlich 2 Typen unterscheiden:
   a) Zahlen
   b) Zeichen/Strings

Für dieses Beispiel wird die Variable vom Typ char verwendet. Bei Zahlen können die Anführungszeichen bei den case's weggelassen werden.
Die switch Anweisung prüft den Variableninhalt und springt an die entsprechende Stelle. Ein case definiert eine Sprungstelle für die Prüfung. Trifft der Wert hinter case zu, springt die switch Anweisung zu dieser Codezeile. Trifft keines der angegebenen case's zu, wird die default Zeile als Standardsprungziel verwendet.

switch (Variable)
{
   case 'A':   // Ist der Inhalt der Variablen
     Befehl1;   // ein A, wird hier weiter gemacht
     break;   // Ohne break; würden die kommenden Befehle sequenziell weiter verarbeitet werden!
    
   case 'B':   // Ist der Inhalt der Variablen
     Befehl2;   // ein B, wird hier weiter gemacht
     break;
    
   default:   // Wenn keines der Cases zugetroffen hat, wird hier weiter gemacht
     Befehl3;
     break;   // Diese Zeile kann auch ausgelassen werden, da keine weiteren Cases folgen
}


Iteration / Wiederholung / Schleifen

Die for -Schleife (Zählschleife):
Eine Zählvariable ist eine Variable, in der gezählt wird.
Diese wird nach jedem Durchlauf um eine Schrittweite erhöht.
Erhöhen nennt man Inkrementierung (i++)
Verkleinern nennt man Dekrementierung (i--)

Der Startwert gibt den Wert an, bei dem die Schleife anfängt zu zählen. Die Bedingung legt fest, wann die Schleifendurchläufe beendet werden.

// Die for-Schleife (Zählschleife)
for (Zählvariable; Bedingung; Schrittweite)
{
   Befehl1;   // Die Zeilen innerhalb der geschweiften Klammern werden so oft ausgeführt,
   Befehl2;   //    wie die Anzahl von Schritten der Zählschleife festlegt.
}

// Ein konkretes Beispiel:
// Zählschleife von 1 bis 10
// -> der Befehl1 wird somit 10 mal ausgeführt.
for (int i = 1; i <= 10; i++)
   Befehl1;   // Bei lediglich einem Befehl, können die geschweiften Klammern auch weggelassen werden


Die while-Schleife (Bedingungsschleife):
Solange die Durchlaufbedingung (Bedingung1) erfüllt ist, wird diese Schleife immer weiter durchlaufen.

Die kopfgesteuerte Schleife:
Nachdem die Bedingung geprüft wurde, werden die Befehle der geschweiften Klammer ausgeführt.

Die fußgesteuerte Schleife:
Die Befehle werden ausgeführt und anschließend wird die Bedingung geprüft und bei zutreffender Bedingung an den Schleifenkopf gesprungen.

Bei Bedingungsschleifen muss der Programmierer sicherstellen, das eine Inkrement- oder Dekrement-Anweisung stattfindet und auf jeden Fall ein Eintreffen der Durchlaufbedingung stattfindet. Sonst besteht die Gefahr einer Endlosschleife.

// Die while-Schleife (Bedingungsschleife)
while (Bedingung1)   // kopfgesteuert
{
   Befehl1;   // Schleifenrumpf
}

do
{
   Befehl1;
} while (Bedingung1)   // fußgesteuert

// Ein Beispiel: Von 1 bis 10 zählen
int i = 0;   // Initialisierung und Startwert
while (i <= 10)
{
   if (i == 5)
     continue; // Bewirkt, dass vorzeitig zum Schleifenende gesprungen wird.
               // Somit wird bei 5 der Befehl1 nicht ausgeführt!
   Befehl1;
   i++;   // Achtung: Nicht vergessen!
}


Aufruf weiterer Algorithmen
Funktionen ohne Rückgabewert werden einfach aufgerufen. Funktionen mit Rückgabewerten verwendet man wie eine Variable.




Funktionen

Funktionen dienen neben den Kontrollstrukturen zur Strukturierung und übersichtlicheren Gestaltung des Quelltextes. Funktionen müssen deklariert und definiert werden. Sie können Rückgabewerte erzeugen. Des Weiteren kann man Funktionen Parameter oder auch Argumente übergeben.

void meinefunktion(int iParameter1);   // Prototypen-Deklarationen
int funktionmitrueckgabe(int iParameter1);   // Mit Rückgabewert vom Typ int

void main();
{
   int iZahl1 = 0;   // Lokale Variable innerhalb main
   meinefunktion(iZahl1);   // Funktionsaufruf
   iZahl1 = funktionmitrueckgabe(iZahl1);   // Funktionsaufruf mit Rückgabewertwird wie eine Variable verwendet
}

void meinefunktion(int iParamerer1)
{
   int iZahl1 = 2;   // Lokale Variable innerhalb meinefunktion
   printf("Meine Zahl lautet: %i", iZahl1);
   // Kein Rückgabewert vorhanden, daher auch keine Zuweisung eines Rückgabewertes
}

int funktionmitrueckgabe(int iParamerer1)   // In den Klammern stehen die sog. "formellen Parameter"
{
   return iParameter1 * 2;   // return = Rückgabewert zuweisen!
}





Parameterübergabe "Call-by-Value"

int addition(int iZahl1, int iZahl2);   // Prototyp

void main()
{
   int iZahl1, iZahl2, iSumme;   // Variablen – Deklaration
   printf("Bitte 2 Zahlen eingeben: ");
   scanf("%i %i", &iZahl1, &iZahl2);
  
   iSumme = addition(iZahl1, iZahl2);   // Funktionsaufruf mit sog. "aktuellen Parametern"
   // Rückgabewert der Funktion wird in Variable iSumme gespeichert
  
   printf("Die Summe der Zahlen ist: %i \n", iSumme);   // Ergebnisausgabe
}

int addition(int iZahl1, int iZahl2)   // übergabe Call-By-Value (Wertübergabe)
{
   return iZahl1 + iZahl2;   // Rückgabewert
}





Parameterübergabe "Call-by-Reference"

Variante 1 mit Pointern und Adressen (in C und C++)

void addition(int iZahl1, int iZahl2, int* iSumme);   // Prototyp

void main()
{
   int iZahl1, iZahl2, iSumme;   // Variablen – Deklaration
   printf("Bitte 2 Zahlen eingeben: ");
   scanf("%i %i", &iZahl1, &iZahl2);
  
   addition(iZahl1, iZahl2, &iSumme);   // Funktionsaufruf mit sog. "aktuellen Parametern"
   // Von iSumme wird nur die Speicheradresse mit & übergeben!!!
  
   printf("Die Summe der Zahlen ist: %i \n", iSumme);   // Ergebnisausgabe
}

void addition(int iZahl1, int iZahl2, int* iSumme)   // übergabe Call-By-Referenz (mit Pointer)
{
   *iSumme = iZahl1 + iZahl2;   // Kein Rückgabewert, sondern direkt an Speicheradresse des Pointers zuweisen!
}


Variante 2 mit Referenzierung (nur in C++)

void addition(int iZahl1, int iZahl2, int& iSumme);   // Prototyp

void main()
{
   int iZahl1, iZahl2, iSumme;   // Variablen – Deklaration
   printf("Bitte 2 Zahlen eingeben: ");
   scanf("%i %i", &iZahl1, &iZahl2);
  
   addition(iZahl1, iZahl2, iSumme);   // Funktionsaufruf mit sog. "aktuellen Parametern"
   // iSumme wird als Referenz übergeben!!!
  
   printf("Die Summe der Zahlen ist: %i \n", iSumme);   // Ergebnisausgabe
}

void addition(int iZahl1, int iZahl2, int& iSumme)   // übergabe Call-By-Referenz (mit Referenzoperator &)
{
   iSumme = iZahl1 + iZahl2;   // Kein Rückgabewert, sondern über die Referenz direkt das Ergebnis in der Variablen iSumme speichern
}





Arrays (Statisch)

Definition Array
Die Datenstruktur Array (Feld) ermöglicht die Zusammenfassung mehrerer gleichartiger zusammengehöriger Elemente eines bestimmten Datentyps. Diese werden über den sogenannten Feld-Index und dem Feld-Namen angesprochen.

Eindimensionale Felder

// Deklaration:
int iarr_zahlen[10];   // Legt ein Array mit 10 Elementen an (Achtung Index startet bei 0!)

// Verwendung:
iarr_zahlen[0] = 1234;   // Speichert die Zahl 1234 in das erste Element des Feldes
iZahl = iarr_zahlen[3];   // Der Inhalt des 4. Element des Feldes wird in iZahl gespeichert.

// Schleife:
for (int i = 0; i < 10; i++)
   iarr_zahlen[i] = i + 1;   // Schreibt die Zahlen von 1 bis 10 in die Array-Elemente 0 bis 9


Mehrdimensionale Felder

// Deklaration:
int iarr_zahlen[10][10];   // Legt ein Array mit 10x10 Elementen an (Achtung Index startet bei 0!)

// Verwendung:
iarr_zahlen[0][1] = 1234;   // Speichert die Zahl 1234 in das erste Element der ersten Dimension
                          //    und das zweite Element der zweiten Dimension des Feldes
iZahl = iarr_zahlen[3][2];   // Der Inhalt des 4. Element der ersten Dimension und des 3. Elements
                             //    der zweiten Dimension des Feldes wird in iZahl gespeichert.

// Schleife:
int i = 1;
for (int x = 0; x < 10; x++)
   for (int y = 0; y < 10; y++)
     iarr_zahlen[x][y] = i++;   // Schreibt die Zahlen von 1 bis n in die Array-Elemente
     // i++ bedeutet in diesem Fall: i Wert wird zugewiesen und anschließend um eins erhöht!


Arrays werden immer mit Call-By-Reference übergeben!

Mehrdimensionale Felder an Funktionen übergeben
Anders als bei eindimensionalen Feldern muss bei der Übergabe mehrdimensionaler Felder für alle Dimensionen größer gleich zwei die Dimensionsgröße (Anzahl Elemente in einer Dimension) explizit angegeben werden.

#define DIMENSION1 10
#define DIMENSION2 10

void arrayausgabe(int meinarray[][DIMENSION2])   // Alle Dimensionen >=2 müssen explizit angegeben werden
{
   for (int i = 0; i < DIMENSION1; i++)
   {
     for (int j = 0; j < DIMENSION2; j++)
       printf("%d ", meinarray[i][j]);   // Zugriff erfolgt wie immer
     printf("\n");
   }
   printf("\n");
}

void main()
{
   int meinlokalesarray[DIMENSION1][DIMENSION2];
   arrayausgabe(meinlokalesarray);   // Der Name eines Arrays ist ein Pointer auf das Feld!
}   // -> Call-By-Reference für alle Arrays


Zeichenketten (char-Arrays)
Zeichenketten werden in Arrays bestehend aus Einzelelementen vom Datentyp char abgebildet.
Eine Zeichenkette endet immer mit dem Zeichen "\0"

int zeichenkettenlaenge(char* carrZeichenkette);   // Prototyp

void main()
{
   char carrZeichenkette[] = "Meine Zeichenkette!";   // char-Array deklarieren und initialisieren
  
   printf("Die Kette ist so lang: %i \n", zeichenkettenlaenge(carrZeichenkette));   // Achtung übergabe ohne & Operator!
}

int zeichenkettenlaenge (char* carrZeichenkette)   // übergabe Call-By-Referenz (mit Pointer)
{
   int i = 0;
   while (carrZeichenkette[i] != "\0")   // Zugriff ohne * Operator!
     i++;
   return i;
}


Ein paar ausführliche Beispiele zu Zeichenketten:

//Prototypen
int zeichenkettenlaenge(char* czeichenkette);
int wieoftvorhanden(char* czeichenkette, char* czeichen);
char* zeichenschneiden(char* czeichenkette);
void spiegeln(char* czeichenkette);
void tauschen(char* czeichenkette);
void zweitezeichen(char* czeichenkette);

//Hauptprogramm
void main()
{
     char carrzeichenkette[10] = "xx#abc#xx";
     char carrsuchzeichen[3] = "xx";
     printf("Zeichenkette lautet: %s \n", carrzeichenkette);
    
     printf("Die Zeichen zwischen den beiden # sind: %s \n", zeichenschneiden(carrzeichenkette));
    
     printf("Die Zeichenkette %s ist %i mal vorhanden.\n", carrsuchzeichen, wieoftvorhanden(carrzeichenkette, carrsuchzeichen));
    
     spiegeln(carrzeichenkette);
     printf("Zeichenkette lautet: %s \n", carrzeichenkette);
    
     tauschen(carrzeichenkette);
     printf("Zeichenkette lautet: %s \n", carrzeichenkette);
    
     zweitezeichen(carrzeichenkette),
     printf("Zeichenkette lautet: %s \n", carrzeichenkette);
}

int zeichenkettenlaenge(char* czeichenkette)
{
     int i = 0;
     while(czeichenkette[i] != '\0')
         i++;
     return i;
}

int wieoftvorhanden(char* czeichenkette, char* czeichen)
{
     int ikettenlaenge = 0;
     int izeichenlaenge = 0;
     int flag = 0;
     int ianzahl = 0;
    
     ikettenlaenge=zeichenkettenlaenge(czeichenkette);
     izeichenlaenge=zeichenkettenlaenge(czeichen);
    
     for (int j = 0; j <= ikettenlaenge - 1; j++)
     {
         flag = 1;
         for (int k = 0; k <= izeichenlaenge - 1; k++)
         {
             if (czeichenkette[j+k] != czeichen[k])
                 flag = 0;
         }
         if (flag == 1)
             ianzahl++;
     }
     return ianzahl;
}


char* zeichenschneiden(char* czeichenkette)
{
     int i = 0;
     int k = 0;
     static char chelfer[10];   //Gültigkeitsdauer verlängern!
    
     i = zeichenkettenlaenge(czeichenkette);
    
     int flag = 0;
     for (int j = 0; j <= i - 1; j++)
     {
         if (czeichenkette[j-1] == '#' && flag == 0)
             flag = 1;
         if (czeichenkette[j] == '#' && flag == 1)
             flag = 0;
         if (flag == 1)
         {
             chelfer[k] = czeichenkette[j];
             k++;
         }
     }
    
     chelfer[k] = '\0';
     return chelfer;
}

void spiegeln(char* czeichenkette)
{
     int i = 0;
     char c = ' ';
    
     i = zeichenkettenlaenge(czeichenkette);
    
     int k = i - 1;
     for (int j = 0; j <= (i - 1) / 2; j++)
     {
         c = czeichenkette[j];
         czeichenkette[j] = czeichenkette[k];
         czeichenkette[k] = c;
         k--;
     }
}

void tauschen(char* czeichenkette)
{
     int i = 0;
     char chelfer = ' ';
    
     i = zeichenkettenlaenge(czeichenkette);
    
     if (i%2 != 0)
         i--;
    
     for (int j = 0; j <= i - 1; j += 2)
     {
         chelfer = czeichenkette[j];
         czeichenkette[j] = czeichenkette[j+1];
         czeichenkette[j+1] = chelfer;
     }
}

void zweitezeichen(char* czeichenkette)
{
     int i = 0;
    
     i = zeichenkettenlaenge(czeichenkette);
    
     int k = 0;
     for (int j = 0; j <= i - 1; j += 2)
     {
         czeichenkette[k] = czeichenkette[j];
         k++;
     }
     czeichenkette[k] = '\0';
}





Arbeiten mit Dateien - Teil 1

// Datei öffnen
FILE* fDatei;
fDatei = fopen("C:\\TEST\\Zahlen.txt", "r");   // Achtung Backslash wird mit \\ erzeugt! "r" bedeutet Lesemodus

// Aus Datei lesen
int returncode, iZahl1;
returncode = fscanf(fDatei, “%d“, &iZahl1);

// In Datei schreiben
fprintf(fDatei, “%d“, iZahl1);

// Datei schließen
fclose(fDatei);

// Alle Dateien schließen
fclose_all();


Modusübersicht
Modus Erklärung
"w" Write – Schreiben (ist eine Datei bereits vorhanden, wird sie überschrieben!)
"r" Read – Lesen
"a" Append – Anhängen
"wb" Write Binary – Schreiben im Binärmodus
"rb" Read Binary – Lesen im Binärmodus

Beispiel
1) Schreiben der Zahlen 1 bis 100 in eine Datei
2) Einlesen aller Zahlen aus einer Datei und Summenausgabe

#include <stdio.h>

void main()
{
     FILE* fDatei;
     int returncode;
     int iZahl;
     int iSumme = 0;
    
     // Schritt 1: Schreiben der Zahlen 1 bis 100
     fDatei = fopen("C:\\TEST\\Zahlen.txt", "w");
    
     for (int i = 1; i < 101; i++)
         fprintf(fDatei, "%d", i);
    
     fclose(fDatei);
    
     // Schritt 2: Einlesen und summieren
     fDatei = fopen("C:\\TEST\\Zahlen.txt", "r");
    
     if (fDatei != NULL)
     {
         // Vorlesen
         returncode = fscanf(fDatei, "%d", &iZahl);
         while (returncode != EOF)   // EOF=Dateiende
         {
             iSumme += iZahl; // Summe bilden
             // Nachlesen
             returncode = fscanf(fDatei, "%d", &iZahl);
         }
     }
     else
         printf("Fehler beim öffnen der Datei!");
    
     fclose(fDatei);
}





Strukturen (Structs)

// Definition Struktur:
/* Strukturen sind Variablen, welche mehrere Elemente verschiedenster Datentypen zusammenfassen kann.
   Diese können mit Hilfe des Namens der Struktur und des Punktoperators angesprochen werden. */


// Definition einer Struktur:
struct
{
     char name[50];
     char vorname[50];
     int alter;
     int groesseincm;
     float gewicht;
} eineperson;

// Zugriff auf eine Struktur:
eineperson.name[0] = 'W';   // Schreibt ein W in das erste Element des char Arrays name
strcpy(eineperson.name,"Max Mustermann");   // String Copy Funktion aus string.h
eineperson.groesseincm = 174;
eineperson.gewicht = 70.5;

// Strukturen als neuer Datentyp:
struct person
{
     char name[50];
     char vorname[50];
     int alter;
     int groesseincm;
     float gewicht;
};

// Verwendung und Deklaration der Struktur
struct person marc;   // Deklaration der Struktur marc
struct person anika;   // Deklaration der Struktur anika
strcpy(marc.name,"Marc Wershoven");   // Zuweisung des Namens der Struktur marc
strcpy(anika.name,"Anika Muschner");   // Zuweisung des Namens der Struktur anika
// Zuweisung von Struktur an Struktur
marc = anika;

// Strukturen als Array:
struct person meinepersonen[10];   // Legt 10 Elemente der Struktur person an
meinepersonen[0].alter = 30;   // Alter der 1. Person mit Index 0 auf 30 setzen





Pointer auf Datenstrukturen

struct meinestruktur
{
     int iZahl1;
     int iZahl2;
};

void main()
{
     struct meinestruktur teststruktur;
     struct meinestruktur * strukturpointer = &teststruktur;

     // Arbeiten mit Pointern auf Strukturen
     teststruktur.iZahl1 = 12;   // Variante 1 – Direkt
     (*strukturpointer).iZahl1 = 12;   // Variante 2 – Per Inhaltsoperator und Pointer
     strukturpointer->iZahl1 = 12;   // Variante 3 – Kurzschreibweise per Inhaltsoperator und Pointer
     // (*pointer).strukturelement kann als pointer->strukturelement abgekürzt werden
}


Zugriff per Pointer auf eine Struktur und Übergabe an eine Funktion

struct meinestrukturdefinition
{
     char name[10];
     int alter;
};

void testfunc(struct meinestrukturdefinition * stest);

void main()
{
     struct meinestrukturdefinition meineteststruktur;   // Deklaration der Struktur mit Name meineteststruktur
     strcpy(meineteststruktur.name,"Marc");
    
     meineteststruktur.alter=33;
     printf("Name: %s Alter: %i (vor Funktionsaufruf)\n", meineteststruktur.name, meineteststruktur.alter);
     testfunc(&meineteststruktur);   // Aufruf der Funktion und übergabe der Adresse!
     printf("\n Neues Alter nach Funktion: %i", meineteststruktur.alter);
}

void testfunc(struct meinestrukturdefinition * stest)
{
     printf("Name: %s Alter: %i", stest->name, stest->alter);
     stest->alter = 34;   // Neues Alter zuweisen über Inhaltsoperator und Pointer
}


Übergabe eines struct-Arrays an eine Funktion mit Call-By-Reference (via Referenzierung)

struct meinestrukturdefinition
{
     char name[10];
     int alter;
};

void testfunc(struct meinestrukturdefinition stest[]);

void main()
{
     struct meinestrukturdefinition meineteststruktur[10];   // Deklaration des Struktur-Arrays
     strcpy(meineteststruktur[0].name,"Marc");
     meineteststruktur[0].alter = 33;
     printf("Name: %s Alter: %i (vor Funktionsaufruf)/n", meineteststruktur[0].name, meineteststruktur[0].alter);
     testfunc(meineteststruktur);   // Aufruf der Funktion mit Referenzierungsübergabe (ohne &)
     printf("\n Neues Alter nach Funktion: %i", meineteststruktur[0].alter);
}

void testfunc(struct meinestrukturdefinition stest[])
{
     printf("Name: %s Alter: %i", stest[0].name, stest[0].alter);
     stest[0].alter = 34; // Neues Alter zuweisen über Inhaltsoperator und Pointer
}





Ein- und Ausgabebefehle - Teil 2

Für die Funktionen cin (Eingabe) und cout (Ausgabe) muss die Bibliothek <iostream> eingebunden werden.

Der Manipulator flush bewirkt das Leeren des Puffers auf das Ausgabemedium.
Der Manipulator endl bewirkt bei einer Bildschirmausgabe einen Sprung zum Anfang der nächsten Zeile und das Leeren des Puffers auf das Ausgabemedium (Sprich: '\n' und flush).

In C heißt der Befehl flush:

int iZahl1;
char cZeichen1;

cout << "Bitte eine Nummer eingeben: " << flush;
cin >> iZahl1;

cout << "Bitte ein Zeichen eingeben: " << flush;
cin >> cZeichen1;

cout << "Ihre Eingaben: Nummer = " << iZahl1 << " Zeichen = " << cZeichen1 << endl;





Arbeiten mit Dateien - Teil 2

Für die Funktionen fwrite und fread muss die Bibliothek <iostream> eingebunden werden.

Einzelne Zeichen schreiben und lesen

FILE* fDatei;
char cZeichen;

fDatei = fopen("C:\\TEST\\Testdatei.txt", "w");
fwrite(&cZeichen, 1, 1, fDatei);   // Ein Zeichen von der Adresse von cZeichen in die Datei schreiben
fclose(fDatei);

fDatei = fopen("C:\\TEST\\Testdatei.txt", "w");
fread(&cZeichen, 1, 1, fDatei);   // Ein Zeichen aus der Datei an die Adresse von cZeichen einlesen
fclose(fDatei);


Satzweise schreiben und lesen

struct meinedatensatzstruktur {
     char name[50];
     int alter;
     int groesseincm;
};

FILE* fDatei;
struct meinedatensatzstruktur meindatensatz;
int returncode;

fDatei = fopen("C:\\TEST\\Testdatei.txt", "wb");
returncode = fwrite(&meindatensatz, sizeof(meindatensatz), 1, fDatei);   // sizeof() ermittelt die Speichergröße
fclose(fDatei);

fDatei = fopen("C:\\TEST\\Testdatei.txt", "rb");
returncode = fread(&meindatensatz, sizeof(meindatensatz), 1, fDatei);
fclose(fDatei);

// Der returncode enthält die Anzahl der gelesenen / geschriebenen Datensätze / Strukturen.
// Bei fread kann der returncode 0 werden, wenn das Dateiende erreicht wurde!


Weitere Übungen "Arbeiten mit Dateien"
Zeichenweise Auslesen eines Token via Funktion anhand von Trennzeichen (z.B. Einlesen einer CSV Datei)

Beispiel CSV Datei test.csv:
# Kommentarzeile
Max,Mustermann,33
Berta,Beispiel,24
Hugo,Heinrich,45
Karl,Kleber,56

struct kontaktliste {
   char vorname[50];
   char nachname[50];
   int alter;
};

int LeseTokenAusDatei(FILE* ptr_Datei, char cbuffer[], char cdelimiter);
void DatenAnzeigen(struct kontaktliste meinedaten[], int ianzahl);

void main()
{
   FILE* ptr_Datei;
   struct kontaktliste meinedaten[50];
   char cbuffer[255];
   int anzahldatensaetze = 0;
  
   ptr_Datei = fopen("C:\\TEST\\test.csv", "r");
   if (ptr_Datei != NULL)
   {
     int datensatz = 0;
     do
     {
       anzahldatensaetze = LeseTokenAusDatei(ptr_Datei, cbuffer, ',');
       if (anzahldatensaetze > 0 && anzahldatensaetze < 50)   // Maximal 50 Datensätze
       {
         if (cbuffer[0] == '#')   // Kommentarzeile überlesen...
           anzahldatensaetze = LeseTokenAusDatei(ptr_Datei, cbuffer, '\n');
         else
         {
           // Datensatz gefunden, Spaltenweise einlesen
           for (int i = 0; i < 3; i++)
           {
             switch (i)
             {
               case 0:   // Vorname
                 strcpy(meinedaten[datensatz].vorname,cbuffer);
                 anzahldatensaetze = LeseTokenAusDatei(ptr_Datei, cbuffer, ',');   // Nachlesen
                 break;
               case 1:   // Nachname
                 strcpy(meinedaten[datensatz].nachname,cbuffer);
                 anzahldatensaetze = LeseTokenAusDatei(ptr_Datei, cbuffer, '/n');   // Nachlesen
                 break;
               case 2:   // Alter
                 meinedaten[datensatz].alter = atoi(cbuffer);
             }
           }
           datensatz++;
         }
       }
     }
     while (anzahldatensaetze > 0);   // Bis Dateiende einlesen
    
     // Ausgabe der eingelesenen Datensätze
     DatenAnzeigen(meinedaten,datensatz);
   }
   else
   {
     cout << "Fehler beim öffnen der Datei..." << endl;
   }
   fclose(ptr_Datei);
}

int LeseTokenAusDatei(FILE* ptr_Datei, char cbuffer[], char cdelimiter)
{
   int buffercount = 0;
   int i = 0;
   char ctempbuffer;
  
   do
   {
     buffercount = fread(&ctempbuffer, 1, 1, ptr_Datei);
     // Nur einlesen bis Trennzeichen oder Zeilenumbruch erreicht wurde
     if (buffercount > 0 && ctempbuffer != 10 && ctempbuffer != 13 && ctempbuffer != cdelimiter)
       cbuffer[i++] = ctempbuffer;
     else
       buffercount = 0;
   }
   while (buffercount > 0 && i < 256); // Nur wenn Zeichen vorhanden sind und max. 255 Zeichen einlesen
  
   cbuffer[i] = 0; // char Array mit \0 beenden
   return i;
}

void DatenAnzeigen(struct kontaktliste meinedaten[], int ianzahl)
{
   for (int i = 0; i < ianzahl; i++)
   {
     cout << "Datensatz Nummer " << i + 1 << " - Vorname: " << meinedaten[i].vorname;
     cout << " - Nachname: " << meinedaten[i].nachname;
     cout << " - Alter: " << meinedaten[i].alter << endl;
   }
}


Zeichenweise INI Datei auslesen und in einer Datenstruktur ablegen (Sequenziell ohne Token Funktion)

Beispiel INI Datei test.txt:
[sektion 1]
key=value
name=Marc
andererkey=andererwert
# Leere Kommentarzeile
[sektion 2]
key2=value2
name2=Anika
andererkey2=andererwert2

struct struktur_INI {
   char section[50];
   char key[50];
   char value[50];
};

int INI_Einlesen(char cdateiname[], struct struktur_INI meine_INI_Datei[]);
void INI_Anzeigen(struct struktur_INI meine_INI_Datei[], int irecords);

void main()
{
   struct struktur_INI meine_INI_Datei[50];
   int ianzahldatensaetze = 0;
   ianzahldatensaetze = INI_Einlesen("test.txt", meine_INI_Datei);
   INI_Anzeigen(meine_INI_Datei, ianzahldatensaetze);
}

int INI_Einlesen(char cdateiname[], struct struktur_INI meine_INI_Datei[])
{
   FILE* meinedatei;
   int irc = 0;
   int irecords = 0;
   char csectionbuffer[50] = "Keine Sektion";
   int isectionbuffer = 0;
   char clokalbuffer[50];
   int ilokalbuffer = 0;
   char cbuffer;
  
   meinedatei = fopen(cdateiname, "r");
   if (meinedatei == NULL)
   {
     cout << "Fehler beim öffnen der Datei!" << endl;
     return 0;
   }
  
   irc = fread(&cbuffer, 1, 1, meinedatei);   // Vorlesen
   while (irc > 0)
   {
     // Das erste Zeichen einer Zeile entscheidet über die Situationen 1-3
     if (cbuffer == '[')   // Situation 1: Sektionszeichen [ gefunden
     {
       isectionbuffer = 0;
       do
       {
         csectionbuffer[isectionbuffer++] = cbuffer;
         irc = fread(&cbuffer, 1, 1, meinedatei);   // nächstes Zeichen
       } while (cbuffer != '/n' && cbuffer != 10 && cbuffer != 13 && irc > 0);
       csectionbuffer[isectionbuffer] = 0;
     }
     else if(cbuffer == ' ' || cbuffer == '#')   // Situation 2: Leerzeile oder Kommentar
     { // Annahme: Es gibt keine leeren Zeilen ohne ein Zeichen!
       do
       {
         irc = fread(&cbuffer, 1, 1, meinedatei);   // nächstes Zeichen - LZ überlesen
       } while (cbuffer != '/n' && cbuffer != 10 && cbuffer != 13 && irc > 0);
     }
     else    // Situation 3: Key und Value Zeile
     {
       // Schritt 1: Bis zum = Key auslesen
       ilokalbuffer = 0;
       do
       {
         clokalbuffer[ilokalbuffer++] = cbuffer;
         irc = fread(&cbuffer, 1, 1, meinedatei);   // nächstes Zeichen
       } while (cbuffer != '=' && cbuffer != 10 && cbuffer != 13 && irc > 0);
       clokalbuffer[ilokalbuffer] = 0;
       strcpy(meine_INI_Datei[irecords].section, csectionbuffer);
       strcpy(meine_INI_Datei[irecords].key, clokalbuffer);
       // Schritt 2: Bis zum /n value auslesen
       ilokalbuffer = 0;
       irc = fread(&cbuffer, 1, 1, meinedatei);   // nächstes Zeichen Gleichzeichen überlesen
       do
       {
         clokalbuffer[ilokalbuffer++] = cbuffer;
         irc = fread(&cbuffer, 1, 1, meinedatei); // nächstes Zeichen
       } while (cbuffer != '/n' && cbuffer != 10 && cbuffer != 13 && irc > 0);
       clokalbuffer[ilokalbuffer] = 0;
       strcpy(meine_INI_Datei[irecords].value, clokalbuffer);
       irecords++;   // Nächster Datensatz im Struktur-Array
     }
     irc = fread(&cbuffer, 1, 1, meinedatei);   //Nachlesen nächste Zeile 1. Zeichen
   }
   fclose(meinedatei);
   return irecords;
}

void INI_Anzeigen(struct struktur_INI meine_INI_Datei[], int irecords)
{
   for (int i = 0; i < irecords; i++)
   {
     cout << "Datensatz " << i + 1 << " : Sektion = " << meine_INI_Datei[i].section;
     cout << " / Key = " << meine_INI_Datei[i].key;
     cout << " / Value = " << meine_INI_Datei[i].value << endl;
   }
}




Dynamische Arrays

Dynamische Arrays können zur Laufzeit angelegt und erweitert werden.

1 dimensional

// Voraussetzung:
#include <stdlib.h>
#include <malloc.h>

// Deklaration:
int* f;
f = (int*) malloc(100);   // Typ-Casting

f = (int*) malloc(25 * 4);

f = (int*) malloc(25 * sizeof(int));

f = (int*) malloc(a * sizeof(int));


2 dimensional

// Voraussetzung:
#include <stdlib.h>
#include <malloc.h>

// Deklaration:
int x = 5, y = 4, i;
int** start;
start = (int**) malloc(x * sizeof(int*));
for (i = 0; i < x; i++)
   start[i] = (int*) malloc(sizeof(int) * y);

// Ab jetzt Zugriff via start[3][2] = 17; möglich


Vergleich und Übersicht: Statische und dynamische Felder

Abbildung 2 - Vergleich und Übersicht: Statische und dynamische Felder




Verkettete Listen

Mit der verketteten Liste können Strukturen im Arbeitsspeicher angelegt, erweitert oder reduziert werden. Dabei zeigt immer ein Strukturelement auf das nächste Strukturelement (Adresse via Pointer).

Schematische Darstellung:

Abbildung 3 - Verkettete Listen (Schematische darstellung)

struct vk
{
     int zahl;
     struct vk *nf;   // Nachfolgeradresse
};

void main()
{
     struct vk * start;
     start = (start vk *) malloc(sizeof(struct vk));
     (*start).zahl = 17;
     (*start).nf = NULL;   // Initialisieren
     (*start).nf = (struct vk *) malloc(sizeof(struct vk));
    
     (*(*start).nf).zahl = NULL;
     (*(*start).nf).zahl = 14;
     start->nf->zahl = 14;   // Abgekürzte Schreibweise mit ->
}


Durchlaufen einer Liste bis zum Ende (NULL)

struct vk * test = start;

while (test->nf != NULL)
   test = test->nf;

Abbildung 4 - Verkettete Listen (Durchlaufen einer Liste bis zum Ende (NULL))

Ausführliche Übungen zur verketteten Liste

#include <stdlib.h>
#include <stdio.h>

// *************** PROTOTYPEN ***************
void gebeaus(struct vk * p);
void haengevornean(struct vk ** p, int zahl);
void haengehintenan(struct vk **, int zahl);
int elementezaehlen(struct vk * p);
void loeschevorne(struct vk ** p);
void loeschehinten(struct vk ** p);
struct vk * suchewert(struct vk * p, int zahl);
int loeschewert(struct vk * p, int zahl);
struct vk
{
   int wert;
   struct vk *nf; //Nachfolgeradresse
};
// ******************************************

void main()
{
   int suchwert;
   // Anlegen des Startpointers
   struct vk *start = (struct vk *) malloc(sizeof(struct vk));
   struct vk *kopie;
   start->nf = NULL;
   start->wert = 0;
   printf("Liste wurde initialisiert mit 1 Element.\n");
   // Ausgabe aller Kettenelemente
   gebeaus(start);
   // 1 Element vorne einfügen
   printf("An die Liste wird 1 Element vorne angehangen.\n");
   haengevornean(&start, 1);
   gebeaus(start);
   // 1 Element hinten anhaengen
   printf("An die Liste werden 4 Element hinten angehangen.\n");
   kopie = start; // Sichern des Originalpointers
   haengehintenan(&kopie, 2);
   gebeaus(start);
   // 1 Element hinten anhaengen
   kopie = start; // Sichern des Originalpointers
   haengehintenan(&kopie, 7);
   gebeaus(start);
   // 1 Element hinten anhaengen
   kopie = start; // Sichern des Originalpointers
   haengehintenan(&kopie, 12);
   gebeaus(start);
   // 1 Element hinten anhaengen
   kopie = start; // Sichern des Originalpointers
   haengehintenan(&kopie, 100);
   gebeaus(start);
   // Zählen der vorhandenen Elemente in der Liste
   printf("Anzahl der Elemente in der Liste: %i\n", elementezaehlen(start));
   // 1. Element löschen
   loeschevorne(&start);
   printf("Loeschung des 1.Elements.\n");
   gebeaus(start);
   // letztes Element löschen
   kopie = start; // Sichern des Originalpointers
   loeschehinten(&kopie);
   printf("Loeschung des letzten Elements.\n");
   gebeaus(start);
   // Suche einen Wert
   suchwert = 7;
   printf("S: %i E: %p W: %i\n", suchwert, suchewert(start,suchwert), *suchewert(start,suchwert));
   // Suche einen Wert
   suchwert = 12;
   printf("Suche %i ersetze durch 0. Erg: %i (1=geloescht).\n",suchwert,loeschewert(start,suchwert));
   gebeaus(start);
}

void gebeaus(struct vk * p)
{
   printf("Listeninhalt: ");
   if (p == NULL)
     printf("...\n");
   else
   {
     while (p != NULL)
     {
       printf("%5i", p->wert);
       p = p->nf;
     }
   }
   printf("\n");
}

void haengevornean(struct vk ** p, int zahl)
{
   struct vk * kopie = *p;   // Sicherung Startadresse 1.Element
   *p = (struct vk *) malloc(sizeof(struct vk));   // Neues Element
   (*p)->wert = zahl;   // Wertzuweisung
   (*p)->nf = kopie;   // Adresszuweisung
}

void haengehintenan(struct vk ** p, int zahl)
{
   while (!(*p)->nf == NULL)
     *p = (*p)->nf;
   (*p)->nf = (struct vk *) malloc(sizeof(struct vk));
   (*p) = (*p)->nf;
   (*p)->wert = zahl;
   (*p)->nf = NULL;
}

int elementezaehlen(struct vk * p)
{
   int zaehler = 0;
   if (p == NULL)
     return 0;
   else
   {
     while (p != NULL)
     {
       zaehler++;
       p = p->nf;
     }
   }
   return zaehler;
}

void loeschevorne(struct vk ** p)
{
   (*p) = (*p)->nf; // überschreiben der Adresse des 1.Elements mit der des 2.
}

void loeschehinten(struct vk ** p)
{
   while(!(*p)->nf->nf == NULL)
     *p = (*p)->nf;
   (*p)->nf = NULL;
}

struct vk * suchewert(struct vk * p, int zahl)
{
   int zaehler = 0;
   if (p == NULL)
     return NULL;
   else
   {
     while (p != NULL)
     {
       zaehler++;
       p = p->nf;
       if (p->wert == zahl)
         return p;
     }
   }
   return NULL;
}

int loeschewert(struct vk * p, int zahl)
{
   int zaehler = 0;
   if (p == NULL)
     return 0;
   else
   {
     while (p != NULL)
     {
       zaehler++;
       p = p->nf;
       if (p->wert == zahl)
       {
         p->wert = 0;
         return 1;
       }
     }
   }
   return 0;
}




Rekursion

Unter einer Rekursion versteht man eine Funktion, welche sich immer wieder selbst aufruft.
Als Beispiel berechnen wir die mathematische Fakultät mit einer rekursiven Lösung.

int fakultaet(int zahl);   // Prototyp

void main()
{
   int iZahl1;
   printf("Bitte eine Zahl eingeben: ");   // Benutzerabfrage
   scanf("%i", &iZahl1);
   printf("Fakultät von %i = %i ", iZahl1, fakultaet(eingabe));   // Funktion Fakultät rekursive Lösung
}

int fakultaet(int z)   // Definition der Funktion fakultaet
{
   if (z <= 1)
     return 1;   // Fakultät <=1 liefert eine 1 zurück
   else   // Diese Bedingung führt zur Beendung der Rekursion
     return (z * fakultaet(z - 1));   // Rekursiver Aufruf
}





Modularisierung – Auslagerung in Header und Quelldateien

Im Zuge der Modularisierung können Funktionen in separate Dateien ausgelagert werden. Dazu werden die Funktions-Prototypen/Deklarationen in eine sogenannte Header Datei geschrieben. Die Datei bekommt z.B. den Namen MeineFunktionen.h . Die eigentlichen Funktionsdefinitionen und der dazugehörige Quelltext wird in die Namensgleiche Quelldatei MeineFunktionen.cpp geschrieben.
Die ausgelagerten Funktionen können nun mittel #include "MeineFunktionen.h" in die Hauptprogrammdatei eingebunden werden.

Beispiel:

// Inhalt der Datei MeineFunktionen.h
int bildesumme(int iZahl1, int iZahl2);   // Prototyp

// Inhalt der Datei MeineFunktionen.cpp
int bildesumme(int iZahl1, int iZahl2)   // Definition
{
   return iZahl1 + iZahl2;
}

// Inhalt der Datei Main.cpp
#include "MeineFunktionen.h"   // Einbinden der externen Funktionen

void main()
{
   int iZahl1 = 12;
   int iZahl2 = 14;
   printf("Die Summe von 12 und 14 ist: %i", bildesumme(iZahl1, iZahl2));
}





Befehlszeilenparameter - Argumente des Hauptprogramms

Um Parameter bzw. Argumente aus der aufrufenden Befehlsaufforderung (Konsole, Prompt) entgegenzunehmen, bekommt die Funktion main Übergabeparameter.

#include <stdio.h>

void main(int argc, char * argv[])
{
   printf("Es wurden %i Argumente übergeben./n", argc);   // argc enthält die Anzahl der übergebenen Argumente
   while (argc != 0)
   {
     // Im char-Array argv sind alle Argumente per Index ansprechbar!
     printf("Das Argument Nr. %i lautet: %s /n", argc, argv[argc-1]);
     argc--;   //Schrittweise zurück bis zum ersten Argument
   }
}





Weitere nützliche Werkzeuge und Funktionen

Static
Wenn das Schlüsselwort static vor eine Variable gesetzt wird, weiß der Compiler, dass die Variable zur ganzen Laufzeit des Programms über existieren soll. Eine lokale Variable, die als static deklariert ist, wird beim Verlassen der Funktion nicht gelöscht, sondern bleibt im Arbeitsspeicher erhalten.

Typedef - Typendefinition
typedef ermöglicht es synonyme Datentypen mit eigenem Namen zu definieren.

Beispiel:
Datentyp boolean erstellen: Die beiden Zustände TRUE und FALSE werden mittels #define dem Präprozessor bekannt gegeben. So kann in folgenden Funktionen der Datentyp boolean verwendet werden.

#define TRUE 1
#define FALSE 0
typedef unsigned int boolean;

// Verwendung
boolean bweiter = TRUE;   // Deklaration
bweiter = FALSE;   // Wertzuweisung


Makros
Makros werden vom Präprozessor vor der Kompilierung im Quelltext ersetzt.

ZUMQUADRAT(x) ((x) * (x))
iZahl = ZUMQUADRAT(4);;   // Erzeugt iZahl = ((4)*(4));

// Klammern bei Makros sind wichtig! Falsches Beispiel:
ZUMQUADRAT(x) x * x
iZahl = ZUMQUADRAT(iZahl2 + 1);;   // Erzeugt iZahl = izahl + 1 * iZahl + 1, Fehler: Punkt-Vor-Strich-Rechnung!


Umwandlungsfunktionen
Funktionen aus der Bibliothek <ctype.h>
Funktion Erklärung
isalpha Prüfung eines Zeichens auf Buchstabe (Rückgabewert: int)
isupper Prüfung eines Zeichens auf Großbuchstabe (Rückgabewert: int)
islower Prüfung eines Zeichens auf Kleinbuchstabe (Rückgabewert: int)
isdigit Prüfung eines Zeichens auf Dezimalzahl (Rückgabewert: int)
isalnum Prüfung eines Zeichens auf Buchstabe oder Zahl (Rückgabewert: int)
isspace Prüfung eines Zeichens auf ’ ’, ’/n’ etc. (Rückgabewert: int)
toupper Wandelt ein Zeichen in einen Großbuchstaben um
tolower Wandelt ein Zeichen in einen Großbuchstaben um

Zeichenkettenfunktionen
Funktionen aus der Bibliothek <string.h>
Funktion Erklärung
strcpy(Ziel, Quelle) Kopiert einen String aus einer Variablen in eine andere
strcat(Ziel, Anhängen) Hängt ein String an das andere an (Verketten)
strlen(String) Gibt die Länge einer Zeichenkette String zurück
strcmp(String1, String2) Vergleicht 2 Strings miteinander (RC==0 bedeutet identisch)

Umwandlungsfunktionen für Zeichenketten
Funktionen aus der Bibliothek <stdlib.h>
Funktion Erklärung
atoi(String) Wandelt String in Integer um
atol(String) Wandelt String in Long um
atof(String) Wandelt String in Float um

Mathematische Funktionen
Funktionen aus der Bibliothek <math.h>
Funktion Erklärung
sin(x) Sinus
cos(x) Cosinus
tan(x) Tangens
log(x) Logarithmus
log10(x) Natürlicher Logarithmus (10)

Funktionen für Verzeichnisse
Funktionen aus der Bibliothek <direct.h>
Funktion Erklärung
mkdir(String) Erstellt ein Verzeichnis
chdir(String) Wechselt das aktuelle Verzeichnis
rmdir(String) Löschen eines Verzeichnis

Funktionen für Dateien
Funktionen aus der Bibliothek <io.h>
Funktion Erklärung
rename(NeueName, AlterName) Dateien umbenennen
unlink(String) Datei löschen – Step 1 (Entbinden)
remove(String) Datei löschen – Step 2 (Löschen)

Funktion für die Ausführung von Systemkommandos
Funktionen aus der Bibliothek <process.h>
Funktion Erklärung
System("cls") Befehl "cls" ausführen




Übungsprojekt "Kundendatenbank"

Es handelt sich um eine kleine Kundendatenbank. Es können Kunden mit Nachname, Vorname und Telefonnummer angelegt, gespeichert, geladen und angezeigt werden! Realisierung über eine verkettete Liste.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#define MAX 100

// * * * P R O TO T Y P E N * * *
void startmenue();
void kundeneumenue(struct vk ** p);
void startanzeige();
void gebeaus(struct vk * p);
void speicher(struct vk * p);
void laden(struct vk ** p);
void naechsteseite();
void killallpoints(struct vk ** p);

// * * * S T R U K T U R * * *
struct vk
{
   char name[MAX];
   char vorname[MAX];
   char tel[MAX];
   struct vk *nf;   //Nachfolgeradresse verkettete Liste
};

// * * * G L O B A L V A R S * * *
int kundencount = 0;

// * * * GLOBALES FELD KUNDE ANLEGEN * * *
struct vk *start = (struct vk *) malloc(sizeof(struct vk));

// * * * H A U P T P R O G R A M M * * *
void main()
{
   // Menüauswahl
   startanzeige();
   startmenue();
   // PROGRAMMENDE
}
// * * * F U N K T I O N E N * * *
void startmenue()
{
   char eingabe;
   while (1)
   {
     eingabe = getchar();
     fflush(stdin);
     switch (eingabe)
     {
       case '1':
         kundeneumenue(&start);
         break;
       case '2':
         gebeaus(start);
         break;
       case '3':
         speicher(start);
         break;
       case '4':
         laden(&start);
         break;
       case '9':
         killallpoints(&start);
         exit(EXIT_FAILURE);
         break;
       default:
         break;
     }
   }
}

void startanzeige()
{
   system("cls");
   printf("--------------------------------------/n");
   printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
   printf("--------------------------------------/n/n");
   printf("- 1 > Kunden anlegen /n");
   printf("- 2 > Kunden zeigen /n");
   printf("- 3 > Speichern der Datenbank ('DB.DAT') /n");
   printf("- 4 > Datenbank einladen /n");
   printf("/n");
   printf("- 9 > Programm beenden /n/n/n");
   printf("--------------------------------------/n");
   printf("Ihre Eingabe: ");
}

void kundeneumenue(struct vk ** p)
{
   char eingabe[MAX];
   struct vk * kopie = *p;   // Sicherung Startadresse 1.Element
   *p = (struct vk *) malloc(sizeof(struct vk));   // Neues Element einfügen
   system("cls");
   printf("--------------------------------------/n");
   printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
   printf("--------------------------------------/n/n");
   // NAME
   printf("\nBitte Namen eingeben: ");
   scanf("%s", &eingabe);
   strcpy((*p)->name, eingabe);   //Namenszuweisung
   // VORNAME
   printf("\nBitte Vorname eingeben: ");
   scanf("%s", &eingabe);
   strcpy((*p)->vorname, eingabe);
   // TEL
   printf("\nBitte Tel.Nr. eingeben: ");
   scanf("%s", &eingabe);
   strcpy((*p)->tel, eingabe);
   // ZURüCK ZUM MENü
   if (kundencount == 0)
     (*p)->nf = NULL;   // Adresszuweisung bei ersten Kunden
   else
     (*p)->nf = kopie;   // Adresszuweisung
   kundencount++;
   startanzeige();
}

void gebeaus(struct vk * p)
{
   char buffer;
   int counter = 0;
   if (kundencount == 0)
   {
     system("cls");
     printf("--------------------------------------/n");
     printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
     printf("--------------------------------------/n/n");
     printf("- DIE DATENBANK BEINHALTET NOCH KEINEN KUNDEN /n");
     printf("--------------------------------------/n");
   }
   else
   {
     system("cls");
     printf("--------------------------------------/n");
     printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
     printf("--------------------------------------/n/n");
     if (p == NULL)
       printf("...\n");
     else
     {
       while (p != NULL)
       {
         printf(" %10s ,%10s, %10s",p->vorname, p->name, p->tel);
         p = p->nf;
         printf("\n");   // pro Kunde eine Zeile
         counter++;
         if (counter == 10)
         {
           naechsteseite();
           counter = 0;
         }
       }
     }
   }
   printf("\nENTER fuer weiter...");
   scanf("%c", &buffer);
   startanzeige();
}

void speicher(struct vk * p)
{
   char buffer;
   FILE* file;
   if (kundencount == 0)
   {
     system("cls");
     printf("--------------------------------------/n");
     printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
     printf("--------------------------------------/n/n");
     printf("- DIE DATENBANK BEINHALTET NOCH KEINEN KUNDEN/n");
     printf("--------------------------------------/n");
   }
   else
   {
     system("cls");
     printf("--------------------------------------/n");
     printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
     printf("--------------------------------------/n/n");
     printf(" Speicher...");
     file = fopen("C:\\db.dat", "wb");
     if(file == NULL)
       printf("\n FEHLER BEIM OEFFNEN DER DATEI...\n");
     else
     {
       if (p == NULL)
         printf("...gespeichert!!!\n");
       else
       {
         while (p != NULL)
         {
           fprintf(file, "%100s%100s%100s", p->vorname, p->name, p->tel);
           p = p->nf;
           printf(".");
         }
         printf("...gespeichert!!!\n");
       }
       fclose(file);
     }
   }
  
   printf("\nENTER fuer weiter...");
   scanf("%c", &buffer);
   startanzeige();
}

void laden(struct vk ** p)
{
   char n[MAX], v[MAX], t[MAX];
   FILE* file;
   char buffer;
   int rc;
   struct vk * kopie = *p;   // Sicherung Startadresse 1.Element
   system("cls");
   printf("--------------------------------------/n");
   printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
   printf("--------------------------------------/n/n");
   printf(" Lade...");
   file = fopen("c:\\db.dat", "rb");
   if (file == NULL)
     printf("\n FEHLER BEIM OEFFNEN DER DATEI...\n");
   else
   {
     rc = fscanf(file, "%100s%100s%100s", &v, &n, &t);
     while (rc != EOF)   // bis Dateiende
     {
       kopie = *p; // Sicherung
       *p = (struct vk *) malloc(sizeof(struct vk));   // Neues Element einfügen
       strcpy((*p)->name, n);
       strcpy((*p)->vorname, v);
       strcpy((*p)->tel, t);
       if (kundencount == 0)
         (*p)->nf = NULL;   // Adresszuweisung bei ersten Kunden
       else
         (*p)->nf = kopie;   // Adresszuweisung
       kundencount++;
       printf(".");
       rc = fscanf(file, "%100s%100s%100s", &v, &n, &t);
     }
     printf("...fertig!!!\n");
   }
   printf("\nENTER fuer weiter...");
   scanf("%c",&buffer);
   startanzeige();
}

void naechsteseite()
{
   char buffer;
   printf("\nENTER fuer naechste Seite...");
   scanf("%c", &buffer);
   system("cls");
   printf("--------------------------------------/n");
   printf("- ---<<< KUNDENDATENBANK V1.0 >>>--- -/n");
   printf("--------------------------------------/n/n");
}

void killallpoints(struct vk ** p)
{
   int counter = 1;
   struct vk * kopie = *p;
   if (kundencount == 0)
     counter = 0;
   else
   {
     while ((*p)->nf != NULL)   // bis Listenende
     {
       kopie = *p;   // Sicherung
       counter++;
       (*p) = (*p)->nf;
       free(kopie);
     }
     free(*p);
   }
   printf("%i geloeschte Pointer bei Programmende...\n", counter);
}





Weitere Übungsbeispiele

Die Funktion strlen selbst gebaut

int zeichenkettenlaenge(char* czeichenkette)
{
   int i = 0;
   while (czeichenkette[i] != '\0')
     i++;
   return i;
}


Eine Funktion zur Umwandlung eines Char-Arrays in Long

long convertchar2long(char chararray[])
{
   int i = 0, j = 0, dezimalstelle = 1;
   double dezimalwert = 10;
   long ergebnis = 0;
   long zwischenerg = 0;
  
   while (chararray[i] != ' ')
     i++;
  
   for (int x = i - 1; x >= 0; x--)
   {
     if (x == 0 && chararray[x] == '-')
       ergebnis *= -1;   // Vorzeichen umdrehen bei Minus
     else
     {
       // Dezimalstelle verarbeiten
       zwischenerg = 1;
       for (j = 2; j <= dezimalstelle; j++)
         zwischenerg *= 10;
       ergebnis += (chararray[x] - 48) * zwischenerg;   // Umrechnung ASCII -48 ergibt den Zahlenwert 0-9
       dezimalstelle++;
     }
   }
   return ergebnis;
}


Eine Funktion zur Umwandlung eines Char-Arrays in Double

double convertchar2double(char chararray[])
{
   int i = 0, j = 0, ink = 0, x, dezimalstelle = 1, vorzeichen = 0;
   double dezimalwert = 10, ergebnis = 0, zwischenerg = 0;
  
   while (chararray[i] != '.')
     i++;
  
   ink = i;
   while (chararray[ink] != ' ')
     ink++;
  
   for (x = i - 1; x >= 0; x--)
   {
     if (x == 0 && chararray[x] == '-')
       vorzeichen = 1;   // Vorzeichen umdrehen bei Minus
     else
     {
       //cDezimalstelle verarbeiten
       zwischenerg = 1;
       for (j = 2; j <= dezimalstelle; j++)
         zwischenerg *= 10;
       ergebnis += (chararray[x] - 48) * zwischenerg;   // Umrechnung ASCII
       dezimalstelle++;
     }
   }
  
   dezimalstelle = 1;
   for (x = i + 1; x < ink; x++)
   {
     // Dezimalstelle verarbeiten
     zwischenerg = 1;
     for (j = 1; j <= dezimalstelle; j++)
       zwischenerg *= 0.1;
     ergebnis += (chararray[x] - 48) * zwischenerg;   // Umrechnung ASCII
     dezimalstelle++;
   }
  
   // Wenn negatives Vorzeichen *-1
   if (vorzeichen == 1)
     ergebnis *= -1;
  
   return ergebnis;
}


Eine Schleife, die ein Array (int) mit dem einfachen Bubble-Sort Algorithmus sortiert

int help;
int counter = 10;
int feld[10];

for (i = 0; i < counter; i++)
{
   for (int j = (counter - 2); j >= 0; j--)
   {
     if (feld[j] > feld[j+1])
     {
       help = feld[j];
       feld[j] = feld[j+1];
       feld[j+1] = help;
     }
   }
}


Eine Schleife mit zusätzlichem "Flag" ausstatten

char* zeichenschneiden(char* czeichenkette)
{
   int i = 0;
   int k = 0;
   static char chelfer[10];
  
   i = zeichenkettenlaenge(czeichenkette);
  
   int flag = 0;
   for (int j = 0; j <= i - 1; j++)
   {
     if (czeichenkette[j-1] == '#' && flag == 0)
       flag = 1;
     if (czeichenkette[j] == '#' && flag == 1)
       flag = 0;
     if (flag == 1)
     {
       chelfer[k] = czeichenkette[j];
       k++;
     }
   }
   chelfer[k]='\0';
   return chelfer;
}





Schlusswort

Ich hoffe, wir konnten Ihnen mit dieser Zusammenfassung und den vielen Beispielen beim Erlernen der Programmiersprache C/C++ oder als Nachschlagemöglichkeit hilfreich zur Seite stehen.

Wir wünschen Ihnen Viel Erfolg und Spass mit C/C++!


Autoren: Marc Wershoven, Anika Muschner (2013)

WICHTIGE HINWEISE!

Als kostenlosen Service stellen die Autoren von www.Online-VBA.de Dateien zum Download bereit. Dieser Download erfolgt stets auf eigene Gefahr.

Bitte beachten Sie die Nutzungsbedingungen und das Impressum von www.Online-VBA.de, bevor Sie die Datei herunterladen.

Ein kostenloser Support oder Service für die unter www.Online-VBA.de veröffentlichen Werke kann leider nicht angeboten werden!

Bei allen Inhalten und Beiträgen handelt es sich um in Freizeitprojekten entstandene Werke.

Die Verwendung der Quelltexte erfolgt auf eigene Gefahr!

Copyright-Hinweise inkl. Autorennennungen dürfen nicht entfernt werden!

Eine kommerzielle bzw. gewerbliche Verwendung der Inhalte von www.Online-VBA.de ist nicht gestattet!

Wir möchten trotzdem darauf hinweisen, dass die Autoren gemeinsam sorgfältig die Inhalte vor der Veröffentlichung prüfen, aber auch wir sind nur Menschen. Daher können wir keine Fehlerfreiheit garantieren. Wir sind aber immer froh und dankbar, wenn Sie uns gefundene Fehler einfach formlos via E-Mail zukommen lassen und wir diese beim nächsten Update korrigieren können!

Diese Seite wird gesponsert von:
WershovenOnline - IT/EDV Dienstleistungen und Beratung

Zum Seitenanfang