C++ Tutorial

08/22/2010 14:19 G0dM0de#1
Vorwort
Für dieses Tutorial wurde der Borland C++ Builder 5 eingesetzt.

Folgendes wird erklärt: Eine Anwendung wird geschrieben, die eine Instanz einer Klasse "Datenbank" hat. Diese Datenbank wird sich selbst mit zufälligen Werten füllen können. Die Anwendung wird ein Image haben, das die Datenbank als Diagramm ausgibt. Dann wird die Datenbank noch eine Methode zum sortieren bekommen, die mit einem Timer laufen wird. Der Timer zeichnet jedes mal das Diagramm neu. So kann man mitsehen, wie die Datenbank sortiert wird und wie der jeweilige Sortieralgorithmus funktioniert.

Programm
Startet den Borland C++ Builder und legt ein neues Projekt an. Und zwar wählt ihr "Anwendung". Jetzt speichert erst einmal alle Dateien in einen Ordner und compiliert durch. Lasst die Unit1 Datei so benannt und die Projektdatei auch. Außer ihr wisst nachher selber, wie ihr das Tutorial an eure Wünsche anpassen könnt. Das Programm läuft also und kann weiter programmiert werden!

Folgende Elemente werden wir benötigen, ich werde sie vorher schon nennen, jedoch müsst ihr sie nicht gleich anlegen!

2 Objekte TBevel (damit das ganze schöner aussieht)
3 Objekte TButton
1 Objekt TImage
1 Objekt TTimer

Euer Projekt könnte dann so aussehen:



Die Anordnung ist egal, was aber wichtig ist: Das Image sollte 225x225 px groß sein! Später mehr dazu. Und der Timer sollte von Anfang an auf Enabled = false sein! Damit nicht beim Programmstart schon sortiert wird!

Jetzt geht ihr beim Builder auf Datei -> Neu ... und legt eine neue Headerdatei an. Hier schreiben wir jetzt die Klasse rein. Sie soll "Datenbank" heißen, was auch ihrer Aufgabe enspricht. Zwar eine sinnlose Datenbank, aber es ist eine Datenbank. Wir lassen alle Methoden und Eigenschaften auf public. Wir brauchen jetzt einen Integer für die Liste, also die eigentliche Datenbank, einen Zeiger auf das Bild, eine Funktion, die der Klasse das Bild übergibt, eine Methode die die Liste füllt, eine die zeichnet und eine die alles sortiert. Natürlich wird jede Methode später einzeln beschrieben!
Ihr müsst außerdem die Datei vcl.h einbinden, damit die Klasse auf die Objekte vom Borland Builder zugreifen kann.
Das ganze sieht dann so aus:

Datenbank.h
Code:
class Datenbank
{
public:

int Liste[225];
TImage* mp_Bild;

void fuellen();
void setImage(TImage* p_Bild);
void zeichnen();
void sortieren();
};

Speichert nun die Datei ab, wie oben angegeben, unter Datenbank.h. Natürlich in das gleiche Verzeichnis, in dem auch das Projekt liegt. Da ihr die Datei über die Entwicklungsumgebung angelegt habt, während das Projekt geöffnet war, wurde die Headerdatei automatisch dem Projekt zugefügt. Also auf keinen Fall die Headerdatei mit einem Editor anlegen, oder das Projekt vor dem Anlegen schließen! Das gleiche gilt auch bei der nächsten Datei!

Jetzt legen wir die dazugehörige C++ Datei an! Wieder auf Datei -> Neu ... Cpp-Datei. Hier wird die Klasse ausprogrammiert. Damit wir die Struktur der Klasse kennen, müssen wir sie einbinden. Legt die einzelnen Funktionen schonmal an, lasst sie aber noch leer:

Datenbank.cpp
Code:
#include "Datenbank.h"

void Datenbank::fuellen()
{

}

void Datenbank::setImage(TImage* p_Bild)
{

}


void Datenbank::zeichnen()
{

}

void Datenbank::sortieren()
{

}
(Ihr müsst zwischen durch am besten immer durchcompilieren, um zu kontrollieren, ob alles funktioniert. Ich hatte z.B. gerade das Problem, dass mir der Compiler gesagt hat, dass zeichnen() kein Element von Datenbank ist. Dann müsst ihr folgendes machen: Projekt -> Optionen ... -> Linker: Debug-Informationen einbinden und Dynamische RTL verwenden aus schalten! Später aber wieder aus schalten, da ihr sonst wieder andere Probleme bekommt.)

Als erstes programmieren wir setImage aus, diese Methode ist die einfachste! Sie legt einfach nur den TImagezeiger der Klasse fest. Man könnte ihn dann private machen, so dass man nur über die Methode ein Image zuweisen kann. Die Methode bekommt einen Imagezeiger (p_Image). p steht für Pointer = Zeiger. In der Klasse steht dann mp_Bild. m bedeutet Member (also "Mitglied" oder "Teil" der Klasse). Und mp ist die Bezeichnung für member und pointer, da das Image in der Klasse beides ist!

Also geben wir nun p_Bild an mp_Bild weiter!

Datenbank.cpp
Code:
#include "Datenbank.h"

void Datenbank::fuellen()
{

}

void Datenbank::setImage(TImage* p_Bild)
{
mp_Bild = p_Bild;
}

void Datenbank::zeichnen()
{

}

void Datenbank::sortieren()
{

}

Als nächstes programmieren wir die Füllmethode aus. Das geht auch ziemlich einfach:

Datenbank.cpp
Code:
#include "Datenbank.h"
#include <stdlib.h>

void Datenbank::fuellen()
{
for(int i = 0; i < 225; i++)
{
Liste[i] = random(226);
}
}

void Datenbank::setImage(TImage* p_Bild)
{
mp_Bild = p_Bild;
}

void Datenbank::zeichnen()
{

}

void Datenbank::sortieren()
{

}

Die Liste der Klasse wird mit zufälligen Zahlenwerten von 0 - 225 gefüllt. Um random() zu verwenden, müssen wir die Bibliothek stdlib.h einbinden. random(int Zahl) liefert eine Zufallszahl im Bereich von 0 bis (Zahl-1) zurück. Unser Image ist 255x255 px groß, also sehen wir nur Werte die zwischen 0 und 225 liegen, deshalb das Intervall von random().


Jetzt wird es langsam anspruchsvoller, zumindest, wenn man noch nie mit dem TImage Objekt gearbeitet hat. Wir haben jetzt also unseren Zeiger auf das Image mp_Bild. Diesem können wir nun Anweisungen zum zeichnen geben, mit der Methode Canvas.

