Grundkurs C Teil 2

http://www.sirius-net.de

Inhaltsverzeichnis Programmiersprachen *

a) Compiler *

b) Interpreter *

c) "Zwischendinger" *

Geschichtliche Entwicklung *

EDV *

PAP *

Programm *

Ein Hauptprogramm *
Technischer Ablauf bei der Erstellung von C/C++ Programmen *

Programme im Hauptspeicher *

Zahlensysteme, Bits & Bytes *

Zahlensystem zur Basis b: Ziffern 0 ..... b-1 *

Zeichensätze *

Aufbau der ASCII-Tabelle: *

Bildung negativer Zahlen: *
C und Standards *

Bezeichner (gültig für C/C++) *

Konstanten im Quelltext *

Wichtige Steuerzeichen *

Grunddatentypen und Variablen *

Grunddatentypen sind in C numerische Typen *

Datentypen *

Grunddatentypen und Variablen *

Einige Deklarationen: *

Aufbau einfacher C-Programme *

Kommentare *
Ein- / Ausgabe mit den Kanälen stdin und stdout *

Übersicht: *

printf () *

Strings (Zeichenketten) *

gets( ) und puts( ) *

Konvertierung von Strings geeigneten Inhalts in nummerische Typen *

A) Prinzip *

B) Die Funktionen *

Arbeitsweise dieser Funktionen *
Zeichenweise Eingabe *

Operatoren und Ausdrücke *

Kombinierte Zuweisungsoperatoren *

Welche *.h Dateien wann benutzen ? *
Operatoren und Ausdrücke *

Eigenschaften von Operatoren *

1. Typ (Stelligkeit) *

2. Priorität (Reihenfolge) *

3. Assoziativität oder Bindungsrichtung *

4. Datentypen, die verarbeitet werden und gegebenenfalls Typ des Ergebnisses *

Addition/Subtraktion/Multiplikation *

Division *

Modulo-Operator *

Übungsaufgaben: (allgemeines) *

Winkelfunktionen *

Bedingungen (Bool´sche Ausdrücke) *

Operatoren zur Formulierung von Bedingungen *

if- und if/else – Konstruktionen *

Entscheidungen: Die switch/case Kaskade *

Konditionaloperator *

Entscheidungskonstruktionen on C/C++ geordnet nach allgemeiner Verwendbarkeit: *

Schleifen (Wiederholung von Anweisungen) *

Typen von Schleifen: *

2. for – Schleife *

do ... while – Schleife *

Ergänzende Befehle zur Programmablaufsteuerung *


 

Programmiersprachen



Einsatz: Werkzeug zur Erzeugung neuer Programme


Prinzip: Textdatei (Quelltext) Regeln der Programmiersprache beachten


Programmiersprache * Programm

Implementiert als

a) Compiler

Programm übersetzt (Quell-)Text in Maschinensprache. D.h. es entsteht eine lauffähige Datei (*.exe) Kann auf dem entsprechenden Betriebssystem direkt von der CPU ausgeführt werden.

Typische Beispiele: C/C++; PASCAL, FORTRAN;

C++ ist eine Erweiterung von C; Erweiterung um Objektorientierung

Assembler: Aus einem Befehl wird ein Maschinenbefehl. (1:1 – Compiler) Maschinenabhängig!

Bei höheren Sprachen wird aus einem Befehl mehrere Maschinenbefehle (1:N – Übersetzung) Quelltexte können portabel sein

b) Interpreter

Es wird eine Laufzeitumgebung benötigt, der Interpreter, der den Quelltext zeilenweise liest und jede Zeile und jede Zeile vor ihrer Ausführung übersetzt. Die Ausführung ist also sehr viel zeitaufwendiger.

Typische Vertreter sind viele Basic-Implementierungen; Perl; Shell-Scripte (« Batch-Dateien)

c) "Zwischendinger"

Der "Compiler" erzeugt sogenannten Byte-Code, der komprimierter als der Quelltext ist, aber kein Maschinencode, sondern unabhängig von der CPU.

Um die Programme laufen zu lassen wird trotzdem eine Software gebraucht, die in der Lage ist das Ding abzuarbeiten (Java-Interpreter, meist schon im Web-Browser integriert), aber der Code ist komprimierter. Also eine Kompromis-Lösung zwischen a) und b) Programme sind schneller als Quelltext mit Interpreter, aber langsamer (um ca. Faktor 10) als compilierte Programme. Rechenintensive Programme sind hierfür also nicht geeignet.

Java ist von der Syntax her mit C/C++ eng verwandt.


Geschichtliche Entwicklung



Maschine mit CPU Problem
 
 
 
 
 
 
 
 
 
 
 
 
 
 

EDV
Programm
 
 
 
 
 
 

Algorithmus: Verarbeitungsvorschrift, die so genau formuliert ist, daß sie von einer Maschine abgearbeitet werden kann.

Algoritmus läßt sich darstellen aus
 
 


 
 
 
 

PAP

Anweisungsfolge




 
 



 
 
 
 
 
 

Anweisungsfolge
 
 
 
 
 
 
 
 

Programm



 
 

(Mehrere) Unterprogramme
Ein Hauptprogramm
In sich geschlossener Programmabschnitt, der eine genau definierte Aufgabe erfüllt (z.B.: berechne Quadratwurzel) und über seinen Namen (z.B.: sqrt () ) aufgerufen werden kann.

Problem ist zu entscheiden, wieviel in so ein Unterprogramm rein soll. Was soll es tun, und was nicht.

Nicht zu unübersichtlich werden lassen!

Programmabschnitt, mit dem die Programmausführung zur Laufzeit beginnt.

D.h. der Anfang des Hauptprogramms ist der Progammeinsprungspunkt (Entry Point)

In C/C++ heißt das Hauptprogramm

main ()

