Genereller Aufbau

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Erste Ausgabe in der Console");
        }
    }
}

Zu Beginn benötigen wir sogenannte using Direktiven. Diese werden zum Teil von Visual Studio automatisch generiert, andere muss man manuell hinzufügen. Damit lassen sich zum Beispiel grundlegende Funktionen von C# oder .Net einbinden. Der System Namespace bietet unter anderem Standardmethoden zur Ein- und Ausgabe.
An dieser Stelle sei kurz erwähnt, dass die von Visual Studio generierten using Direktiven für unsere ersten Beispiele eigentlich nicht benötigt werden. Wenn sie dich stören, kannst du sie bedenkenlos aus deinem Code entfernen.
Nach den using Direktiven kommt unser eigener namespace. Diese Namespaces beschreiben, grob gesagt, in welchen Bereich unsere Methoden und Variablen gehören. Namespaces ermöglichen auch die Verwendung gleicher Variablen- oder Methodennamen in unterschiedlichen Kontexten.
Nun folgt die Main-Funktion die in unserer Klasse Programeingebettet ist. Klassen werden an anderer Stelle behandelt. Dieses Main ist der Einstiegspunkt jedes Programmes und muss in jedem Code ein mal (und nur ein mal) vorkommen.
Das vorangestellte void definiert den Rückgabetyp dieser Funktion - nämlich keine Rückgabe. Doch dazu später mehr. Nach dem Funktionsnamen folgen zwei runde Klammern. Das string[] args beschreibt Parameter die ggf. an die Methode übergeben werden. Die geschweiften Klammern { } bilden einen sogenannten Anweisungsblock der unseren Code sozusagen gruppiert und anzeigt, dass der darin geschrieben Code zu unserer main-Methode gehört.
Console. leitet unsere Ausgabe in der Console ein. Mit WriteLine() geben wir an, was wir als Zeile in der Console ausgeben möchten.
Jede Anweisung muss mit einem Semikolon abgeschlossen werden.
Der geschrieben Code lässt sich nun in Visual Studio per Strg-F5 compilieren und ausführen.

Einfache Datentypen und Variablen

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 13;
            int b = 24, c = 26;
            float ergebnis = 5 * c + 5 - 3.0f / 7;

            bool x = true;

            float f;
            f = 13.7603f;

            char p = 'p';

            Console.WriteLine("a = {0} b = {1} c = {2}", a, b, c);
            Console.WriteLine("ergebnis = {0}", ergebnis);
            Console.WriteLine("x = {0}", x);
            Console.WriteLine("f = {0} p = {1}", f, p);
        }
    }
}


Variablen dienen dazu um Informationen wie Zahlen oder Texte zu speichern. Es gibt unterschiedliche Datentypen die abhängig ihres Inhaltes zu verwenden sind.
Typische Datentypen sind int für ganze Zahlen, float oder double für Dezimalzahlen, char für Zeichen und bool für die Wahrheitswerte true/false sowie string für Zeichenketten.
Folgende Tabelle gilt für 32 bit Systeme:
Name Minimum Maximum Größe in Bit
bool false / true 8
char 0 65535 16
int -2.147.483.648 2.147.483.647 32
uint 0 4.294.967.295 32
long -9,223,372,036,854,775,808 9,223,372,036,854,775,807 64
ulong 0 18,446,744,073,709,551,615 64
float 3,4E-38 3,4E+38 32
double 5,0E-324 1,7E+308 64
Wie du siehst werden Variablen einfach per '=' initialisiert.
Dabei ist immer der Datentyp an erster Stelle zu nennen. Es können auch mehrere Initialisierungen in einer Anweisung (also bis zum ; ) geschrieben werden. Ebenso ist es möglich - wie bei Variable f - diese zu deklarieren aber erst später zu initialisieren. Zu beachten gilt, dass das Dezimaltrennzeichen ein Punkt ist und am Ende eines floats ein f bzw bei einem double ein d nachgestellt wird.
Ebenfalls neu in diesem Code ist die Art der Ausgabe. Per { } schaffen wir sozusagen Platzhalter für Variablen die in der nachstehenden Reihenfolge befüllt werden.
Du wirst im Laufe der Zeit noch mehrere Datentypen kennenlernen, doch die hier genannten bilden sozusagen die Basis der Sprache.

Dateneingabe

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int a;
            string str;

            Console.WriteLine("Eingabe a: ");
            a = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("Eingabe str: ");
            str = Console.ReadLine();     

            //Ausgabe der Werte
            Console.WriteLine("\na = {0} str = {1}", a, str );
        }
    }
}