Datenbank.cpp
Code:
//...

void Datenbank::zeichnen()
{
mp_Bild->Canvas->MoveTo(0,0);
mp_Bild->Canvas->Rectangle(0,0,225,225);

mp_Bild->Canvas->MoveTo(0,0);

for(int i = 0; i < 225; i++)
{
mp_Bild->Canvas->LineTo(i,Liste[i]);
}
}

//...

Als erstes bewegen wir den Punkt, von dem aus wir anfangen zu zeichnen, ganz nach links oben. Anders als im gewöhnlichen Koordinatensystem, fängt man nicht unten links bei (X/Y) (0/0) an, sondern oben links.
Wir zeichnen ein Rechteck (Rectangel(X1, Y1, X2, Y2)), damit wir einen Rahmen haben. Das dient nur dazu, dass das ganze schöner aussieht. Ist also nicht unbedingt notwendig. Rectangle zeichnet einen Rahmen vom Punkt (X1/Y1) nach (X2/Y2). Dann setzen wir den "Stift" wieder nach links oben in die Ecke.
Jetzt kommt das eigentliche: Es wird eine Linie gezeichnet, abhängig von den Werten der Liste. Die Linie wird gezeichnet mit X = i und Y = Liste[i]. Wäre die Liste also mit 225 gleichen Werten gefüllt, würde eine gerade durch das Bild gehen.

Nun müssen wir soriteren. Ganz einfach wäre es natürlich mit einer fertigen Sortiermethode. Wir schreiben jedoch selber eine, ihr könnt später das Programm auch mit anderen Methoden ausprobieren.

Unser Sortieralgorithmus wird so funktionieren: Er durchläuft die Liste und überprüft den nächsten Eintrag, ob dieser größer ist. Und tauscht dann ggf. Das bedeutet natürlich, dass man die Liste n-mal sortieren muss. Der Sortieralgorithmus würde beim ersten mal nur klappen, wenn man zwei oder vielleicht sogar noch drei Einträge hätte. Aber bei 225 Einträgen muss der Algorithmus öfters durchlaufen!

Die Problematik beim Tauschen von Variablen beim Programmieren ist in erster Linie die, dass ich, wenn ich zwei Variablen a und b habe, b a zuweise und dann zwei gleiche Werte habe. Dann kann ich nicht mehr a b zuweisen. Deshalb braucht man hier eine Hilfs- bzw. Tauschvariable.



Beispiel:
Code:
| a | b | h |
|---|---|---|
| 5 | 2 | - |
1.| 5 | 2 | 5 |
2.| 2 | 2 | 5 |
3.| 2 | 5 | 5 |
Unsere Sortierenmethode sieht dann so aus:

Datenbank.cpp
Code:
//...

void Datenbank::sortieren()
{
int h;

for(int i = 0; i < 225; i++)
{
if(Liste[i] > Liste[i+1])
{
h = Liste[i];
Liste[i] = Liste[i+1];
Liste[i+1] = h;
}
}
}

//...
Das wars nun von der Klasse! Jetzt müssen wir nurnoch das Form anpassen. Öffnet die Unit1.h und ruft eine Instanz von der Datenbank ins Leben. Bei mir heißt sie DieDatenbank. Schreibt sie unter die public-Anwenderdeklarationen. Und natürlich müsst ihr die Headerdatei Datenbank.h einfügen! So sollte das ganze dann aussehen:

Unit1.h
Code:
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>

#include "Datenbank.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published: // Von der IDE verwaltete Komponenten
TBevel *Bevel1;
TBevel *Bevel2;
TButton *Button1;
TButton *Button2;
TButton *Button3;
TImage *Image1;
TTimer *Timer1;
void __fastcall Button1Click(TObject *Sender);
void __fastcall Button2Click(TObject *Sender);
private: // Anwender-Deklarationen
public: // Anwender-Deklarationen
__fastcall TForm1(TComponent* Owner);
Datenbank DieDatenbank;
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
Jetzt wieder zurück zur Unit1.cpp. Dort müssen wir jedem Button seine Funktion zuweisen. Ihr könnt ihre Caption auch demensprechend ändern. Also auf den Button "Füllen", "Zeichnen" und "Soriteren" schreiben. In den Konstruktor von Form1 setzen wir das Bild fest und zeichnen die leere Datenbank. So, dass wir nur einen Rahmen haben.
Vergesst nicht, dass der Timer Enabled = false sein sollte! Also, falls ihr das noch nicht gemacht habt, stellt das beim Objektinspektor ein oder schreibt es in den Konstruktor von Form1 rein! Ich werde beides machen. Alle Buttons führen direkt eine Methode aus, nur der Sortierbutton setzt den Timer auf Enabled = true. So sollte eure Unit1.cpp nun aussehen:

Unit1.cpp
Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
// Konstruktor

Timer1->Enabled = false;

DieDatenbank.setImage(Image1);
DieDatenbank.zeichnen();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
DieDatenbank.fuellen();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DieDatenbank.setImage(Image1);
DieDatenbank.zeichnen();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------
Jetzt muss der Timer noch soriteren und dann die Datenbank nach jedem Sortierschritt zeichnen. Wir setzen das Timerintervall noch etwas niedriger, damit schneller sortiert wird. Setzt es auf 100, das sollte reichen. Das war nun der letzte Schritt. Fertig sieht dann die Unit1.cpp so aus:

Unit1.cpp
Code:
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
Timer1->Enabled = false;
Timer1->Interval = 100;

DieDatenbank.setImage(Image1);
DieDatenbank.zeichnen();
}
//---------------------------------------------------------------------------

void __fastcall TForm1::Button1Click(TObject *Sender)
{
DieDatenbank.fuellen();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button2Click(TObject *Sender)
{
DieDatenbank.setImage(Image1);
DieDatenbank.zeichnen();
}
//---------------------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender)
{
Timer1->Enabled = true;
}
//---------------------------------------------------------------------------


void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
DieDatenbank.sortieren();
DieDatenbank.zeichnen();
}
//---------------------------------------------------------------------------


So sollte euer Programm nun funktionieren:







C++ Wecker / Zeitgesteuerte Codeausführung04.01.2010

