ThInf-HOME

  1. Programmieren als Teil des Softwareengineerings

  2. Softwareprojekte

  3. Grenzfall: ein C-Programm in einer Datei

  4. Einfache Ein- und Ausgabe

  5. Elementare Datentypen und Speicherbedarf

  6. Erste Kontrolle: die Befehle 'if' und 'switch'

  7. Logische Vergleichsoperatoren

  8. Übungsaufgaben


I-PROGRAMMIEREN1 WS 0203 - Vorlesung mit Übung
Programmieren als Teil des Softwareengineerings
Erste Elemente eines C-Programms

                          Organisatorisches: Aufgrund von Grippe konnte diese Vorlesung nicht
                          vollständig als HTML-Text geschrieben werden. Die restlichen Informationen
                          gab es aber als mündlichen Vortrag.
                        

AUTHOR: Gerd Döben-Henisch
DATE OF FIRST GENERATION: Sep-23, 2002
DATE OF LAST CHANGE: Oct-9, 2002
EMAIL: Gerd Döben-Henisch


Werkzeuge: Für HTML den Editor 'quanta', für Sourcecode den Editor 'xemacs', für (UML-)Diagramme den Editor 'tcm' mit 'gimp' als Formatierer und Konverter, für die Umwandlung von C(++)-Sourcecode nach HTML den Konverter 'cpp2html', zur 'Kontrolle' des Aussehens des HTML-Codes 'mozilla 1.0', zum Verwalten der Dateien 'make', zum Kompilieren 'gcc', zum Debuggen von Sourcecode den Debugger'gdb', zum Einpacken der Dateien das Werkzeug 'tar' mit dem Komprimierer 'gzip'




1. Programmieren als Teil des Softwareengineerings

Programmieren geschieht im Normalfall immer in einem grösseren Kontext, der als Disziplin von dem Fach Softwareengineering (SWE) behandelt wird und als konkreter Prozess in der Regel Teil eines konkreten Softwareprojektes ist. Beide Themen werden im Lehrplan gewöhnlich im 4. und 5.Semester behandelt. Die Lehrveranstaltung Programmieren1 - 3 verstehen sich als Vorbereitungen auf dieses komplexe Thema. DEr Schwerpunkt liegt zwar eindeutig auf dem Erlernen einer konkreten Programmiersprache, auf der Handhabung von Programmierwerkzeugen und auf das Kennenlernen erster grundlegender Konzepte, doch soll in dieser vorlesung auch schon der grössere Zusammenhang des Softwareengineerings ansatzweise thematisiert werden. Dazu ein erweitertes Schaubild.



swe

Programmieren als Teil des SWE




START

2. Softwareprojekte

Während die Disziplin des Softwareengineerings den Vorgang der Softwareerstellung in all seinen Phasen theoretisch analysiert, Modelle erarbeitet und Werkzeuge bereitstellt, findet der konkrete Prozess der Erstellung Software gewöhnlich im Rahmen eines Softwareprojektes statt. Zwar lässt sich die konkrete Praxis selten 1-zu-1 unter verfügbare theoretische Modelle einordnen, aber der Erfolg von Softwareprojekten hängt letzendlich davon ab. Wie Dr.Denker von der Firma Aonix in einem Vortrag im Rahmen des Informatikkolloquiums herausstellte, liegt die Erfolgsquote von SW-Projekten seit Jahren bei nur 26-27%; dies offenbart ein klares Defizit zwischen Anforderung an das Softwareengineerung und tatsächlicher Leistungsfähigkeit.

Der eigentliche Sourcecode ist zwar letztlich Ziel und Kern eines jeden Softwareprojektes, doch lässt sich guter Sourcecode bei grösseren Projekten eigentlich nur erstellen, wenn eine Reihe von Randbedingungen erfüllt sind. Die Darstellung dieser Randbedingungen gehört in die zukünftige Vorlesung SWE. Am Beispiel eines kleinen Projektes (siehe: Vorbereitung eines Projektes sowie Allgemeiner Projektrahmen) sei hier trotzdem mal ein erster Eindruck vermittelt, welche Komponenten alle in einem SW-Projekt wirksam werden; und dies ist nur ein einfaches Beispiel.

Im Normalfall besteht Sourcecode nicht nur aus einer einzigen Datei, sondern aus einer Vielzahl von Dateien, die entsprechend verwaltet werden müssen. Dafür gibt es mittlerweile diverse Werkzeuge. In der Lehrveranstaltung programmieren1 werden wir mit 'make' ein einfaches Werkzeug kennenlernen.