Die Dateneingabe ist in C# sehr einfach. Per Console.Readline() wird die Eingabe ermöglicht. Dabei ist darauf zu achten, dass die Variable vorher bereits deklariert wurde, und dass die Eingabe dem Datentyp der zu befüllenden Variable entsprechen muss.
So kann die Eingabe 'Hallo' nicht in einem integer gespeichert werden.
Da die Variable a ein integer ist und unser ReadLine() die Eingabe als String liefert benötigen wir ein Convert.ToInt32().
Eine weitere kleine Neuerung ist das \n im letzten Statement. Dieses \n stellt einen einfachen Zeilenumbruch in der Console dar und kann an jeder Stelle innerhalb von Anführungszeichen verwendet werden. Dieses \n ist eins von einer Reihe an sogenannten Escapesequenzen. Durch das vorangestellte Backslash ( \ ) lassen sich Zeichen darstellen die sonst im Programm zu Problemen führend würden.

Die wichtigsten dieser Zeichen sind:
\n – Zeilenumbruch
\‘ – Einfaches Anführungszeichen
\“ – Doppeltes Anführungszeichen
\\ - Backslash
\a – akustisches Signal (klassisches „Beep“)
\t – Tabulator
\xnn – Zeichen als Hexadezimalziffer (zB \x40 für @)
\ooo – Zeichen als Octalziffer (zB \100 für @)

Bedingte Anweisungen

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 13;
            int b = 20;
            bool x = false;

            if (a < 20)
                Console.WriteLine("a ist kleiner als 20");
            else if (a > b)
                Console.WriteLine("b ist groesser als b");

            if (x)
                Console.WriteLine("x = True");
            else
            {
                Console.WriteLine("Else wird ausgefuehrt");
                Console.WriteLine("x = Falsch");
            }
        }
    }
}

Bedingte Anweisungen ermöglichen es Codestellen nur unter definierten Umständen ausführen zu lassen. Die klassische Bedingte Anweisung ist das If-Statement. In den runden Klammern erfolgt die Prüfung des Statements. Liefert diese true (ist die Aussage also wahr) wird die Nachfolgende Anweisung ausgeführt. Das kann eine einzelne Zeile sein oder ein ganzer { } Block. Per Else If lassen sich Bedingungen aneinander Reihen. Der Else Block wird dann ausgeführt wenn keine vorgestellter If-Block ausgeführt wird.
Vereinfacht lässt sich dies mit WENN (if Statement) – DANN (Anweisung wenn wahr) – SONST (else) übersetzten.
Typische Vergleichsparameter sind < (Kleiner als), > (Größer als), '==' (ist gleich) und != (ist ungleich). Die Erste Prüfung liefert true da a kleiner als 20 ist. Das Folgende Else If wird nicht ausgeführt. If (x) liefert false da x mit false initialisiert wurde. Somit wird der Else-Block ausgeführt.

If Bedingungen können auch verkürzt in der Form ( Statement ) ? DANN : SONST; geschrieben werden. Dies ist aber nur dann geeignet wenn keine Anweisungsblöcke sondern nur einzelne Werte das Ergebnis sind. zB ( x > 5) ? „Ja“ : „Nein“; bedeutet, dass ein „Ja“ geliefert wird wenn x > 5 ist. Ansonsten wird ein „Nein“ das Ergebnis sein.

Logische Ausdrücke

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            int a = 13;
            bool x = true;

            if (a > 10 && a < 20)
                Console.WriteLine("a liegt zwischen 10 und 20");

            if (a < 10 || x)
                Console.WriteLine("a ist kleiner als 10  ODER x = true ");
        }
    }
}

Logische Ausdrücke sind Aussagen oder Bedingungen die am Ende true oder false liefern, deren Aussage also wahr oder falsch ist.
Per || lassen sich Ausdrücke Oder-Verknüpfen und per && lassen sich Ausdrücke Und-Verknüpfen. Dabei wird jeder Teilausdruck für sich selber bewertet, so dass der Ausdruck 3 > 2 && 5 == 6 false liefert da der zweite Teilausdruck falsch ist.
Derart verknüpfte Bedingungen können natürlich auch an anderen Stellen, wie zB der If-Anweisung verwendet werden.
Eine weitere Eigenschaft lässt sich mit einem ! (Rufzeichen) erzielen. Dieses wird als „Umkehrsymbol“ interpretiert. Aus !true wird also false und umgekehrt. Eine einfache übersicht bietet nachfolgende Tabelle. Leicht zu merken sind die Umstände, dass && - Verknüpfungen nur dann true liefern wenn alle Teilausdrücke true sind während || - Verknüpfungen nur dann false liefern wenn alle Teilausdrücke false sind.
Wahrheitstabelle