Für unseren Wecker benötigen wir eine Klasse (Wecker). Diese Klasse hat die set- und get-Methoden (beim Wecker: set: stellen(...) und get: Weckzeit()). Eine Methode, die die aktuelle Windows-Uhrzeit auf dem Bildschirm ausgibt Uhrzeit(). Und natürlich das wichtigste: Die Methode, die ausgeführt wird, wenn die Weckzeit mit der Uhrzeit übereinstimmt: klingeln().
Meine Klasse wird also ein Wecker. Man kann natürlich auch alles andere machen. Ein Wecker ist bloß in diesem Fall das beste Beispiel, passt wunderbar in das Prinzip rein!

Was noch wichtig ist: Wir müssen die Uhrzeit regelmäßig abfragen. Also brauchen wir eine Endlosschleife mit einer Sleep()-Methode.

Und außerdem habe ich die Methode system("CLS") auch ein paar Mal gebraucht. Sie löscht den Bildschirm in der Konsole. Folgende Bibliotheken sind nun wichtig für uns:
Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h> // system()
#include <time.h> // time
#include <dos.h> // time

class Wecker
{
// ...
};

void main()
{
getch();
}
Die Klasse braucht natürlich ihre Weckzeit, die sie speichert. Also geben wir ihr drei Integerwerte. Außerdem noch die Variable, mit der wir die Zeit abfragen. Diese Variablen setzen wir alle auf private, da wir sie nur innerhalb der Klasse benötigen. Und time t setzen wir in die Klasse und nicht in die einzelnen Methoden, da wir sie in mehr als einer Methode benötigen!
Code:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h> // system()
#include <time.h> // time
#include <dos.h> // time


class Wecker
{
private:
int WZ_h; //WeckZeit Stunde
int WZ_m;
int WZ_s;

struct time t;

public:
void stellen(int h, int m, int s)
{

}

void Uhrzeit()
{

}

void Weckzeit()
{

}

bool klingeln()
{

}
};

//---------------------------------------------------------------------------

void main()
{
getch();
}
So, die leeren Methoden hab ich auch gleich hinzugefügt. stellen() benötigt natürlich Parameter und übergibt die Werte von außen nur der Klasse. klingeln() hat den Rückgabetyp bool (true / false), damit man später die Klasse fragen kann: Ist die Weckzeit schon erreicht? Nein? -> false; Ja? -> true.
Das ganze sieht dann so aus:
Code:
class Wecker
{
private:
int WZ_h; //WeckZeit Stunde
int WZ_m;
int WZ_s;

struct time t;

public:
void stellen(int h, int m, int s)
{
WZ_h = h;
WZ_m = m;
WZ_s = s;
}

void Uhrzeit()
{

}

void Weckzeit()
{

}

bool klingeln()
{
gettime(&t);

if(WZ_h == t.ti_hour && WZ_m == t.ti_min && WZ_s == t.ti_sec)
{
return true;
}
else
{
return false;
}
}
};
gettime(&t) holt die aktuelle Zeit und dann können wir mit t.ti_hour usw. die Uhrzeit abfragen. Ihr könnt natürlich gettime() nicht an einer Stelle ausführen, wo sich das Programm 5 Minuten vor der Abfrage befindet, da dann in t der Wert von vor 5 Minuten stehen würde. Ich hoffe das ist so einigermaßen klar!
So, und dann ist die Abfrage mit UND verknüpft. Das ergebnis muss überall true sein, damit das Ereignis eintritt. Also Stunde, Minute und Sekunde müssen übereinstimmen (Weckzeit / Uhrzeit).

Jetzt kommen wir noch schnell zur Ausgabe von den beiden Zeiten:
Code:
class Wecker
{
private:
int WZ_h; //WeckZeit Stunde
int WZ_m;
int WZ_s;

struct time t;

public:
void stellen(int h, int m, int s)
{
WZ_h = h;
WZ_m = m;
WZ_s = s;
}

void Uhrzeit()
{
gettime(&t);

printf("Uhrzeit: %i:%i:%i\n", t.ti_hour, t.ti_min, t.ti_sec);
sleep(1);
system("CLS");
}

void Weckzeit()
{
printf("Weckzeit: %i:%i:%i\n", WZ_h, WZ_m, WZ_s);
}

bool klingeln()
{
gettime(&t);

if(WZ_h == t.ti_hour && WZ_m == t.ti_min && WZ_s == t.ti_sec)
{
return true;
}
else
{
return false;
}
}
};
Wichtig ist, dass Uhrzeit() später nach Weckzeit() ausgeführt wird, da sich die sleep()-Methode in Uhrzeit() befindet und man sonst nichts von der Weckzeit mitbekommen würde. Aber das ist auch nicht so wichtig! Das dient uns im Moment nur zur Kontrolle.
So, Weckzeit() ist klar. Gibt einfach nur die 3 Integer auf dem Bildschirm aus. Und Uhrzeit(): Holt sich erst wieder die aktuelle Uhrzeit mit gettime() und gibt sie dann auf dem Bildschirm aus. Daraufhin folgt sleep(). 1 ist der kleinste Wert. sleep() erwartet einen unsignet int , das bedeutet einen Integer ohne Vorzeichen. Negative Werte sind ausgeschlossen. Was aber viel schlimmer ist: Wir können keine Kommazahlen (double, float) verwenden! Das heißt, manchmal wird der Wecker nicht ausgelöst, wenn sich die sleep() Methode grade an einem unpassenden Zeitpunkt befindet. Ihr werdet es noch beim Test sehen!
Aber das ist nunmal die einfachste Methode und vorerst ausreichend.
Als nächstes wird der Bildschirm gelöscht, damit wir nicht eine endlose Liste von Uhrzeiten haben, wenn wir später jede Sekunde die Uhrzeit aufrufen.

Das wars von der Klasse! Jetzt fehlt uns nurnoch die main()-Funktion! Bei dieser fasse ich mich kurz.
Code:
void main()
{
Wecker meinWecker;

int scan_h; // Zwischenspeicher fuer Eingabe
int scan_m;
int scan_s;

printf("Wecker einstellen: \n");
printf("hh: ");
scanf("%i", &scan_h);

printf("mm:");
scanf("%i", &scan_m);

printf("ss:");
scanf("%i", &scan_s);

system("cls");

meinWecker.stellen(scan_h, scan_m, scan_s);

while(1)
{
meinWecker.Weckzeit();
meinWecker.Uhrzeit();

if(meinWecker.klingeln() == true)
{
printf("BEEEEEP!");
//printf("\a"); // PC macht einen Beepton
break;
}
}

getch();

system("CLS");

printf("Programm beenden durch Tastendruck ...");
getch();
}
Als erstes rufen wir eine Instanz ins Leben (meinWecker). Dann kommen Zwischenspeichervariablen für den Wecker, da wir mit scanf jede Variable einzeln abfragen. Das erstpart uns den Stress mit den Doppelpunkten, dass wir nicht noch einen String außeinander nehmen müssen. Dieses Tutorial soll ja nur das Minimum erklären! Die Texte aus den printf()-Methoden dienen nur zur Orientierung des Benutzers. Dann wird der Bildschirm noch mal gelöscht und die Werte an die Klasse übergeben (meinWecker.stellen(...)), bevor's los geht! Und dann kommt die (theoretische) Endlosschleife. Jedoch befindet sich ein break in ihr.
Jetzt werden immer beide Zeiten ausgegeben. Uhr- und Weckzeit. Insgesamt wird dann ca. eine Sekunde gewartet, dann verglichen: Wenn der Vergleich positiv ausfällt, liefert klingeln() true zurück. Und dann kommt es zum Beep und zum Abbruch der while()-Schleife.
Dann noch ein Tastendruck und man wird raus geführt.