Mit dem C/C++ Compiler wird eine Sammlung bereits übersetzter Unterprogramme für häufig vorkommende Aufgaben mitgeliefert, die Standardbibliothek.
Hinweis: Unterprogramm heißen in C Funktionen

 
Technischer Ablauf bei der Erstellung von C/C++ Programmen


  1. Quelltext erstellen im Editor. (ASCII-Textdatei) Ganz normale Textdatei ohne Steuerzeichen. Dateiname con C nach der Norm *.c; die von C++ mit der Endung *.cpp
  2. Der Preprozessor (Software)

  3. Nimmt in C/C++ Textersatz am Quelltext vor. Insbesondere kann mit #include der Inhalt anderer Textdateien in den Quelltext aufgenommen werden.

  4. Der Compiler analysiert den Quelltext (Parsing). Ist der Quelltext formal richtig. Wenn nicht, gibt der Compiler eine Fehlermeldung (Errors/Warnings) aus. "Error" geht nicht weiter. "Warnings" ist eine Unsauberkeit im Quelltext, die nicht zum Stop des Compilers führt. Sollte aber auch beseitigt werden. Die Fehlermitteilungen sind in Englisch.

  5. Wenn keine Fehlermeldungen kommen, erzeugt der Compiler Maschinencode. Der Teil des Compilers, der dafür zuständig ist heißt Code generator.
    Die Datei, die neu entsteht hat die Endung *.obj (Object-Datei) und ist schon im Maschinencode.
  6. Der Linker (Binder) kombiniert die *.obj Datei mit Teilen aus der Standard-Bibliothek (s.o.) und erzeugt ein ausführbares Format (*.exe)
  7. Programm (*.exe) aufrufen und testen. Sind Logik-Fehler enthalten?
Programme im Hauptspeicher
Ausgangszustand: *.exe Datei auf der Festplatte.

Das Programm wird aufgerufen. Der Loader des Betriebsystems lädt ein Abbild (Kopie) der *.exe Datei in den Hauptspeicher, und setzt diese Programmausführung am Entry Point (s.o.) des Programms auf. Die im Hauptspeicher liegende "Kopie" des Programms heißt Prozeß (UNIX) oder Task (Windows)
 
Daten-Abschnitt

(Datensegment)

Variablen

Code-Segment

(Verarbeitung, Algorithmus)

Stack

 
 
 

Zahlensysteme, Bits & Bytes
3 4 5 0
3 2 1 0

Zahl zur Basis 10:

3 4 5 0 3 2 1 0

3 * 103 + 4 * 102 + 5 * 102 + 0 * 100

3 + 1000 + 4 + 100 + 5 * 10 + 0 * 1
 
 

Zahlensystem zur Basis b: Ziffern 0 ..... b-1

10 Dezimal 0 ...... 9

2 Binär 0, 1

23 8 Oktal 0 ...... 7

24 16 hexadezimal 0 ....... F

Binär: In diesem Zahlensystem arbeitet der Rechner intern, d.h. die Daten liegen im 2er System als Bitmuster vor (Folge von Nullen und Einsen)

Dezimal: Wird zur Kommunikation mit dem Anwender benutzt.
 
 

Kleinste Informationseinheit

1 Bit,

Zahl der darstellbaren Werte: 2 ( 0 bzw. 1 )
 
 


Faßt man mehrere Bits zu einer größeren Informationseinheit zusammen, so können mehr unterschiedliche Informationen dargestellt werden.
Üblich : 8 Bit 1 Byte

1 Byte:
 
7 6 5 4 3 2 1 0
0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1
0 1 0 0 0 0 0 1
27 26 25 24 23 22 21 20
128 64 32 16 8 4 2 1

 

Jedes Bit im Byte kann den Wert 0 oder den Wert 1 annehmen. Das heißt ein Byte kann 28 verschiedene Zustände annehmen = 256 (dezimal)

Kleinste Speichermenge, die im PC angesprochen werden kann ist 1 Byte

In C entspricht dem Byte der Datentyp unsigned char (s.u.)

0 1 0 1 0 1 0 1 85
1     2     5   125 okt
                 
                 

 
 
  Bei Oktalzahlensystem wird aus je 3 Bit eine Oktalziffer
0 0 0 Kleinste Einheit 0
1 1 1 Größte Einheit 7
       

 
  1. « 24, aus je 4 Bit entsteht eine Hex-Ziffer
0 0 0 0 0 dezimal
1 1 1 1 15 dezimal F (hex)
         
0 1 0 1 0 1 0 1 Binär
5
5
Hex

 

Egal wie die Eingabe erfolgt, als 65 (dezimal), 41 (hex) oder 101 (oktal) führt intern immer zum gleichen Bitmuster:

01000001 (binär) In der ASCII-Tabelle ist der Zahl das Zeichen »A« zugeordnet.
Zeichensätze
Zeichensatztabellen (z.B. ASCII-Tabelle) sind die normierte aber letzten Endes willkürliche Zuordnung der 256 verschiedenen Zustände eines Bytes zu irgendeiner Bedeutung/ Interpretation

Aufbau der ASCII-Tabelle:

0 ... 31 (dezimal): Steuerzeichen

Bsp.: 08 (dez) Backspace

09 (dez) TAB

13 (dez) RETURN

12 (dez) Form Feed (Drucker: Neue Seite)
 
 

48 ... 57 (dezimal): Ziffern 0 ... 9

30 ... 39 (hexadezimal)
 
 

65 ... 122 (dezimal) Buchstaben (engl. Alphabet) A ... Z a ... z
 
A 0 1 0 0 0 0 0 1 65 dez
a 0 1 1 0 0 0 0 1 97 dez
  7 6 5 4 3 2 1 0 Bit-Position

Kleine und große Buchstaben unterscheiden sich nur an der 5. Bit-Position. Bei großen Buchstaben ist das 5. Bit gelöscht, bei kleinen Buchstaben ist es gesetzt. Rein rechnerisch beträgt der Unterschied immer 25 = 25 dez = 20 hex. Gilt nur für die Buchstaben des englischen Alphabets, also ohne Sonderzeichen und Umlaute.

Die Aussage »A« ist kleiner als »a« ergibt sich aus den zugeordneten Werten aus der ASCII-Tabelle ( 65 dez = A < 97 dez. = a )

Verläßlich bei der ASCII-Tabelle sind nur die Dezimal-Werte von 0 bis 127

Zeichen ohne Bild

32 (dezimal) blank (Leertaste)

20 (hex)

1 1 1 1 1 1 1 1
0 0 0 0 0 0 0 0

 