Schleifen

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //FOR SCHLEIFE
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine(i);
            }

            //WHILE SCHLEIFE
            int j = 0;
            while (j < 10)
            {
                Console.WriteLine(j);
                j = j + 1;
            }

            //DO SCHLEIFE
            int k = 0;
            do
            {
                Console.WriteLine(k);
                k = k + 1;
            } while (k < 10);
        }
    }
}

Schleifen werden dazu verwendet um bestimmte Anweisungen wiederholt ausführen zu lassen. Typsiche Schleifen sind for, while und do. Jede der drei Schleifentypen sind untereinander austauschbar wobei die do-Schleife als einzige mindestens ein mal ausgeführt wird da die Prüfung erst am Ende der Schleife ausgeführt wird. Schleifen bestehen in der Regel aus dem Schleifenkopf in der geprüft wird ob der folgende Schleifeninhalt ausgeführt wird. So bedeutet for (int i=0; i<10; i++), dass die Variable i mit 0 beginnt und so lange i kleiner als 10 ist die Schleife ausgeführt wird. Danach wird i um 1 erhöht. Das passiert so lange bis i<10 false liefert. Wichtig ist hierbei, dass diese Bedingung auch tatsächlich irgendwann false liefert da man sonst in einer Endlosschleife landet.
Alle drei Schleifen liefern alle das selbe Ergebnis.
Diese Folgenden Grafiken verdeutlichen die Funktionsweise der Schleifen:
For-Schleife
For-Schleife
While-Schleife
While-Schleife
Do-Schleife
Do-Schleife

Arrays und Listen

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void Main(string[] args)
        {
            //array mit 20 Plätzen
	        int[] arr1 = new int[20];

	        //Liste
            List list1 = new List();

	        //array befüllen
	        for (int i = 0; i < 20; i++)
		        arr1[i] = i;
	
	        //array ausgeben
	        for (int i = 0; i < 20; i++)
		        Console.WriteLine(arr1[i]);

	        //Die Methode Add() fügt bei einer Liste den Inhalt hinten an Remove() oder RemoveAt() entfernt einen Eintrag
	        list1.Add(159);
	        Console.WriteLine(list1[0]);
        }
    }
}

Als Array oder Liste bezeichnen wir einen Datentyp der sozusagen als Container für eine andere Variablen dient. So kann man zum Beispiel einem Array mit dem Namen ziffern 20 Zahlen speichern ohne dafür 20 integer-Variablen anlegen zu müssen.
Jeder dieser Container legt seine beinhaltenden Informationen unter einem fortlaufenden Index ab. So liegt der erste Wert auf Patz 0 (wir beginnen immer bei 0 an zu zählen) und z.B. der dritte Wert auf Platz 2. Referenziert wird dieser Platz - zum befüllen oder abrufen - per [INDEX]. Im nachfolgenden Beispiel sind zwei der häufigsten Listentypen vorgestellt. Das Array, das eine fixe Größe hat und der Vector mit dynamischer Größe. Der Beinhaltende Datentyp wird gleich bei der Deklarierung angegeben und kann nicht geändert werden. So kann ein integer-Array nur Variablen vom Typ integer enthalten.
Wichtig hierbei ist zu beachten, dass man in seinem Code keine Zugriffsverletzungen ausführt. So kann ein Array arr1 mit 10 Werten keinen Wert bei arr1[12] enthalten oder entgegennehmen.
Ebenfalls möglich ist es ein solches Array mehrdimensional darzustellen. Möchte man etwa ein Schachbrett in einem Array abbilden, könnte man ein zweidimensionales Array erstellen. Die Verwendung ist dabei gleich der eines eindimensionalen, allerdings mit einer weiteren Indexangabe.
Ein char-Array für unser Schachbrett könnte also z.B. als char schachbrett[8][8]; abgebildet werden.
Leicht lässt sich dies als ARRAYNAME[ZEILEN][SPALTEN] veranschaulichen. Arrays können aber durchaus mehrere Dimensionen besitzen, allerdings muss man bedenken, dass der benötigte Speicher exponentiell wächst. So benötigt z.B. ein char arr [100][365][24][60][60]; bereits über 3 Gigabyte Arbeitsspeicher.