C++ Klassen03.01.2010

Vorraussetzungen
Einstieg in C

Vorwort
In diesem Tutorial werde ich euch:
Klassen
if-Abfrage
UML (Klassendiagramm)

beibringen.

Programm
Wir erstellen erst einmal wieder unser Hauptprogramm mit der main() Funktion. Bauen wir es gleich so auf, das es sich nicht nach einem Durchlauf schließt und binden wir gleich die Bibliotheken stdio.h und conio.h ein, damit wir sie gleich drin haben!
Code:
#include <stdio.h>
#include <conio.h>

void main()
{
getch();
}
Ihr könnt übrigens bei den Compilerbibliotheken, also den Bibliotheken, die ihr in die spitzen Klammern schreibt, ".h" auch weg lassen. Sie werden trotzdem eingebunden.

Nun zu unsrer Klasse. Wir bauen uns vorerst mal eine ganz einfache Klasse. Sie soll rechnen können: Addieren, Subtrahieren, Dividieren und Multiplizieren. Wie schon im vorherigen Tutorial brauchen wir dafür 3 Variablen.
Eine Klasse besteht aus Methoden und / oder Eigenschaften. Eigenschaften sind Variablen, die in der Klasse stehen (int, string, float, usw.), Methoden ausführbare Befehle, so wie z.B. printf().
Die Klasse muss vor der main() Funktion deklariert werden, damit sie in der main() Funktion auch bekannt ist. Eine Klasse ist vom Datentyp class. Für unsere Klasse verwenden wir einen aussagekräftigen Namen "Rechner", damit man weiß, was die Klasse macht. Ihr könnt sie folgendermaßen deklarieren:
Code:
#include <stdio.h>
#include <conio.h>

class Rechner;

void main()
{
getch();
}
So hat die Klasse jedoch noch keinen Inhalt. Weder Methoden noch Eigenschaften. Nebenbei möchte ich euch auch noch einen kleinen Einblick in die UML (Unified Modeling Language) geben. Wenn ihr mal etwas programmieren wollt, das komplexer ist, könnt ihr mit ihr sehr gut dokumentieren. Im Beruf kann es auch sein, dass ihr einen Plan bekommt, nachdem ihr dann programmieren müsst.
Wir erstellen also ein Klassendiagramm zu unserer Klasse "Rechner". Sie hat noch keine Inhalte, also sieht unser Klassendiagramm folgendermaßen aus:



Im oberen "Kasten" des Klassendiagramms steht der Klassenname. Im nächsten stehen die Eigenschaften und im letzten die Methoden. Die Bezeichnung der Datentypen und die Syntax ist in der UML etwas anders, als in der Programmiersprache. Darauf werd ich aber am entsprechenden Punkt noch eingehen.

Nun brauchen wir Inhalt für unsere Klasse. Wir brauchen also drei Variablen (float) für unsere Rechnungen (Eigenschaften) und vier Funktionen für jede Rechnung (Methoden). Bei Klassen muss man angeben, ob die Methoden und Eigenschaften public, private oder protected sind. Ich schreibe erstmal die Klasse, später erkläre ich es:
Code:
#include <stdio.h>
#include <conio.h>

class Rechner
{
public:
float Zahl1;
float Zahl2;
float Ergebnis;

float addieren(float Uebergabe1, float Uebergabe2)
{

}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{

}

float dividieren(float Uebergabe1, float Uebergabe2)
{

}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{

}

};

void main()
{
getch();
}
Jetzt wirds kernig! Erstmal das mit public, private, protected usw.! Also, alles was unterhalb von public: steht ist public! Wollt ihr private Elemente müsst ihr private: in die Klasse schreiben und darunter eure private Elemente. Aber lassen wir das vorerst. Nun die Erklärung:

public: Auf Elemente, die public sind, kann jeder zugreifen. Ob außerhalb der Klasse oder innerhalb, jeder kann es. So kann z.B. innerhalb der main() Funktion direkt auf Zahl1 der Klasse Rechner zugegriffen werden. Möchte man dies nicht, braucht man ...

private: Auf Elemente, die private sind, kann nur die Klasse selbst zugreifen. Außerhalb der Klasse kann nicht auf die Elemente zugegriffen werden.

protected: Elemente die protected sind, sind nur für Ableitungen wichtig. Auf diese werde ich in einem anderen Tutorial eingehen.

Man kann Klassen ableiten, dabei werden die Inhalte der Klasse kopiert und in eine neue hinzugefügt (wie gesagt, späteres Tutorial!). Dabei geschieht folgendes:
public: Wird abgeleitet, bleibt public
private: wird nicht abgeleitet
protected: wird abgeleitet und zu private

In der UML wird die Sichbarkeit mit folgenden Kürzeln angegeben:
public: +
private: -
protected: #

Wir ändern unsere Zahlen so, dass sie private sind, damit nur die Methoden auf diese zugreifen können:
Code:
#include <stdio.h>
#include <conio.h>

class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{

}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{

}

float dividieren(float Uebergabe1, float Uebergabe2)
{

}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{

}

};

void main()
{
getch();
}
Nun weiter mit der Erklärung... Die Syntax einer Klasse sieht folgendermaßen aus (wie schon im Code zu sehen ist):
Code:
// ...
class Klassenname
{
// ...
};
// ...
Ganz wichtig ist der Strichpunkt nach der schließenden geschweiften Klammer! Dieser wird oft vergessen und sorgt für Compilerfehlermeldungen. Dieser Strichpunkt ist etwas ungewöhnlich, ich weiß. Man kann die Klasse auch vorher deklarieren, was in speziellen Fällen notwendig ist (hier nicht):