Anders die Ziffer »0«, die den Wert 48 (hex) bzw. 30 (hex) hat

0 0 1 1 0 0 0 0 Binärzahl
7 6 5 4 3 2 1 0 Bitfolge
32 d 16 d 1 0 Wert

 

Ganze Zahlen mit und ohne Vorzeichen

a 0 0 0 0 0 0 0 0
b 1 1 1 1 1 1 1 1

 

Frage: Ist a größer als b ? Nein, wenn MSB kein Vorzeichen ist sondern eine gültige Stelle, dann 0 < 255

Das Bit, das am weitesten links steht (mit der höchsten Nummer) nennt sich
MSB (most significant bit).
Dieses Bit kann als Vorzeichen interpretiert werden. Für diesen Fall ist die
Zahl negativ, wenn MSB = 1
 
 

Bildung negativer Zahlen:

"Zweierkomplement-Arithmetik":

Ausgangszustand: 11111111

kippen 00000000

+1 00000001

a 0 0 0 0 0 0 0 0
b 1 1 1 1 1 1 1 1

A ist in dem Fall größer wie b, denn MSB ist Vorzeichen und somit 0 > -1



In C/C++ wird das unterschieden durch die Datentypen

Unsigned char = MSB ist kein Vorzeichen Wertebereich: 0 ... 255

Signed char = MSB ist Vorzeichen Wertebereich: -128 ... +127


C und Standards
K & R C, wie es erfunden wurde, beschrieben in Kernighen/Ritchie ""The C Programming Language", 1. Auflage (dt. Übersetzung: "Programmieren in C") Ab 1970/71
ANSI-C ANSI—Kommitte verabschiedet Standard zu C 

(ANSI ist das amerikan. Gegenstück zu DIN)

1989
ANSI C++ Ab 1989 entwickelte Bjarne Stronstrup C zu C++ weiter

"Die C++ Programmiersprache" bei Edison-Wesley

1998

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Bezeichner (gültig für C/C++)
« Namen im Quelltext für Variablen und Unterprogramm (Funktionen)
Konstanten im Quelltext
Einzelne Zeichen
'A‘
'x‘
'5‘
Eingeschlossen in einfache Hochkommata
Ganze Zahlen, Basis 10
65
372
-58
Keine besondere Kennzeichnung
Ganze Zahlen, Basis 16
0x41
0xFace
0x7E
Führendes 0x als Kennzeichnung für hexadezimal
Ganze Zahlen, Basis 8
0101
035
0715
Beginnt mit führender Null
Floating point-Konstanten, immer zur Basis 10
Trennzeichen ist Punkt
3.75
-2358.29
 
 
1.5E3
1.5e3
   
 
1e6
-1e6
   
 
1e-6
-1e-6
   
Zeichenketten

« strings

"Hello World !"
Eingeschlossen in doppelte Hochkommata
"Hello World ! \n Zeile 2 \n"
Steuerzeichen, Ersatzdarstellung für "new line".

Steuerzeichen werden mit \ (Backslash) einleitet

Ausgabe von " geht, indem in einem String durch 
\"
     