Gerne wird ein solches Array per for-Schleife bearbeitet oder ausgegeben. Hierfür wird die Zählervariable der for-Schleife direkt für den Index des Arrays verwendet.

Funktionen

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {
        static void hallo()
        {
            Console.WriteLine("Funktion 'hallo' aufgerufen");
        }

        static int add()
        {
            int a;
            int b;

            Console.WriteLine("Eingabe a:");
            a = Convert.ToInt32(Console.ReadLine());

            Console.WriteLine("Eingabe b:");
            b = Convert.ToInt32(Console.ReadLine());

            return a + b;
        }
        
        static void Main(string[] args)
        {
            int ergebnis;

            Console.WriteLine("Erster Funktionsaufruf");
            hallo();

            ergebnis = add();
            Console.WriteLine("Ergebnis = {0}", ergebnis);
        } 
    }
}

Funktionen eignen sich hervorragend um häufig verwendete Codeabschnitte in einer eigenen Funktion (oder Methode) zu implementieren anstatt die gleichen Zeilen immer wieder zu schreiben. Somit sinkt der Schreib- und Wartungsaufwand.
Die erste Funktion kennen wir bereits. Nämlich die main-Funktion. Funktionen werden nach folgendem Schema deklariert: [Rückgabetyp] [Funktionsname] () {Anweisungen}. Optional kann auch ein [Zugriffsmodifier] wie z.B. public oder const vorangestellt werden. Der Rückgabetyp definiert den Typ der durch das return-Statement an die aufrufende Funktion zurückgegeben wird. Sobald das return Statement erreicht wird endet die Funktion, egal was danach noch kommen mag.
Die Rückgabetypen von Funktionen sind die gleichen wie sie für Variablen verwendet werden.
Einzig der Typ void hat keinen Rückgabetyp und auch kein return-Statement. So muss ein eine Funktion int getNumber() einen integer als return-Wert haben.

Parameterübergabe

  • Code
  • Erklärung
  • Ergebnis

using System;

namespace CsharpExample
{
    class Program
    {

        static void div(ref int num)
        {
            num = 60;
        }

        static int add(int z1, int z2)
        {
            return z1 + z2;
        }

        static void Main(string[] args)
        {
            int ergebnis;
            int zahl = 100;

            Console.WriteLine("Eingabe a und b:");
            int a = Convert.ToInt32(Console.ReadLine());
            int b = Convert.ToInt32(Console.ReadLine());

            ergebnis = add(a, b);

            Console.WriteLine("Zahl vor Funktionsaufruf = {0}", zahl);
            div(ref zahl);
            Console.WriteLine("Zahl nach Funktionsaufruf = {0}", zahl);
        }
    }
}

Damit Funktionen mit Variablen aus anderen Funktionen (z.B. aus main() ) arbeiten können, müssen diese übergeben werden. Die Anzahl, der Typ der Parameter und die Reihenfolge muss bei der Funktion definiert werden. Diese Reihenfolge muss bei dem Aufruf strikt eingehalten werden. Wahlweise können die Werte als Wert (Call By Value) oder als Referenz (Call By Reference) übergeben werden. Wird der Parameter als Wert übergeben, arbeitet die Funktion mit einer Kopie dieser Variable, bei einer Referenz (erkennbar an dem vorangestellten ref) wird der Wert der ursprünglichen Variable verwendet und ggf. verändert. Es wird keine Kopie erstellt.
Obwohl der Funktionsname nur einmal im aktuellen Namespace verwendet werden darf, kann er mehrfach genutzt werden, wenn er sich zumindest in der Parameterliste unterscheidet. Dieser Vorgang wird überladung genannt.

Somit können die Funktionen int calculate(int a, int b) und int calculate(int a, int b, int c) im gleichen Namespace trotz gleichen Namens existieren. Bei dem Aufruf dieser Funktion erkennt der Compiler automatisch welche der beiden Funktionen gemeint ist, je nach dem ob 2 oder 3 Parameter übergibst.

Wichtig zu wissen ist, dass Variablen die keine Referenzen sind nur innerhalb dieser Funktion gültig sind. Außerhalb der Funktion sind Variablen anderen Funktionen unbekannt.
Wie du in unserem Beispiel sehen kannst, können wir entweder 2 Parameter übergeben ohne, dass die Funktion diese ändert, oder aber wir lassen die Funktion unsere Variable bewusst ändern in dem wir sie als Referenz übergeben.