Code:
#include <stdio.h>
#include <conio.h>

class Rechner;

class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{

}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{

}

float dividieren(float Uebergabe1, float Uebergabe2)
{

}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{

}

};

void main()
{
getch();
}
Weiter mit der Erklärung. Wir behalten die Variante bei, die die Klasse nicht vorher schon deklariert. Wenn nicht, macht das auch nichts aus. Also, wir haben hier vier Methoden. Eine Methode hat folgenden Aufbau, folgende Syntax:
Code:
// ...
Rückgabetyp Methodenname(Parametertyp Parameter_1, Parametertyp Parameter_2, ..., Parametertyp Parameter_n)
{
// ...
return Rückgabe; // ggf.
}
// ...
Ist der Rückgabetyp vom Typ void, gibt die Methode keinen Wert zurück, braucht demzufolge kein return. In unserem Fall wird jedoch jede Methode einen Wert zurückgeben, da wir ja ein Ergebnis bekommen.
Dann gibt es noch den Parameter. In unserem Fall haben wir je Methode zwei Paramter. Die Variablen werden in unserem Fall in der Methode deklariert, da vor dem Parameternamen ein Parametertyp (float) steht:
Code:
float addieren(float Uebergabe1, float Uebergabe2)
{

}
Die Variablen Uebergabe1 und Uebergabe2 können nur in der jeweiligen Methode verwendet werden. Sie sterben am Ende der Methode.
Code:
float addieren(float Uebergabe1, float Uebergabe2)
{// <- Uebergabe1, Uebergabe2 werden ins Leben gerufen

}//<- Uebergabe1, Uebergabe2 sterben
Ihr könnt also Uebergabe1 und Uebergabe2 nicht von wo anders aus aufrufen. Zahl1 wird später Uebergabe1 zugewiesen und Zahl2 Uebergabe2. Man bräuchte sie garnicht zuzuweisen, sondern könnte gleich der Variable Ergebnis das Ergebnis der beiden Übergabewerte zuweisen, jedoch machen wir das hier so, es ist einfach ordentlicher.

Jetzt müssen wir jedoch erstmal unser Klassendiagramm aktualisieren. Syntax ist hier bei Eigenschaften:
Code:
Sichtbarkeit Name: Datentyp

Bei einer Methode:
Code:
Sichtbarkeit Name(Parameter_1:Parametertyp, Parameter_2:Parametertyp, ..., Parameter_n:Parametertyp): Rückgabetyp
Wie man sieht ist das ganze genau anders rum, ja, ziemlich blöd. Was noch dazu kommt, ist, dass man die Datentypen nicht programmiersprachenspezifisch angibt. Das heißt, ihr schreibt dort nicht "+ Name: int" rein.

Ein paar Datentypen:
int = GZ (Ganzzahl)
float = FKZ (Fließkommazahl)
string = Text

Also sieht unser neues Klassendiagramm folgendermaßen aus:



Nun zurück zu unseren Methoden. Jetzt programmieren wir sie aus.
Code:
#include <stdio.h>
#include <conio.h>


class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 + Zahl2;

return Ergebnis;
}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 - Zahl2;

return Ergebnis;
}

float dividieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 / Zahl2;

return Ergebnis;
}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 * Zahl2;

return Ergebnis;
}

};

void main()
{
getch();
}
Jetzt haben wir in jeder Methode den entsprechenden Rechenschritt. Den Variablen Zahl1 und Zahl2 der Klasse werden die Übergabewerte Uebergabe1 und Uebergabe2 der jeweiligen Methoden zugewiesen. Wenn man jetzt z.B. eine Addition durchführen würde und diese beendet wäre, würden die Werte in Zahl1 und Zahl2 immernoch drin stehen. Jedoch könnte man sie nicht abrufen, da sie private sind. Die Werte von Uebergabe1 und Uebergabe2 könnte man nicht mehr von Außerhalb abrufen, da die Werte am Ende der Methode sterben.
Und da unsere Methoden einen Rückgabewert vom Typ float erwarten, geben wir ihnen auch einen vom Typ float zurück (return Ergebnis). Ein anderer Datentyp wäre wahrscheinlich nicht möglich, wie z.B. ein String. Einen Integer akzeptiert der Compiler, aber ob alles problemlos funktionieren wird, weiß ich nicht.

Nun haben wir unsere Klasse fertig geschrieben. Eine Klasse ist jedoch nur etwas wie ein Bauplan. Wir können die Klasse so nicht benutzen, wir brauchen eine Instanz. Wir können uns das so vorstellen: Der Vogel ist die Klasse (der Bauplan) und eine Amsel ist eine Instanz. Oder ein Auto. Ein Auto kann ein Bauplan sein und ein Opel eine Instanz. Ein Opel kann natürlich auch wieder ein Bauplan sein, das ist Ansichtssache. Und dann das bestimmte Model eine Insanz.

Also, wir haben jetzt unsere Klasse Rechner geschrieben und können, genauso wie bei allen anderen Datentypen, eine Instanz vom Typ Rechner bilden. Deshalb solltet ihr keine Klasse schreiben, die int, float, string usw. heißt. Also rufen wir eine Instanz ins Leben:
Code:
#include <stdio.h>
#include <conio.h>


class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 + Zahl2;

return Ergebnis;
}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 - Zahl2;

return Ergebnis;
}

float dividieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 / Zahl2;

return Ergebnis;
}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 * Zahl2;

return Ergebnis;
}

};

void main()
{
Rechner DerRechner;

getch();
}
Jetzt haben wir die Instanz "DerRechner". Ein ordentlicher Name würde ich sagen. In den meisten Fällen wird die Instanz so benannt: Artikel + Klassenname. Da mir sonst nichts besseres einfällt. Jetzt können wir auf die einzelnen Elemente zugreifen, solange sie public sind. Beim Methodenaufruf: DerRechner.addieren(5, 5); würden wir 10 zurück bekommen, also können wir es direkt ausgeben lassen. Damit es jedoch übersichtlicher wird, und wir nicht einen so langen Methodenaufruf im printf() haben, verwenden wir eine Zwischenvariable (float Ausgabe). Sie dient nur der Übersicht:
Code:
#include <stdio.h>
#include <conio.h>


class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 + Zahl2;

return Ergebnis;
}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 - Zahl2;

return Ergebnis;
}

float dividieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 / Zahl2;

return Ergebnis;
}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 * Zahl2;

return Ergebnis;
}

};