Ausgabe von \ in einem String durch
\\
     
         
Wichtige Steuerzeichen
\n New line
\t Tabulator
\b Back Space
   

 
Grunddatentypen und Variablen
Datentyp Variable
  • Größe in Bytes 
  • Art und Weise, wie das Bit-Muster intern verwaltet wird. Z.B. 

  • Mit Vorzeichen (signed)
    Ohne Vorzeichen (unsigned) 
  • Menge der auf den Datentyp erlaubten Rechenoperationen
  • Eigenschaften eines Datentyps

  • plus 
  • Konkreter Platzbedarf im Hauptspeicher 
  • Konkreter "Ort" (Adresse) im Hauptspeicher 
  • Variablen haben einen Namen, über den sie angesprochen werden können
  •    

     

    Beispiel einer Variablen-Deklaration:
     
      Datentyp Name ;  
    ganzzahliger Typ mit Vorzeichen int i ; Deklariert eine Variable i von Typ int
        i = 375 ; weist der Variablen i die Konstante / den Wert 375 zu
             

    Hinweis: Variablen sind zunächst uninitialisiert, d.h. enthalten einen unbekannten Wert.
    Bevor irgend etwas anderes mit der Variablen gemacht wird, sollte sie einen definierten Wert bekommen; z.B. durch Zuweisung. D.h. der Wert in der Variable bleibt erhalten, bis auf die Variable erneut zugegriffen, bzw. diese neu eingelesen wird.
     
     
    Grunddatentypen sind in C numerische Typen
    Ganzzahltypen   floating point Typen
    Mit Vorzeichen Ohne Vorzeichen   Mit Nachkommastellen
    signed Unsigned   Immer mit Vorzeichen
    signed char unsigned char   float
    Int     double
          long double
    Signed char Unsigned Char      
    Int « signed int Unsigned int     Float
    Long int Unsigned long int     Double
            Long double
             
    Datentypen
    Typ Länge Bereich

    unsigned char 8 Bits0 bis 255

    char 8 Bits -128 bis 127

    enum 16 Bits -32768 bis 32767

    unsigned int 16 Bits 0 bis 65535

    short int 16 Bits -32,768 bis 32767

    int 16 Bits -32,768 bis 32767

    unsigned long 32 Bits 0 bis 4294967295

    long 32 Bits -2147483648 bis 2147483647

    float 32 Bits 3.4 * 10-38 bis 3.4 * 10+38

    double 64 Bits 1.7 * 10-308 bis 1.7 * 10+308

    long double 80 Bits 3.4 * 10-4932 bis 1.1 * 10+4932
     
     
     
     

    Grunddatentypen und Variablen

    Einige Deklarationen:

    int i, ,j, k ;

    long x;

    double hoehe, breite, y ;

    int l ; float f ;
     
     
     
     
     
     

    Aufbau einfacher C-Programme
    Kommentare
    #include <stdio.h> Das Programm soll die Text-Datei stdio.h hier in den Quelltext aufnehmen
    Void main ( ) Das Hauptprogramm
    { Programmblock, der zu main ( ) gehört. Was hier zwischen bis zur geschlossenen geschweiften Klammer steht, ist alles Inhalt der Funktion main ()

     

    Variablen-Deklaration
    Muß vollständig vor dem Anweisungsteil stehen!
    Anweisungsteil / Alogorithmus
    }  

     
     
     
    Ein- / Ausgabe mit den Kanälen stdin und stdout
    stdin stdout
    Standardeingabe Standardausgabe
    Tastatur Bildschirm

    Alles, was mit Ein- /Ausgabe zu tun hat wird in C prinzipiell über (Standard-)Funktion erledigt. Kommt also aus einer Bibliothek.

    Übersicht:
     
    Art der gelesenen / geschriebenen Daten lesende Funktion schreibende Funktion
    Alle Grunddatentypen und strings scanf () printf ()
    ptrings gets () puts ()
    Ein Zeichen getchar () putchar ()
     
    Standard: ANSI

    #include <stdio.h>


     

    printf ()
     
    printf () "print formatted to stdout"  
    printf ("\033[2J") ;   String in doppelten Hochkommas
    \033

    \0x1B

    27

    ESC Kann in einem string jedes beliebige ASCII-Zeichen darstellen
    [2J
    Löscht den Bildschirm Anweisung wird von geladenem ANSI-Treiber ausgeführt
    i = ‚A‘    
    printf("%c %d(dez) %X (hex) %o (okt) \n " i,i,i,i) ;   Das 1. Argument von printf () ist immer eine Zeichenkette.

    Diese kann enthalten:
    a) beliebiger Text, der ausgegeben wird
    b) Steuerzeichen, die mit \ eingeleitet werden. Z.B.
    \n New Line – neue Zeile
    c) Formatbeschreiber, die mit % beginnen.
    Zu jedem Formatbeschreiber in der Zeichenkette sollte (!) ein zusätzliches Argument korrespondieren das vom Datentyp her zum Formatbeschreiber passt.
    (Selber aufpassen, weil der Compiler im anderen Fall keine Fehlermeldung ausgibt, aber auf dem Bildschirm nur Schroot ankommt!) 

    printf("Inhalt der Variable l : %ld\n",!) ; %ld Ausgabe Datentyp long im Format dezimal
    d = 4.0 * atan (1.0) ; atan Arcus Tangenz
    das Ergebnis der Rechnung rechts vom Gleichheitszeichen ist nachher der Wert von d
    printf("Inhalt der Variable d : %lf \n", d) ;   Berechnet Ë auf Rechnergenauigkeit
    printf("So geht es auch: %lf\n", 4.0*atan(1.0)) ;   Berechnet den Wert direkt. Ohne Umweg über eine Variable
      y=sqrt(x); Berechnet Quadratwurzel von x und stellt es in die Variable Y

    Fast alle mathematischen Funktionen haben den Datentyp double

    Die Variablen x und y sollten daher im Vorfeld ebenfalls als Datentyp double deklariert worden sein.

    %7.3lf % Leitet Formatbeschreiber ein
      if Zu double passender Formatbeschreiber
      7.3 7 = Gesamtbreite der Ausgabe (Vorschlagscharakter; wenn mehr Platz benötigt, holt ihn sich das Programm), davon sind
    3 = Anzahl der Nachkommastellen (verbindlich)
    Die Kommastelle zählt mit !
    Für die Bildschirmausgabe wird die letzte Nachkommastelle von printf () kaufmännisch gerundet. Intern bleibt der Gesamtwert erhalten.
    printf ("%s\n" , "Weiterhin viel Spaß mit C ! \n") ;    
    }    
    Um die folgenden Zeichen am Bildschirm auszugeben ist an Syntax nötig: % %%
      \ \\
      " \"

     
     
     
     

    scanf()

    read formatted from stdin
    int i ;  
    printf("ganze Zahl eingeben - > ") ;  
    scanf("%d", &i) ; /* & = Adressoperator; Wirkung: ermittle Adresse der Variablen i */
      /* scanf() liest auf Adressen ein ! */
      /* Die Adresse einer einfachen Variablen wird in C mit dem Adressoperator & ermittelt.

    Ausnahme: Arrays (s.u.)

    &i
    /* Adresse von i */
    I
    /* "Nicht-Adresse" – Wert bzw. Inhalt von Speicherplatz i */
    %d
    /* Auch das erste Argument von scanf() ist eine Zeichenkette. In dem Fall steht der Formatbeschrieber pasend zum einzulesenden Datentyp: ganzzahlig dezimal. */
    %d
    /* Achtung: hier nur den Formatbeschreiber eintragen !. Falls in dieser Zeichenkette Text und/oder ein Steuerzeichen steht, würde scanf() genau auf deren Eingabe warten. */
      /* Ab dem ersten Zeichen, das nicht zum Formatbeschreiber passt, läßt scanf() den Rest der Eingabe im Eingabepuffer stehen. Daher sollte scanf() wenn mit der Tastatur gearbeitet wird mit dem Befehl fflush(stdin); kombiniert werden. */
    fflush(stdin) ; /* Bereinigt den Eingabepuffer */
       
    scanf("%s" , .. ) ; liest den string nur bis zum ersten blank, TAB oder CR
       

     
     
     

    Strings (Zeichenketten)
    Für strings gibt es in C keinen Grunddatentyp.

    String ist eine Folge von ASCII-Codes, die hintereinander im Speicher stehen.
    1 ASCII-Code passt in eine char-Variable. Gelingt es mehrere solche char-Variablen sauber hintereinander im Speicher anzulegen, ensteht eine "Variable für einen String".

    Konstruktionen, die aus mehreren Variablen gleichen Typs bestehen, heißen Array und werden von C unterstützt.
     
      "Hallo" String-Konstante
    Beispiel einer Array-Deklaration:    
    char f[81] ;   Array, bestehend aus 81 Elementen vom Typ char
    80 Zeichen plus Abschluß 0
      [ ] Ankündigung Array
      81 Größe des Arrays
      f Name des Array
         
    'H' 'a' 'l' 'l' 'o'         . . .

     

    Namen von Arrays verhalten sich anders als Namen von einfachen Variablen. Array ist selbst eine Adresse

    Arraynamen sind in C Adressen.

    Arrayname « der Adresse des ersten Arrayelements

    Wenn ich mit scanf( ) und %s einen string einlesen will, hat das die Besonderheit, daß er nur bis zum ersten Blank, TAB oder CR einliest. Der Rest fällt unter den Tisch.


    Das String-Format von C ASCII-Z Format


    Ausgelesen wird bis zur Abschluß-Null 00 (hex)

    Achtung: Der vordefinierte Adressraum für das Array solte nicht zu klein ausgelegt sein.
    scanf( ) überprüft nur die Einsprungsadresse und schreibt die Eingaben bis zur Abschluß-Null. Wenn der Anwender über den vordefinierten Bereich hinausschreibt, wird der Inhalt nachfolgender Speicheradressen überschrieben / zerstört.
     
    char f[81]
    f 3050 'H' 'a' 'l' 'l' 'o' 0 (dez)          
    Adresse
    3050     Adresse ist nur fiktiv
     
    ASCII 'B' 'o' 'n' 'd' '-' '0' '0' '7'      
    Hex 42 6F 6E 64 2D 30 30 37 00      

    gets( ) und puts( )

    String von stdin einlesen, bzw. nach stdout schreiben.
     
    char f[81] ;    
    printf("Bitte Zahlenkette eingeben: ") ;    
    gets(f) ; /* Arrayname ist die Adresse, ab der gets( ) den string im Hauptspeicher ablegen kann. */ Auch hier gilt: Lieber etwas größer wegen dem Überlauf der Eingabe. Siehe oben.
      /* übernimmt Zeichen von stdin, bis [Return] kommt. Diese Zeichen werden an der Adressen (hier: f) hintereinander im Hauptspeicher abgelegt. */  
      /* An Stelle von [Return] (13 d) wird die Strin-Ende-Null (0 d) im Array abgelegt. */  
         
    puts(f) ; /* Gibt an dem ihm übergebenen Adresse (hier: f) sol lange Zeichen nach stout aus, bis die Strng-Ende-Null gefunden wird.Statt der String-Ende-Null wird ein »\n« (new line) ausgegeben  
    printf("%s\n" , f) ;    
         
    31
    32
    33
    00
    '1'
    '2'
    '3'

     
     
     

    Konvertierung von Strings geeigneten Inhalts in nummerische Typen
    Das Problem taucht ständig auf: Eingabe im ASCII-Zeichenformat, Verarbeitung muß im nummerischen Format passieren und wieder zurück zur Ausgabe auf Bildschirm oder Drucker im ASCII.Format

    A) Prinzip

    Anwendereingabe: A B C [return] Tastatureingabe
    intern. Format: 31 32 33 00 hex
    –0x30 1 2 3 hex
    *102 *101 *100
    Zwischenergebnis 100 + 20 + 3

    Ergebnis: 123 (dez) binär kodiert in einer nummerischen variablen z.B. vom Typ int.

    B) Die Funktionen

    ascii to
     
    Rückgabetyp Name der Funktion  

    int

    atoi ( ) ascii to integer Adresse, ab der der String steht, meist ein Arrayname.

    long

    atol ( ) ascii to long

    double

    atof ( ) ascii to double

     

    Beispiel:

    char f[81]; int i ;

    printf("Zahl eingeben -> ") ;

    gets(f) ;

    i = atoi(f) ;

    Arbeitsweise dieser Funktionen

    führende Blanks und Tabs werden überlesen

    Vorzeichen -sofern vorhanden- werden berücksichtigt. Kein Vorzeichen wird als positiver Wert interpretiert.

    Ab jetzt werden nur noch konvertierbare Zeichen verarbeitet. Dies sind:
    Ziffern (alle 3 Funktionen atoi ( ); atol ( ); atof ( ))
    Bei atof ( ) zusätzlich noch: Dezimalpunkt; E und e für die Exponentialschreibweise; ein zweites Vorzeichen für den Exponenten. (z.B. 27.89; 1.8E4; -2.6E-3; 2.9e7)

    Die Verarbeitung endet, wenn
    a) die String-Ende-Null erreicht ist oder
    b) das erste nicht konvertierbare Zeichen auftritt.

    Ist bereits das erste Zeichen nicht konvertierbar, geben die Funktionen Null (0 bzw. 0.0) zurück.
     
     

    Zeichenweise Ein-/Ausgabe
     
    putchar( )
     
     

    %c

    %X

    %d

    %o
     
     
     
     

     

       
    getchar( ) int i;
    printf("1Zeichen eingeben ->") ;
    i = getchar( ) ;
    fflush(stdin) ;
    /* Hinweis: getchar( ) liest 1 Zeichen ein, wartet auf [Return]. Da dies nicht eingelesen wird von getchar( ) bleibt es im Tastaturpuffer. Damit es dort wieder rauskommt, muß mit fflush(stdin) der Puffer wieder geleert werden. */
         
         

    An Ein- / Ausgabefunktionen gibt es 6 Stück
     
     

    Zeichenweise Eingabe
     


    Achtung: kein Standard ! #include <conio.h> console i/o

    getch( ) ; int i ;
    i = getch( ) ;
    getch( ) zeigt nichts am Bildschirm an. Das eingelesene Zeichen wird nur Programmintern in die Variable gestellt.
    So kann ein Programmablauf angehalten werden bis ein Tatstendruck erfolgt.
    getche( ) ; int i ;

    i = getche( ) ;

    getche( ) zeigt eingelesenes Zeichen am Bildschirm
        Beide lesen 1 Zeichen ein, warten nicht auf [Return].
    Kein fflush(stdin) nötig !

    Rückgabewerte von Funktionen muß man in C nicht zuweisen. Nur bei Bedarf !

    Hinweis: Ursache der Meldung "Call to function xxx with no prototype": Es fehlt eine #include-Datei

    Abhilfe: Online-Hilfe – mit Cursor auf Name der Funktion und [Ctrl+F1] drücken, dann gibts Beschriebung zum jeweiligen Befehl, auch welche #include-Datei gebraucht wird.


    Operatoren und Ausdrücke
    c = a + b ;  
    int   int   double   Datentyp
    int     double     Zwischenergebnis
                 
    links vom Komma: Regeln der impliziten Typkonvertierung. Der höherwertige / anspruchsvollere Typ wird dem anderen automatisch zugewiesen.

    rechts vom Komma: Bei der Zuweisung wird gegebenenfalls in den Typ der Variable konvertiert, auf den zugewiesen wird (hier a). In dem Beispiel oben werden also die Nachkommastellen –falls vorhanden- abgeschnitten und der Typ double auf die Größe vom Typ int abgeschnitten.
     
     

    Kombinierte Zuweisungsoperatoren (bezieht sich auf die Grundrechenarten)
      Zuweisung                      
    a = a * b ; « a *= b     ;
    a = a / b ; « a /= b     ;
    a = a % b ; « a %= b     ;
    a = a + b ; « a += b     ;
    a = a - b ; « a -= b     ;
                             
                             

    Welche *.h Dateien wann benutzen ?
     
    Dateien laden mit #include    
    <stdio.h>   Standard Ein-/Ausgabefunktionen  
        Dateifunktionen printf( ); scanf( ); gets( ); puts( ); getchar( ); putchar( )
    <conio.h> Console I/O kein Standard  
    <math.h>   mathemat. Funktionen
    (Für die Operatoren nicht nötig)
    sqrt( ); powl( ); atan( ); sin( ); cos( ); usw.
    <stdlib.h>   Konvertierungen atoi( ); atol( ); atof( );
        Zufallszahlengenerator  
        Sortieren  
        dynam. Speicherverwaltung  

    Operatoren und Ausdrücke
    Beispiel:
     
    x
    =
    5
    *
    y
    +
    3
    ;
    Operand
    Operator
    Operand
    Operator
    Operand
    Operator
    Operand
     

     

    Eigenschaften von Operatoren

    1. Typ (Stelligkeit)

    Beschreibt die Anzahl der zugehörigen Operanden
    1 Operand (unär) -5 unäres Minus (Vorzeichen)
    &i Adressoperator
    2 Operanden (binär) x + 5 Addition, Subtraktion, Division, Multiplikation, ..
    y = 7 ; Zuweisung
    3 Operanden (ternär) später
    2. Priorität (Reihenfolge) Jeder Operator hat innerhalb der Menge der Operatoren eine bestimmte Priorität, die darüber entscheidet, in welcher Reihenfolge Ausdrücke ausgewertet werden, die Operatoren unterschiedlicher Priorität enthalten.
    Beispiel: x = 3 * y + 5
    x = 3 * y + 5  
      14   3   4   Priorität
       
    1.
         
         
    2.
     
    3.
       
    Die voreingestellte Priorität der Operatoren kann mit Hilfe von Prioritätsklammern durchbrochen werden:
    x = 3 * ( y + 5 )  
      14   3   4   Priorität
           
    1.
     
       
    2.
       
    3.
         

      x = 3 + sqrt(5.9) * (y + 7) ;

    /*Die erste Klammer ist ein Funktionsaufruf und wird nicht in der Priorität nach der zweiten Klammer berücksichtigt.
     
     

    3. Assoziativität oder Bindungsrichtung Legt die Reihenfolge der Auswertung fest, wenn in einem Ausdruck mehrere Operatoren gleicher Priorität vorkommen. Beispiel:





    x = 3 + x - 5 + b ;
    14 4 4 4 Priorität

    links nach rechts

    a = b = c = d = 0 ;
    rechts nach links

    falsch ist: 7 = x ;

    richtig: x = 7 ;

    Auf eine Konstante kann nicht zugewiesen werden ! Fehlermeldung wäre in dem Fall: "LVALUE required" ("Linkswert" Ausdruck, der links von einer Zuweisung stehen kann « veränderbarer Speicherplatz)

    4. Datentypen, die verarbeitet werden und gegebenenfalls Typ des Ergebnisses Am Beispiel der Operatoren für die Grundrechenarten
    Priorität Operatoren  
    3 * / %  
    4 + -  

    Addition/Subtraktion/Multiplikation


     
     

    Division

    Regeln wie oben, jedoch zusätzlich:
    Division durch Null ist nicht definiert
    Modulo-Operator

    Übungsaufgaben: (allgemeines)

    Aufgaben: x
     
     
     
     


    W (Wurfweite) y

    w = V2 * sin(2*Ñ ) /g

    g.w = V2 * sin(2 * Ñ )

    V = Wurzel aus g * w /sin(2 * Ñ )

    Eingabe: Weite (Meter) und Winkel

    V = m/s
     
     
     
     
     
     

    Winkelfunktionen

    Beispiel: y = sin(x) ; y – sin des Winkels // x – Winkel

    Diese Funktionen übernehmen den Winkel nicht in der Einheit ° (Grad) sondern radiat (rad).
    Umrechnung: rad = grad * PI / 180
    grad = rad * 180 / PI


    Bedingungen (Bool´sche Ausdrücke)
    Ausdruck, der nach seiner Auswertung einen Wahrheitswert (Bool´scher Wert) liefert.

    Wahrheitswert: TRUE, FALSE
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     

    In C gibt es für Wahrheitswert keinen eigenen Dateityp. Stattdessen wird int verwendet.
     
    nummerischer Wert in int Wahrheitswert  
    0 False  
    alles anderen Werte True  
    0 1  

    Beispiel: if( x > 5 ) ...... ;
     
     

    Wird Programmintern ein TRUE generiert, so wird hierfür die 1 genommen.
     
     

    Operatoren zur Formulierung von Bedingungen

    1. Vergleichsoperatoren (relationale Operatoren)

    2. binäre Operatoren > größer; >= größer gleich Priorität 6
      < kleiner; <= kleiner gleich

      == gleich; priorität 7
      != ungleich

    3. Logische Operatoren (bool´sche Operatoren)

    4. unärer Operator ! logisch NOT Priorität 2

      binäre Operatoren && logisches AND Priorität 11
      | | logisches OR Priorität 12
       
       
       
       

      Hinweis: ein logisch-exclusiverer XOR-Operator ist in C nicht implementiert !

    Beispiele:

    .....

    Datentyp für Wahrheitswerte in C : int

    als Bedingung kann in C jeder Ausdruck verwendet werden, der einen int liefert.

    if ( x ) .... ; « if( x != 0 ) ... ;

    if ( ! x) ... ; « if( x == 0 ) ... ;

    Achtung: Fehlerquelle !

    if ( x = 5 ) .... ; richtig: if ( x = = 5 ) .... ;
     
     

    Beispiele:
     
     
     
     
     
     
     
     

    if ( x >= 'A' && x <= 'Z') ..... ; /* liefert für alle Großbuchstaben TRUE */

    if ( ! ( x < 'A' || x > 'Z' ) ) .... ; /* entspricht der 1. */

    if ( x < 'A' || x > 'Z') .... ; /* liefert für alle außer den Großbuchstaben TRUE */

    if ( ! ( x >= 'A' && x <= 'Z' ) ) .....; /* entspricht der 3. */

    Nach folgender Regel (de Morgan´sche Regel) wird die umgekehrte Bedingung erstellt:
    Erst ein NOT davorstellen, dann alle Operatoren in der Klammer umdrehen.

    if ( x >= 'A' && x <= 'Z' | x >= 'a' && x<= 'z' ) ... ;

    /* liefert TRUE zurück für alle Groß- und Kleinbuchstaben */
     
     

    Hinweis:

    Werte in Ganzzahltypen werden prinzipiell genau gespeichert, Werte in floating-point Typen sind mit geringen Rundungsfehlern behaftet.

    floating-point Typen nie mit = = 0der != vergleichen,
    sondern mit > >= < <=

    Für jeden floating-point Typ existiert ein Schwellenwert ò , für den gilt:
    a + ò > a

    float: ò = 1.192 * 10 -7
    double: ò = 2.220 * 10 -16
    long double: ò = 1.084 * 10 –19

    Da long double nicht standardisiert ist, ist double vorzuziehen.
     
     

    if- und if/else – Konstruktionen

    Beispiel:
     
     





     
     

    main ( )

    {

    double ug, og, h ;

    printf("Untergrenze: ") ; scanf("%lf" , &ug) ;

    fflush(stdin) ;

    printf("Obergrenze: ") ; scanf("%lf", &og) ;

    fflush(stdin) ;

    if (ug > og)


    { h = ug ; ug = og ; og = h ; } /* Dreieckstausch über Hilfsvariable h */

    printf("3. Wert: ") ; scanf("%lf", &h ) ;

    fflush(stdin) ;

    if( h >=ug && h <= og )

    printf("liegt im Bereich \n") ;

    else

    printf("liegt außerhalb des Bereichs\n") ;

    }

    --------------------------

    Oft ist auf mehrere Bedingungen zu prüfen, die sich gegenseitig ausschließen. Dafür eignet sich eine if/else-Kette.

    Die Bedingungen bei if( ) werden der Reihe nach geprüft. Es wird in den ersten Anweisungsteil verzweigt, dessen Bedingung ein TRUE ergibt. War dies der Fall, so wird die Programmausführung nach dem Durchlaufen des Anweisungsteils hinter der if/else-Kette fortgeführt.
    Ergibt keine der Bedingungen bei if( ) den Wert TRUE, kommt es draruf an, ob die if/else-Kette von einem optionalen else abgeschlossen wird. Ist das der Fall, so wird die Anweisung oder der Block, die/der zum optionalen else gehört durchlaufen. Ist das nicht der Fall, so wird keine der Anweisungen in der if/else-Kette ausgeführt.

    Beispiel:

    /* Noten.c */

    #include <stdio.h>

    /* Eingabe Punktzahl -> Ausgabe Noten */

    main ( )

    {

    int n ;

    printf("Punktezahl -> ") ; scanf("%d" , &n) ; fflush(stdin) ;

    if( n >= 88 && n <= 100) puts("Sehr gut") ;
    else
    if (n >= 76 ) puts ("gut") ;
    else
    if (n >= 63) puts( "mit Erfolg") ;
    else
    if (n >= 51) puts( "ausreichend") ;
    else
    if (n >= 0 ) puts( "nicht ausreichend") ;
    else
    puts("Falsche Eingabe") ;

    }
     
     

    Entscheidungen: Die switch/case Kaskade

    (siehe Kopie)

    reservierte Wörter: switch, case; default

    switch( z ) /* z « Selektor-Variable */

    Die Selektor-Varaible und die case-Konstante müssen vom genzzahligen Typ sein. Der Standard schreibt mindestens int vor. Bereiche von Werten weie [20 ... 50] können nicht angegeben werden, zusammmengesetzte Datentypen (z.B. Arrays, also auch Strings) sind nicht erlaubt.
     
     

    Konditionaloperator

    (ternär, Priorität 13) Ersetzt eine einfache if/else Konstruktion der Form

    if( bed.) anw.1 ;
    else anw.2 ; bed. ? anw.1 : anw.2 ;
     
     
     
     

    Beispiel:

    float f ;

    f <- Wert ;

    f >= 0 ? printf("%10.3f + \n", f)

    : printf("%10.3f - \n", -f ) ;
     
     

    Der Konditionaloperator gibt einen Wert zurück, der zugewiesen werden kann. Es ist der Wert, den die Anweisung hinterläßt, die tatsächlich ausgeführt wird.

    Beispiel:

    int x, y, max ;

    x <- Wert ; y <- Wert ;

    max = x > y ? x : y ; /* if (x > y ) max = x; else max = y ; */
     
     

    Entscheidungskonstruktionen on C/C++ geordnet nach allgemeiner Verwendbarkeit:

    1. if und if/else-Konstruktionen am flexibelsten und umfrangreichsten
    2. switch/case Kaskade nur einzelne Abfragen und Ganze Zahlen z.B. Menusteuerungen
    3. Konditionaloperator

    Die Operatoren increment ( + + ) und decrement (- - )

    Die Operatoren sind unär

    Erhöhen, bzw. erniedrigen den Inhalt des Operanden um 1.

    Beispiel:

    c++ ; « c = c + 1 ;
     
     

    Achtung: Es gibt 2 Syntax-Möglichkeiten:

    Postfix-Schreibweise C++ ; bzw. C-- ;
    Prefix-Schreibweise ++C ; bzw. - - C ;

    Der Unterschied in der Wirkungsweise kommt erst zum Tragen, wenn die increment/decrement-Anweisung in einem Zusammenhang eingebettet ist:
     
    Postfix Prefix
    "benutze Inhalt der Variable und erhöhe dann ihren Wert" "erhöhe den Wert der Variable und erhöhe in dann."

    Beispiel:

    int c ;
    c = 5 ;
    printf("%d \n ", c++) ; /* Gibt am Bildschirm 5 aus und erhöht dann den Wert von c um 1 /
    printf("%d \n ", ++c) ; /* erhöht c um 1 und gibt dann diesen Wert aus, also 7 */


    Schleifen (Wiederholung von Anweisungen)
    Allgemein gilt: In Abhängigkeit von einer Bedingung werden die Anweisungen, die zu einer Schleife gehören (nochmals) durchlaufen.
    Typen von Schleifen:
     
    Laufbedingung   Abbruchbedingung

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
       
     
     
     
     
     
     
     
     
    abweisend   nicht abweisend

       
     
     
     
     
     
     
     
     
    Jede Schleife in C kann über einen (gegebenenfalls auch mehrere) Zähler gesteuert werden. Das ist sinnvoll, wenn vor Beginn der Schleife bekannt ist, wie oft sie laufen soll. [ Grafik G1 ]

    Jede der Schleifen in C bindet eine Anweisung oder einen Anweisungsblock, der mehrere Anweisungen enthalten kann.

    Schleifenkonstruktionen dürfen geschachtelt werden, wobei die innere Schleife vollständig in der äußeren liegen muß

    Schleifen und Entscheidungskonstruktionen dürfen beliebig miteinander kombiniert werden.
     
     
     
     

    Syntax:

    while ( bed. ) anw ; /* Eine Anweisung */

    while (bed.
    {
    anw1 ; anw2 ; ) /* Mehrere Anweisungen */
    anw3 ; ....... ;
    }
     
     

    Beispiel:

    int a ;
    i = 'A' ;
    while ( i <= 'Z' )
    {
    printf("%c" , i ) ;
    i++ ;
    } /* Ende der Schleife */
    printf("\n") ;
    printf("%c" , i) ; /* Gibt das ASCII-Zeichen aus nach Z -> [ */
     
     

    i = 'A' ;
    while ( i <= 'Z' ) printf(" %c " , i++ ) ; /* Ende der Schleife */
    printf("\n") ;
     
     

    2. for – Schleife

    for ( ausdr1 ; ausdr2 ; ausdr3 ) anw. /* Eine Anweisung */

    for (ausdr1 ; ausdr2 ; ausdr3 )

    {

    anw1 ; anw2 ; ..... ; /* Mehrere Anweisungen */

    anwN ;

    }
     
     

    Beispiel:

    for ( i = 'A' ; i <= 'Z' ; i++ )
    printf(" %c " , i ) ;
    printf("\n") ;
     
     

    i = 'A' ;
    for( ; i <= 'Z' ; )
    {
    printf("%c" , i ) ;
    i++ ;
    }
    printf("\n") ;
     
     
    for( i = 'A' ; i <= 'Z' ; printf("%c" , i ++ )) ;
    printf("\n") ; for( i = 'A' ; ; i++ )
    {
    printf("%c" , i ) ;
    if( i = = 'Z' ) break ;
    }
    printf("\n") ;
     
     
     
     
     
     
     
     
    Minimal-Sytax für die for – Schleife:

    for ( ; ; ) ; /* wiederholt endlos die Leeranweisung */
     
     

    do ... while – Schleife
     
     
     
     
     
     

    i = 'A' ;
    do printf("%c" , i ++ ) ; while (i <= 'Z' ) ;
    printf("\n") ;
     
     

    oder:
     
     

    i = 'A' ;
    do
    {
    printf("%c" , i) ;
    i ++ ;
    }
    while ( i<= 'Z' ) ;
    printf("\n") ;

    Printf("Weiter mit [RETURN] ") ;
    do /* reagiert nur auf Eingabe von [RETURN] */
    i = getch ( ) ;
    while ( i != 13) ;
     
     

    do
    i = getch ( ) ; /* bleibt in der Schleife bis zur Eingabe von 0, 1 oder 2 */
    while ( i < '0' || i > '2' ) ;
     
     

    Printf("Wollen sie .... [j/n] ->") ;
    do
    i = getch ( ) /* bei Eingabe von j, n, N, J gehts raus aus der Schleife */
    while ( i != 'j' && i != 'J' && i != 'n' && i != 'N' ) ;

    nach der de Morgan´schen Regel:

    while (!( i = = ' j ' || i = = 'J' || i = = 'n' || i = = 'N' ) ;
     
     
     
     

    Ergänzende Befehle zur Programmablaufsteuerung
    (Sprungbefehle)

     
    Befehl vorkommen Wirkung
    break

    (häufig)

    in Schleifen und in switch / case – Konstruktionen Sprung hinter das Ende der unmittelbare umgebenden Schleife bzw. switch / case – Konstruktion 
    continue

    (seltener, weil auch mit if möglich)

    nur in Schleifen beginne nächsten Schleifendurchlauf sofort. Entspricht einem Sprung zur erneuten Prüfung der Laufzeitbedingung. Bei for – Schleifen wird –so vorhanden- vorher noch der ausdr3 gemacht.
         

     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
    Befehl vorkommen Wirkung
    exit ( ) Standardfunktion <stdlib.h>
    Kann an beliebiger Stelle im Anweisungsteil aufgerufen werden.
    beendet aktuellen Prozeß

    Syntax für exit ( ) :

    if ( bed ) exit ( 0 ) ; /* in Klammer gehört der exit – Code. Er kann in *.bat – Dateien bzw. unter UNIX in Shell-Scripten abgefragt werden mit if errorlevel abgefragt werden. Mögliche Werte sind 0 .... 255.
    Per Kovention gilt: 0 fehlerfreies Programmende
    != 0 Ende wegen Fehler
    */
    Befehl vorkommen Wirkung
    goto nicht oder nur sparsam verwenden ! Sprung zur angegebenen Marke

    Übungen:

    1. ASCII-Tabelle ausgeben
    2. Summe über alle ganzen Zahlen zwischen Unter- und Obergrenze (jeweils inclusive)
    3. Alle 3er Kombinationen von Großbuchstaben erstellen lassen und mitzählen.