Wir beginnen jetzt damit dass wir zunächst konkrete C-Programme analysieren und mit den verfügbaren Elementen experimentieren. Im späteren Verlauf werden wir versuchen, zunehmend auch Aufgabenstellungen zu formulieren, diese objetkorientiert zu analysieren und dann in ein C-Programm (meist bestehend aus mehreren Dateien) umsetzen.


START

3. Grenzfall: ein C-Programm in einer Datei

Der einfachste Fall ist ein C-Programm, das vollständig in einer einzigen Datei vorliegt. Die grundsätzliche Struktur eines solchen 1-Datei-Programms zeigt das folgende Schaubild:



cprogramm

Ein C-Programm in einer Datei




/***************************************************************
*
* start.c
*
* author: gdh
* date: oct-8, 2002
*
* idea: Erstes einfaches Beispiel für ein einfaches C-Programm
* before: Keine
* after: Keine
* compilation: gcc -o start start.c
* usage: start
*
***************************************************************/

#include  <stdio.h>

int main(void)
{
   printf("Jetzt kommt es: \n\n");

   printf("Das berühmte erste Hallo...\n");

   printf("!!!!!!!!!!!!!\n");


   return(0);  /* auch möglich: return 0; */
}


In diesem Programm gibt es eine Präprozessoranweisung '#include <stdio.h>', die besagt, dass die Headerdatei 'stdio.h' als Text zum nachfolgenden Quelltext dazugeladen werden soll. Diese Datei enthält eine Reihe Vereinbarungen zu den Ein-/ Ausgabefunktionen von C, die in einer eigenen Bibliothek abgelegt sind. Aufgrund der Headerdatei 'stdio.h' erkennt der Compiler, dass die Zeichenkette 'printf' nicht irgendeine Zeichenkette ist, sondern ein Befehlswort der Sprache C, das besagt, dass das nachfolgende Argument '(.......)' auf den Bildschirm ausgegeben werden soll.

Dann folgt die Angabe 'int main(void){ ... }'. 'main' ist der Name jener Funktion, die in jedem C-Programm vorhanden sein muss, da alle anderen Funktionen diese Funktion voraussetzen. Die Struktur von 'main' entspricht dem allgemeinen Format von Funktionen in C: TYPANGABE FUNKTIONSNAME (MÖGLICHE EINGABE-PARAMETER) { BEFEHLSBLOCK }. Hier also
TYPANGABE -> 'int'
FUNKTIONSNAME -> 'main'
(MÖGLICHE EINGABE-PARAMETER) -> '(void)' := 'void = leer' besagt, dass keine Parameter übergeben werden; es gibt aber auch die Möglichkeit, dass man Parameter übergibt (spätere Lektion).
{ BEFEHLSBLOCK } -> Folge von möglichen C-Befehlen. Im Beispiel nur printf-Anweisungen.

Die Form der main-Funktion entspricht der form, wie man eine Funktion definiert. Die nachfolgenden printf-Anweisungen sind auch C-Funktionen; diese treten aber nicht als Funktionsdefinitionen auf, sondern in der Form von Funktionsaufrufen. Ein Funktionsaufruf besteht aus dem Funktionsnahmen (auch Befehlswort), dem ein Paar runde Klammern folgen, in denen jene Parameter stehen, die der Funktion als Argumente übergeben werden. Später werden wir sehen, dass es auch Funktionen gibt, die man auch anders hinschreiben kann, z.B. die Additionsfunktion. Statt '+(a,b)' für die Addition der beiden Zahlen 'a' und 'b' wird man sie schreiben 'a + b'; dies ist die sogenannte Infixschreibweise von Funktionen.Der Funktionsnahme ist '+' und die Argumente sind 'a' und 'b', ohne runde Klammern.

Im Falle der Funktion 'printf' haben wir die Päffixschreibweise 'printf(.......)'. Die Eingabeparameter der Funktion printf bestehen entweder einfach aus einer Zeichenkette "........" alleine oder aus einer Zeichenkette "......%....%...." in der Formatspezifikatoren '%' auftreten, und nach der Zeichenkette soviele weiteren Argumente, wie Formatspezifikatoren in der Zeichenkette vorkommen (siehe das nachfolgende Beispiel).

Die 'return-Anweisung' schliesst die Folge der Befehle ab. Sie definiert einen Rückgabewert der funktion main an jene funktion, die diese main-Funktion aufruft. Im konkreten Fall wird der Wert '0' zurückgeliefert, wenn die Funktion main beendet wird.


START

4. Einfache Ein- und Ausgabe