void main()
{
Rechner DerRechner;

float Ausgabe;

Ausgabe = DerRechner.addieren(5, 5);

printf("Ergebnis: %f \n", Ausgabe);

getch();
}
Damit das ganze nicht so langweilig ist, fügen wir noch die Eingabe hinzu, aus dem vorherigen Tutorial. Wir brauchen dafür jedoch wieder zwei Variablen zum Zwischenspeichern. Erst wird die Eingabe in sie rein geschrieben, dann werden sie an die Klasse übergeben:
Code:
#include <stdio.h>
#include <conio.h>


class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 + Zahl2;

return Ergebnis;
}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 - Zahl2;

return Ergebnis;
}

float dividieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 / Zahl2;

return Ergebnis;
}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 * Zahl2;

return Ergebnis;
}

};

void main()
{
Rechner DerRechner;

float Ausgabe;

float Zahl1;
float Zahl2;

printf("Zahl1: ");
scanf("%f", &Zahl1);

printf("Zahl2: ");
scanf("%f", &Zahl2);

Ausgabe = DerRechner.addieren(Zahl1, Zahl2);

printf("Ergebnis: %f \n", Ausgabe);

getch();
}
Jetzt habt ihr eine Klasse, die rechnen kann. Natürlich konnte man das vorher auch schon unumständlicher. Aber das ist ein gutes Beispiel für Klassen.

Ich werde euch hier noch am Rande kurz die if-Abfrage zeigen. Schwierig ist dieser Befehl nicht. Syntax:
Code:
if(Bedingung)
{
// Code für Bedingung erfüllt
}
else
{
// Bedingung nicht erfüllt, kann auch weg gelassen werden
}
Wir möchten in unserem Beispiel abfragen, ob der Benutzer addieren, subtrahieren, multiplizieren oder dividieren will. Wir weisen jedem dieser Operationen einen Zahlenwert zu. Gibt der Benutzer diesen ein, dann wird die entsprechende Operation ausgeführt.
Man könnte das auch mit "Befehlen", also Text, umsetzen, aber wir bleiben hier bei einem einfachen Beispiel.
Wir brauchen also einen Integer für die mögliche Eingabe (0, 1, 2, 3). Diesen nennen wir "Eingabe". Dann brauchen wir noch ein printf(), damit ausgegeben wird, was der Benutzer für die jeweilige Operation drücken muss. Und noch ein scanf(), das die Eingabe einliest. Und eben die if-Abfrage.
Code:
#include <stdio.h>
#include <conio.h>


class Rechner
{
private:
float Zahl1;
float Zahl2;
float Ergebnis;

public:
float addieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 + Zahl2;

return Ergebnis;
}

float subtrahieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 - Zahl2;

return Ergebnis;
}

float dividieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 / Zahl2;

return Ergebnis;
}

float multiplizieren(float Uebergabe1, float Uebergabe2)
{
Zahl1 = Uebergabe1;
Zahl2 = Uebergabe2;

Ergebnis = Zahl1 * Zahl2;

return Ergebnis;
}

};

void main()
{
Rechner DerRechner;

float Ausgabe;

float Zahl1;
float Zahl2;

int Eingabe;

printf("Zahl1: ");
scanf("%f", &Zahl1);

printf("Zahl2: ");
scanf("%f", &Zahl2);

printf("0 = Addieren\n");
printf("1 = Subtrahieren\n");
printf("2 = Multiplizieren\n");
printf("3 = Dividieren\n\n");

scanf("%i", &Eingabe);

if(Eingabe == 0)
{
Ausgabe = DerRechner.addieren(Zahl1, Zahl2);
}
if(Eingabe == 1)
{
Ausgabe = DerRechner.subtrahieren(Zahl1, Zahl2);
}
if(Eingabe == 2)
{
Ausgabe = DerRechner.multiplizieren(Zahl1, Zahl2);
}
if(Eingabe == 3)
{
Ausgabe = DerRechner.dividieren(Zahl1, Zahl2);
}
if(Eingabe != 0 && Eingabe != 1 && Eingabe != 2 && Eingabe != 3)
{
printf("Eingabe nicht möglich!\n\n");
}

printf("Ergebnis: %f \n", Ausgabe);

getch();
}
Die if-Abfrage ist eigentlich ziemlich selbsterklärend. Wenn wir den Fall durchgehen, dass ich eine 1 drücke, dann durchläuft das Programm die if-Abfragen: Ist die Eingabe == 0? Nein (false). Ist die Eingabe == 1? Ja (true), Code ausführen. Ist die Eingabe == 2? Nein (false). Ist die Eingabe == 3? Nein (false). Wenn keine der Bedinungen erfüllt (true) ist, dann gib "Eingabe nicht möglich!" aus.
Ein Ergebnis wird in diesem Fall leider trotzdem ausgegeben. Man könnte das natürlich verhindern. Z.B. indem man die Ausgabe des Ergebnisses in jede if-Abfrage setzt. Das wäre jedoch weniger elegant. Also lasse ich es so. Ihr könnt z.B. auch die Ausgabe von Anfang an auf 0 setzen (Ausgabe = 0). Dann wird im else-Fall einfach Ergebnis: 0 ausgegeben.

In diesem Beispiel kann ich euch leider nur ungeschickt die else-Anweisung zeigen, da ich für jede if-Anweisung ein else bräuchte und somit pro else im Fall false des ifs ein printf() ausgegeben werden würde. Deshalb muss ich hier am Schluss abfragen: "Ist die Eingabe ungleich 0 und ungleich 1 und ungleich 2 und ungleich 3, dann gib ... aus".

Kurze Info zur &&-Verknüpfung (logisches UND):
0 steht für false (if-Bedingung nicht erfüllt)
1 steht für true (if-Bedingung erfüllt)

0 & 0 = 0
0 & 1 = 0
1 & 1 = 1

Dann noch zum Ungleich etwas. Bei if-Abfragen könnt ihr fragen:
== : ist gleich (immer zwei = !!!)
!= : ist ungleich
> : ist größer als
< : ist kleiner als
>= : ist größergleich (größer oder gleich)
<= : ist kleinergleich (kleiner oder gleich)

Einstieg in C02.01.2010

Regeln
Nun ja, wozu Regeln? Ganz klar: Wenn man irgendwann mal komplexere Programme schreibt, oder sogar in die Spieleentwicklung geht - sei es kommerziell oder privat - dann ist Teamarbeit angesagt. Man kann kein Spiel wie Gothic 3 im 1-Mann-Projekt durchziehen. Da muss die Arbeit aufgeteilt werden ... Engine, 3D Grafik, logische Abläufe im Spiel ... Aber von Spieleprogrammierung möchte ich jetzt gar nicht weiter reden!

Also hier nun ein paar Regeln:
Einrücken
Benennung der Dinge
Sprache
Kommentare
Dokumentation
Einrücken: Rückt nach einer geschweiften Klammer immer 4 Leerzeichen vor, damit man den Quelltext später noch gut lesen kann, und selber auch nach einem Monat noch versteht. Auch anderen Programmierern, sei es im Team oder Leute, die einem helfen sollen, fällt es so einfacher, das Programm zu verstehen!

Benennung der Dinge: Benennt die Variablen, Klassen usw. immer nach dem, was sie tun oder was sie sind. Benennt zum Beispiel keinen Integer "Integer1", "Integer2", "Integer3" usw.

Sprache: Einigt euch selbst auf eine Sprache! Wenn ihr die Bennenung der Dinge und die Sprache einhaltet, dann werdet ihr euer Programm später wie ein Buch lesen können. Ich bevorzuge Englisch, da es sich mit den bereits vorhandenen Methodennamen besser liest und es von nahezu jedem verstanden werden kann.

Kommentare: Sind nicht unbedingt erforderlich. Aber, wenn ihr mal ein Programm schreibt, das euch Schwierigkeiten bereitet hat, dann solltet ihr den Teil, den ihr vielleicht nicht auf Anhieb wieder verstehen werdet, kommentieren. Oder wenn ihr etwas programmiert, von dem ihr meint, dass ihr es zu einem anderen Zeitpunkt nicht mehr verstehen werdet.

Dokumentation: Nicht mit einem Kommentar verwechseln! Ein Kommentar ist im Gegensatz zur Dokumentation eine kurzer Erklärung zu einem Programmblock oder einer Programmzeile. Unter Dokumentation versteht man, eine Klasse zum Beispiel so zu dokumentieren, also jede einzelne Methode und jedes Attribut so zu kommentieren, dass man weiß, wofür es da ist, was es als Input erwartet und was es einem wieder zurück gibt.

Programm
Damit sich das ganze hier nicht - wie jedes andere Einsteiger Tutorial - mit der einfachen Textausgabe beschäftigt, erweitere ich es noch um ein paar Kleinigkeiten, nicht viel, aber etwas Um einen lauffähigen Compiler müsst ihr euch leider selbst kümmern. Ich programmiere mit dem Borland C++ Builder 5. In diesem Tutorial dürfte das keine Rolle spielen. Hauptsache ihr habt einen lauffähigen Compiler.

Also los gehts: Grundgerüst ist für uns erstmal die main() Funktion.
Code:
void main()
{

}
So siehts aus! Die Funktion ist vom Typ void, das bedeutet, sie hat keinen Rückgabewert. Wäre sie z.B. vom Typ Integer (int main()), dann müsste man einen Integerwert zurück geben mit z.B. return 0. Da wir aber keinen Rückgabewert brauchen, weil wir keine Verwendung für ihn hätten, lassen wir es erst mal so.

Durchcompiliert macht das Programm noch garnichts. Es beendet sich auch am Ende wieder. Das wollen wir natürlich nicht, deshalb fügen wir noch die Funktion getch() ("Get Charakter") hinzu. Diese wartet auf einen Tastendruck vom Benutzer. Um diese Funktion zu benutzen müssen wir die Bibliothek conio.h einbinden. Am besten binden wir sie am Anfang des Programms ein, dann kennt alles darunter die Funktion. Bibliotheken werden eingebunden mit #include, Bibliotheken des Compilers stehen in einer spitzen Klammer (#include <conio.h>), eigene Dateien, die man einbinden, werden mit Einführungsstrichen eingebunden (#include "EigeneCPPDatei.cpp"). So wird sie aus dem Pfad der .exe Datei eingefüht. Bei eigenen Dateien müsst ihr also ggf. den entsprechenden Pfad angeben. Der Includebefehl wird nicht mit einem Strichpunkt beendet, da dieser eine Compileranweisung ist und kein C++ Befehl. Der Compiler fügt an dieser Stelle einfach nur den Quelltext der eingefügten Header(*.h)- / C++ Datei ein. Damit entwickelt sich noch ein Problem, auf das ich in einem eigenen Tutorial noch beschreiben werde. Hier wird es noch keine Probleme geben.
Der getch() Befehl muss innerhalb der main() Funktion aufgerufen werden. Außerhalb hat er keinerleis Auswirkung. Außerhalb sind demnach nur Funktionsdeklarationen und ausprogrammierte Funktionen.
An dieser Stelle muss ich noch erklären, was eine Deklaration ist. Eine Deklaration ist das alleinige "in's Leben rufen" einer Funktion oder Variable, ohne Zuweisung von Werten oder Inhalt. So wie z.B. int Wert;. Der Integer "Wert" hat jetzt theoretisch keinen Inhalt. Er wird jedoch irgendeinen wirren Inhalt aus dem Speicher haben, wenn man ihn nun aufruft.
Code:
#include <conio.h>

void main()
{
getch();
}
So, jetzt sollte das Programm noch irgendetwas machen! Also als bestes Beispiel ist eine Ein-/Ausgabe. Ich bevorzuge nicht cin und cout, sondern printf(). Die Funktion printf() gibt einen String auf dem Bildschirm aus, also einen Text oder Zahlen oder Zeichen. Der Text steht innerhalb der Klammern. Um die Funktion zu benutzen, müssen wir allerdings eine weitere Bibliothek einfügen: stdio.h, für Standardfuntionen. Also wieder wie oben, per #include!
Wenn man einen festen Text ausgeben will, würde das so aussehen (ein konstanter Text steht in Anführungsstrichen!):
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
printf("Hello World!");
getch();
}
Und was sehen wir nach dem Compilieren? Auf dem Bildschirm erscheint "Hello World!". Da wir aber eine Ein-/Ausgabe planen, brauchen wir eine Ausgabe, die nicht konstant, sondern variabel ist. Also brauchen wir eine Variable, die ausgegeben werden muss. Wir wollen nur Rechnen, also geben wir einen Integer ein und aus. Eine Fließkommzahl (Datentyp float) wäre natürlich auch möglich, aber schauen wir uns erstmal die Ganzzahlen (Datentyp int) an!