Für die elementare Ein- und Ausgabe stehen in C viele Funktionen zur Verfügung. Wir betrachten heute nur zwei: 'printf' sowie 'scanf'. Beiden Funktionen ist gemeinsam, dass man ihnen Formatangaben mit übergeben kann, die festlegen, in welches Format ein bestimmter Variablenwert konvertiert werden soll. Die kompletten Formatangaben umfassen 6 Felder, von denen hier zunächst nur die wichtigsten angegeben werden

START

FLAGS

MINIMUM FIELD WIDTH

PRECISION

SIZE MODIFIER

CONVERSION LETTER

MEANING

%





d,i

Vorzeichenbehaftete Dezimalzahl

%





o (bzw. x,X)

Vorzeichenlose Oktalzahl (bzw.Hexadezimalzahl)

%





c

Zeichen

%





f

Wenn keine Präzisierung angegeben wird, dann [-]dd.dddddd

%





s

Zeichenkette



Im weiteren Verlauf werden wir noch weitere Konversions-Spezifikationen kennenlernen.


START

5. Elementare Datentypen und Speicherbedarf



dattyp

Elementare Datentypen in C



Aussagen in einem Programm sind in der Regel Funktionen (Operationen), die auf Daten operieren. In C gibt es einerseits eingebaute Datentypen, der Anwender kann abr auch eigene Datentypen generieren.

Datentyp

Bedeutung

Grösse in Bytes
(z.B. SuSe 7.2 Linux auf 32-Bit System)

Wertebereich
(z.B. SuSe 7.2 Linux auf 32-Bit System)
(exemplarisch)

int

Ganze Zahl

4

float

Gleitkomma mit einfacher Genauigkeit

4

double

Gleitkomma mit doppelter Genauigkeit

8

char

Zeichen

1

unsigned char

Zeichen

1

[0,255]

signed char

Zeichen

1

[-128,127]

enum

Aufzählungen von Namen, die ganze Zahlen repräsentieren

void

leer/ nichts; für Funktionen ohne Rückgabewert

unsigned int

4

[0,4294967295]

signed int

Ganze Zahl

4

[-2147483648,2147483647]

short int

2

signed short int

2

[-32768, 32767]

unsigned short int


4

[0,65535]

long int

4

signed long int

4

[-2147483648,2147483647]

unsigned long int

4

[0,4294967295]

long double

12

In der vorausgehenden Aufstellung werden zusätzlich Attribute zu den Basis-Datentypen verwendet:

Attribut

Bedeutung

short

eventuell kleiner als 'normal'

long

eventuell grösser als 'normal'

unsigned

vorzeichenfrei

signed

vorzeichenbehaftet

Welche Auslegungen die einzelnen Datentypen genau haben, das kann man einerseits der Headerdatei limits.h entnehmen, andererseits kann man das mit dem Operator sizeof() überprüfen.

Zeichen über werden über den Datentyp char realisiert. Besonders zu beachten ist die Unterscheidung eines einzelnen Zeichens, einer Zeichenkonstante, geschrieben z.B. 'a' für das Einzelzeichen 'a', und einer Zeichenkette (string), geschrieben als Folge von Zeichen zwischen doppelten Anführungszeichen " ..... ".

Da es einzelne Zeichen gibt, die eine Sonderbedeutung haben können{',",\,n,t,o,x,b,f,r} , muss man bei Gebrauch dieser Sonderzeichen speziell deutlich machen, dass man diese Sonderzeichen nicht als 'normale' Zeichen benutzen will, sondern eben als Sonderzeichen. Dies geschieht durch Vorstellen eines Rückstrichs (backslash):

ZEICHEN

BEDEUTUNG

\'

Einfacher Anführungsstrich

\"

Doppelter Anführungsstrich

\\

Rückstrich (backslash)

\n

Zeilenumbruch (newline)

\t

Tabulator-Zeichen (tab)

\oct-ziffern

Zeichen mit einem oktalen Wert (bis zu drei Zeichen)

\xhex-ziffern

Zeichen mit einem hexadezimalen Wert

\b

Ein Zeichen nach links (backspace)

\f

Eine Seite weiter (formfeed)

\r

An den Anfang der nächsten Zeile (carriage return)


/***************************************************************
 *
* start2.c
*
* author: gdh
* date: oct-8, 2002
*
* idea: Beispiel mit Verinbarung und Bildschirmausgabe von Variablen vom Typ 'int' und 'char'
* before: Keine
* after: Keine
* compilation: gcc -o start2 start2.c
* usage: start2
*
***************************************************************/

#include  <stdio.h>

int main(void)
{

  int x,y;        /* Zwei Variablen mit Namen 'x' und 'y' vom Typ 'int' */
  char c, hans;  /* Zwei Variablen vom Typ 'char' */

  x=3;      /* Wertzuweisungen */
  y=5;
  c='a';
  hans='y';

  printf("Wert von x= %d und Wert von y= %d \n",x,y);
  /* Ausgabe der Werte von x und y mittels Formatspezifizierer */
  printf("Wert von c= %c und Wert von hans= %c \n",c,hans);
  /* Ausgabe der Werte von c und hans mittels Formatspezifizierer */


   return(0);  /* auch möglich: return 0; */
}


gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2> ./start2
Wert von x= 3 und Wert von y= 5
Wert von c= a und Wert von hans= y
 

Hier eine weitere Variante mit der Funktion 'scanf'. Die Funktion scanf ist einerseits bequem, da man formatiert Daten von der Tastatur einlesen kann, sie ist aber zugleich schwierig, da jene Daten, die nicht in ein vorgesehenes Format passen, dennoch im Input-Buffer landen und das Einlesen der nächsten Daten stören können. Falsche Eingaben bei mehrfachen Argumenten sind daher eine beliebte Fehlerquelle. Im Beispiel wird nur angenommen, dass ausser formatspezifikatoren nur noch normale Textzeichen auftreten können, die dann als solche auch in der Eingabe in der angegebenen Reihenfolge erscheinen müssen.

Um die Funktion von Textzeichen zwischen Formatspezifikatoren im Beispiel zu demonstrieren, wurden zwischen den beiden Formatspezifikationen für Zeichen vom Typ char keine Kommas gesetzt, während dies im Falle der Formatumwandler für Variablen vom Typ int getan wurde. Weicht die Eingabe davon ab, verhält sich das Programm unerwartet.

Eine ausführlichere Auseinandersetzung mit der Funktion 'scanf' erfolgt an späterer Stelle.


/***************************************************************
 *
* start3.c
*
* author: gdh
* date: oct-8, 2002
*
* idea: Beispiel mit Vereinbarung und Bildschirmausgabe von Variablen vom Typ 'int' und 'char'
*       sowie Abfrage von der Tastatur
* before: Keine
* after: Keine
* compilation: gcc -o start3 start3.c
* usage: start3
*
***************************************************************/

#include  <stdio.h>

int main(void)
{

  int x,y;        /* Zwei Variablen mit Namen 'x' und 'y' vom Typ 'int' */
  char c, hans;  /* Zwei Variablen vom Typ 'char' */



  printf("\nBitte Werte fuer die CHAR-Variablen c und hans OHNE trennendes Komma:");
  scanf("%c %c",&c,&hans);

  printf("Bitte Werte fuer die INT-Variablen x und y MIT zwei trennenden Kommas: ");
  scanf("%d,, %d",&x,&y);


  printf("Wert von c= %c und Wert von hans= %c \n",c,hans);
  /* Ausgabe der Werte von c und hans mittels Formatspezifizierer */
  printf("Dezimaler Code-Wert von c= %d \n Dezimaler Code-Wert von hans= %d \n",c,hans);

  printf("Wert von x= %d und Wert von y= %d \n",x,y);
  /* Ausgabe der Werte von x und y mittels Formatspezifizierer */



   return(0);  /* auch möglich: return 0; */
}



gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2> ./start3

Bitte Werte fuer die CHAR-Variablen c und hans OHNE trennendes Komma:a b
Bitte Werte fuer die INT-Variablen x und y MIT zwei trennenden Kommas: 123,,55
Wert von c= a und Wert von hans= b
Dezimaler Code-Wert von c= 97
 Dezimaler Code-Wert von hans= 98
Wert von x= 123 und Wert von y= 55
gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2>


START

6. Erste Kontrolle: die Befehle 'if' und 'switch'

AUSWAHLOPERATOR

BEDEUTUNG

  1. if ( AUSRUCK ) ANWEISUNG

  2. if ( AUSDRUCK ) ANWEISUNG1 else ANWEISUNG2

  1. Wenn AUSRUCK 'true' ist, dann wird die nachfolgende ANWEISUNG ausgeführt.

  2. Wenn AUSDRUCK 'true' ist, dann wird ANWEISUNG1 ausgeführt, andernfalls ANWEISUNG2.

Falls ANWEISUNG1 ein weiteres if enthält, dann muss es von einem else gefolgt werden.

switch ( AUSDRUCK ) ANWEISUNG


wobei ANWEISUNG folgende Label enthalten kann:

  1. case KONSTANTER-AUSDRUCK :

  2. default : (höchstens ein default-label)

und die UNTERANWEISUNG break;

Wenn AUSDRUCK 'true' ist, dann wird die nachfolgende ANWEISUNG ausgeführt. Mittels der Label case und default kann man im Bereich der ANWEISUNGEN differenzieren.

Falls eine break-ANWEISUNG vorliegt, wird die Ausführung von switch mit break abgebrochen und bei der nächsten ANWEISUNG hinter der switch-Anweisung fortgesetzt.

.Ein Ausdruck (engl. 'expression') besteht aus einem C-Operator (= Funktionsnamen) und den zu diesem Operator gehörenden Argumenten (= Operanden) des Operators. In C gibt es Zuweisungsoperatoren (z.B.: '='), arithmetische Operatoren (z.B. '+'), Vergleichsoperatoren (z.B.: '<'), logische Operatoren (z.B.: '&&'), Bitoperatoren (z.B.: '&'), sowie Inkrement- und Dekrement-Operatoren (z.B. '++').

Man kann in einem Ausdruck oft ein Argument durch einen anderen Ausdruck ersetzen und dadurch komplexere Ausdrücke bilden, z.B.:

 a = b

 a = sizeof(int)
 

In diesem einfachen Beispiel wird in dem Ausdruck 'a = b', in dem der Variablen a der Wert der Variablen b zugewiessen wird, der Variablenname 'b' durch den Ausdruck 'sizeof(int)' ersetzt. 'sizeof(int)' ist selbst ein Ausdruck bestehend aus dem Funktionsnamen 'sizeof' und dem Argument 'int'. Es wird also der Variablen a im zweiten Ausdruck der Wert der Funktion sizeof bei dem Argument int zugewiessen.

Eine Anweisung (engl. 'statement') besteht aus einem Ausdruck gefolgt von einem Semikolon (';'), d.h. durch die Hinzufügung des Semikolons wird aus einem Ausdruck ein Befehl, der ausgeführt werden soll.


START

7. Logische Vergleichsoperatoren



VERGLEICHSOPERATOREN
(Infix-Schreibweise, 2-stellig)

BEDEUTUNG

<

kleiner

<=

kleiner-gleich

>

grösser

>=

grösser-gleich

==

gleich

!=

nicht gleich, ungleich



Im folgenden Beispiel werden zwei Zahlen von der Tastatur abgefragt und dann wird mittels 'if' und 'else' und den logischen Operatoren '<' sowie '>' geklaert, ob die erste Zahl x kleiner, groesser oder dann gleich der zweiten Zahl y ist. Die dabei verwendete if-else-Konstruktion ist rekursiv, insofern im else-Statement wieder eine if-else-Konstruktion eingesetzt wurde.



  /***************************************************************
 *
* start4.c
*
* author: gdh
* date: oct-8, 2002
*
* idea: Benutzer gibt zwei Zahlen x,y ein, das Programm entscheidet,
        ob x kleiner, gleich oder groesser y ist
* before: Keine
* after: Keine
* compilation: gcc -o start4 start4.c
* usage: start4
*
***************************************************************/

#include  <stdio.h>

int main(void)
{

  int x,y;        /* Zwei Variablen mit Namen 'x' und 'y' vom Typ 'int' */



  printf("Geben sie bitte zwei ganze Zahlen x und y ein, ohne Trennzeichen: ");
  scanf("%d %d",&x,&y);

  printf("Wert von x= %d und Wert von y= %d \n",x,y);

  /*******************************
   * Abfrage der moeglichen Faelle
   ******************************/

if(x < y) printf("x ist KLEINER y\n");

else {
  if(x>y) printf("x ist GROESSER y\n");
  else printf("x ist GLEICH y\n");
}



   return(0);  /* auch möglich: return 0; */
}



gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2> ./start4
Geben sie bitte zwei ganze Zahlen x und y ein, ohne Trennzeichen: 4 7
Wert von x= 4 und Wert von y= 7
x ist KLEINER y
gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2> ./start4
Geben sie bitte zwei ganze Zahlen x und y ein, ohne Trennzeichen: 10 2
Wert von x= 10 und Wert von y= 2
x ist GROESSER y
gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2> ./start4
Geben sie bitte zwei ganze Zahlen x und y ein, ohne Trennzeichen: 3 3
Wert von x= 3 und Wert von y= 3
x ist GLEICH y
gerd@goedel:~/WEB-MATERIAL/fh/I-PROGR1/I-PROGR1-TH/VL2>


START

8. Übungsaufgaben

Werden während der Übung gestellt.


START