Wir legen also drei Integer an. Das ist die Mindestanzahl, die wir für eine Rechnung brauchen (a + b = c, a - b = c, a / b = c, a * b = c). Man könnte natürlich auch eine eingegebene Zahl mit einer Konstanten verrechnen, doch selbst dann bräuchten wir mindestens drei Integer! Also deklarieren wir erstmal die Integer. Ich bevorzuge es, aufgrund der Übersicht, sie nicht in einem Zug (int a, b, c) zu deklarieren, sondern untereinander (siehe Code).
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
int a;
int b;
int c;

printf("Hello World!");
getch();
}
So, nun muss jede Variable noch eingelesen werden. Um euch zu zeigen, was sonst raus kommen würde, geben wir erstmal die Variablen nur aus. Also müssen wir das printf() verändern. Wir geben in das printf() ein: a + b = c. Damit er jedoch nicht den Text ausgibt, sondern die Variablen, müssen wir das kennzeichnen.
Code:
//...
printf("%i", a);
//...
So gibt man mit printf() einen Integer (%i) aus. Weitere Datentypen sind auch möglich, dementsprechende Kürzel müssen verwendet werden. Um mehrere Variablen in einem printf() auszugeben, schreibt man sie einfach nach dem Komma in der Reihenfolge, wie sie ausgegeben werden sollen. Demensprechend viele %i müssen auch im printf() zur Verfügung stehen!
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
int a;
int b;
int c;

printf("%i + %i = %i", a, b, c);
getch();
}
Nach dem Compilieren wird bei mir zum Beispiel "1 + 256 = 1" ausgegeben, was natürlich nicht stimmt. Wir haben ja noch keine Werte eingegeben, also kommen irgendwelche Werte, die vorher jemand anders mal in den Speicher gesetzt hat raus. Jetzt brauchen wir also eine Abfrage. Diese machen wir mit scanf()! Damit der Benutzer weiß, was er wann eingeben muss, setzen wir noch ein printf() vor jede Eingabe. Die Funktion scanf() benötigt wieder Datentyp und einen Zeiger auf die Variable. Wir zeigen auf eine Variable mit dem & Operator.
Da der Integer c das Ergebnis aus a und b sein soll, wird dieser logischerweise nicht eingelesen.
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
int a;
int b;
int c;

printf("a = ");
scanf("%i", &a);

printf("b = ");
scanf("%i", &b);

printf("%i + %i = %i", a, b, c);
getch();
}
So, das einzige, was uns jetzt noch fehlt, ist eine Rechnung. Damit der Benutzer auch weiß, was gerechnet wird, geben wir vor der Abfrage noch die Formel aus. Wir benutzen vorerst a + b = c, so wie es schon da steht. In unserem Integer c steht später das Ergebnis. Also weisen wir dem Wert die Rechnung zu. In C++ wird das rechte immer dem linken zugewiesen, also c = a + b. a + b = c würde nicht funktionieren.
Da die Rechnung mit unserer Eingabe stattfinden soll, muss sie natürlich nach der Eingabe geschehen. Würde man c = a + b vor das scanf() setzen, würde das Programm mit falschen Werten rechnen.
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
printf("a + b = c\n\n");

int a;
int b;
int c;

printf("a = ");
scanf("%i", &a);

printf("b = ");
scanf("%i", &b);

c = a + b;

printf("%i + %i = %i", a, b, c);
getch();
}
Bei der Ausgabe von "a + b = c" habe ich zwei mal "\n" angehangt. Eines davon bewirkt einen Zeilenumbruch. Andernfalls würde die Ausgabe "a =" gleich hinten angehängt werden. Ihr könnt diese Zeilenumbrüche so oft ihr wollt in eure anderen printf() Funktionen einfügen, um die Darstellung euren Wünschen anzupassen.

So, wenn ihr jetzt das Programm ausführt, dann rechnet es auch a + b aus. Die Eingabe von negativen Zahlen ist auch möglich, so rechnet das Programm zum Beispiel: -5 + 5 = 0. Das könnte man auch verhindern, indem man zum Beispielen einen unsigned int verwendet, jedoch würde das in diesem Fall keinen Sinn ergeben. Der Wertebereich des Integers ist auch beschränkt und spätestens wenn man multiplizieren oder dividieren will reicht der Integer nicht mehr aus.
Also probieren wir das mal aus. Wir ersetzen das + durch ein / und haben so eine Division. Per Abfrage wäre natürlich auch eine Auswahl möglich, jedoch nicht in diesem Tutorial! Die Division ist für das Beispiel noch besser geeignet, da bei einer Division auch eine Kommazahl raus kommen kann, die mit dem Integer nicht dargestellt werden kann.
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
printf("a / b = c\n\n");

int a;
int b;
int c;

printf("a = ");
scanf("%i", &a);

printf("b = ");
scanf("%i", &b);

c = a / b;

printf("%i / %i = %i", a, b, c);
getch();
}
Gibt man jetzt 2 / 5 ein, so bekommt man das Ergebnis 0. Es besteht auch die Möglichkeit, den Rest auszugeben, aber da ist die Lösung mit einer Fließkommazahl doch angenehmer! Also ändern wir vor a, b und c das int zu float. Bei scanf() unf printf() muss demensprechend auch der Datentyp von %i zu %f geändert werden. Vergesst es nirgends, da euch sonst an irgendeiner Stelle ein falscher Wert ausgegeben wird!
Code:
#include <conio.h>
#include <stdio.h>

void main()
{
printf("a / b = c\n\n");

float a;
float b;
float c;

printf("a = ");
scanf("%f", &a);

printf("b = ");
scanf("%f", &b);

c = a / b;

printf("%f / %f = %f", a, b, c);
getch();
}
08/22/2010 23:41 BlackWu#2
Quelle angeben.
08/22/2010 23:48 JewLz. x3#3
Wenn dus' nicht selbst geschrieben hast, quelle.
09/20/2010 19:37 G0dM0de#4
Ja sry hab außm Buch
09/20/2010 23:22 MrSm!th#5
Noch ne kleine Kritik, nutz Code Tags Q_Q
09/24/2010 14:35 G0dM0de#6
Quote:
Originally Posted by MrSm!th View Post
Noch ne kleine Kritik, nutz Code Tags Q_Q
Ok danke für den Tipp :P
09/28/2010 19:53 _sh0x#7
Haste alleine getippt ausm Buch? Naja Code mal die C++ Codes. Und mach es ein bisschen übersichtlicher naja
09/28/2010 19:56 muse-#8
Quote:
Ok danke für den Tipp :P
das ist jetzt die Stelle,an der du auf edit klickst und alles in codes packst btw <: