C Block 3

http://www.sirius-net.de

Funktionen ( Unterprogramme) *

Funktion: *

Vorteile: *

Funktionen (Unterprogrammtechnik) *

Reihenfolge im Quelltext: *

Übergabe der Parameter beim Funktionsaufruf *

Datentypen, die als Parameter an Funktionen übergeben werden und mögliche Rückgabetypen. *

Funktion, die Array verarbeitet *

Lokale und globale Variablen *

Funktionen, die Arrays verarbeiten, hier: Strings *

s_cmp() : lexikalischer Vergleich der Strings *

s_rev () : String "umdrehen" *

Wo in C- Programmen automatische Typkonvertierungen vorkommen können *

Speicherklassen *

Lokale Variablen: *

static Datensegment *

globale Variablen: *

Funktionen *

Der Modifizierer const *

Der Modifizierer volatile *

Konzept für eine eigene " wasserdichte" Eingabefunktion *

Funktionsdefinitionen: *

Konzept für ein Programm ( hier Mastermind ) *

2 und mehrdimensionale Arrays (Matritzen) *

Syntax für den Zugriff auf eines der Arrayelemente: *

Initialisierung von einfachen Variblen und Arrays bei der Deklaration. *

Sonderfall: 2d- Arrays von char *

Kommandozeilenparameter ^ Die Argumente von main() *

Strukturen ^ Datensatz *

Mögliche Datentypen für Strukturkomponenten: *

Aufbau einer Variable vom Typ mitarbT: *

Zugriff auf die Komponenten einer Strukturvariable *

Strukturen im Hauptspeicher *

Funktionen, die Strukturen verarbeiten *

Unions *

Deklaration einer Union: wie bei Strukturen, *

Zugriff auf die komponenten einer Union: *

Dateien *

Grundoperationen auf Dateien und Directories: *

Dateien aus Sicht von C *

Dateiorganisation – Dateizugriffe *

Einfacher Ansatz: index – Sequentiell *

Allgemeines Procedere bei Dateizugriffen *

Begriffsklärung: *

File – Pointer , Datentyp: File * *

Satzzeiger *

fopen() Datei öffnen *

fopen() Modus und Rechte *

Zeichenweise I/O *

Blockweise schreiben und lesen *

Funktionen rund um den "Satzzeiger" *

Übungsvorschläge: *
 
 

Funktionen ( Unterprogramme)

Funktion:

Vorteile: Funktion Funktionen (Unterprogrammtechnik) Prototyp: void cls ( void); Rückgabetyp Name Parameterliste Funktionsdefinition: void cls ( void);


{


printf("\033[2J");

}

Prototyp: void curpos ( int x, int y ); Rückgabetyp Name Parameterliste Funktionsdefinition: void curpos ( int x, int y);


{

printf("\033[%dH",y,x);

}

Prototyp: double pi (void);

Funktionsdefinition: double pi ( )

Rückgabetyp Name Parameterliste
{

return 4.0*atan(1.0);


}
 
Wann endet eine Funktion?

!= void, so ist bei RETURN ein Ausdruck anzugeben. Der Wert dieses Ausdruckes ist dann

der Rückgabewert der Funktion reserviertes Wort 3b. 4.0*atan(1.0) ( im Programm: printf( "%lf" , pi()); gibt aus x=pi(); schreibt in x

Prototyp: double viereck ( double a, double b);werden im Compiler überlesen

  Funktionsdefinition: double viereck (double a, double b)

Rückgabetyp Name Parameterliste


{

return a * b ;


} Reihenfolge im Quelltext:

# include <.......> Standart- Includes

====
 

Prototypen für eigene Funktionen Reihenfolge der Prototypen ist beliebig

====

Implementierung eigener Funktionen

= Funktionsdefinitionen

= Quelltext der Funktionen

Variablen in der Parameterliste einer Funktion und lokale Variablen einer Funktion



Sichtbarkeit: nur innerhalb der Funktion/des Programm- Blocks, in dem sie deklariert sind.



"lokale" Variablen



Lebensdauer: Die lokalen Variablen und Parameter einer Funktion werden( im Stackbereich des Programmes) aufgebaut bei Eintritt in diese Funktion und wieder abgebaut, wenn die Funktion endet.
  Übergabe der Parameter beim Funktionsaufruf 57

int mult1 ( int x, int y ) Funktionskopf mit formalen Parametern


{ x = 3 ; *

return x * y;


}


void main()

{

int a, b, c;

a = 5; b = 7; zu main() lokale Variablen

c = mult1 ( a , b );

57

printf ( "%d\n",c ) ;

printf ( "%d\n",a ) ;
 
 

Regel:

die aktuellen Parameter beim Funktionsaufruf müssen mit den formalen Parametern der Funktion in Anzahl, Typ und Reihenfolge übereinstimmen.
 

4020

void mult1 ( int x, int y, int *p)

{

*p = x * y;

}

void main()

{

int a, b, c;

4020

a = 5; b = 7;

mult2 ( a , b ,&c);

57

printf ( "%d\n",c ) ;

printf ( "%d\n",a ) ;
 
 


void mult1 ( int x, int y)

{

return x * y;

}

void main()

{

int a, b, c;

a = 5; b = 7;

mult2 ( a , b );

57

printf ( "%d\n",c ) ;

printf ( "%d\n",a ) ;
 
 

Stack
 
 
 
 
 
Rückspr.-Adr
5
7

Datentypen, die als Parameter an Funktionen übergeben werden und mögliche Rückgabetypen.
Typ
Bemerkung
Standarts
Numerische Grunddatentypen
- keine -
- alle -
Pointer aller Art
Die gerufene Funktion kann den Pointer dereferenzieren (* Operator)
- alle -
Arrays aller Art (auch Strings) 
Arrays als ganzes werden nicht an Funktionen übergeben bzw. zurückgegeben, sondern deren Anfangsadresse, also ein Pointer. 
- alle - 
Strukturen

("Datensätze")

Können seit ANSII– C als Ganzes über den Stack übergeben werden, was allerdings ineffizient ist. 

Besser: Adresse der Struktur übergeben, was in allen Standarts geht.

( K&R )

ANSII- C

C++

Referenztypen
- siehe später - 
C++
Instanzen von Klassen
- siehe später - 
C++

Bsp.:

Funktion, die Array verarbeitet Bubble- Sort für Arrays
 
 

Prototyp: void bubble (int * , int ) ;
 
 

Funktionsdefinition:

void bubble ( int * f , int n )

{ int i , j , h ; --- Inhalt bubble- sort ---

}
 
 
 
 

Lokale und globale Variablen
  lokale Variablen: globale Variablen:
deklariert innerhalb einer Funktion,

üblich: nach der 1. { des Funktionsblockes, bzw. als parameter zwischen ( und ) des Funktionskopfes.

 
Sichtbarkeit: lokal, d.h. in der Funktion/ Pgm- Block, indem sie deklariert wird. sichtbar für alle Funktionen im Quelltext
Lebensdauer: werden angelegt, wenn die Funktion betreten wird und wieder 

Abgebaut, wen die Funktion endet.

gesamte Programmlaufzeit 

è Datensegment

sinnvoll bei:   Großen Arrays, die wegen ihrer Größe nicht lokal 

( also auf dem Stack ) abgelegt werden können. Bei Programmen, in denen alle Funktionen fast ausschließlich mit den gleichen Daten arbeiten.

Bedarf der Begründung!


 
 
 

Für lokale und globale Variablen gleichen Namens gilt:

Im Sichtbarkeitsbereich der lokalen Variable ist kein Zugriff auf die globale Variable gleichen Namens möglich. ( K&R, ANSII - C )

Funktionen, die Arrays verarbeiten, hier: Strings 28.09.1999

Void main()

{

char f1[81], f2[81];

int i;

gets (f1);


i = s_len(f1); Stringlänge

printf("%d\n",i);

printf("%d\n", s-len("Hallo"));

size_ t ganzzahliger Typ, der von sizeof() zurückgeliefert wird. Je nach Hersteller unsigned od, int

(s.o. "typdef")


Void main()

{

char f1[81], f2[81];

int i;

gets (f1);

i = s_len(f1);

printf("%d\n",i);

printf("%d\n", s-len("Hallo"));

s_cpy(f2,f1); Stringcopy

puts (f2);
 

Hinweis: s-cpy() bzw: die Standartdef. strcpy() <string.h> gibt seinen ersten Aufrufparameter zurück.( = Anfangsadresse des kopierten String.) Sinn: geschachtelte Funktionsaufrufe werden möglich!!

printf("%d\n", atoi(s_cpy(f2,gets(f1) ) ) ) );
 
 

Prinzip: Rückgabewert der inneren Funktion ist der Aufrufparameter der (nächsten) äußeren Funktion. Void main()

{

char f1[81], f2[81];

int i;

gets (f1);

i = s_len(f1);

printf("%d\n",i);

printf("%d\n", s-len("Hallo"));

s_cpy(f2,f1);

puts (f2);

gets(f2);

s_cat(f1,f2); Stringverkettung

puts (f1);
 

s_cmp() : lexikalischer Vergleich der Strings

Standart- Funktion: strcmp()<string.h>

BlumenvaseÆgrHausÆkl AlfÆ

BlumentopfÆklhausÆgr AlfÆ

StuttgartÆklHoseÆkl

Stuttgart – NordÆgrSchuhÆgr

int s_cmp (char * st1; char * st2 ) ;


String1 String2


positiv wenn string1 "größer" string2


null wenn string1 gleich string2


negativ wenn string1 "kleiner" string2

Void main()

{

char f1[81], f2[81];

int i;

gets (f1);

i = s_len(f1);

printf("%d\n",i);

printf("%d\n", s-len("Hallo"));

s_cpy(f2,f1);

puts (f2);

gets(f2);

s_cat(f1,f2); Stringverkettung

puts (f1);

i = s_cmp (f1 , f2 ); String umdrehen

printf("%s\n %s\n %d\n", f1, f2, i);

i = s_cmp ("Haus", "haus");

s_rev( f1 );

puts( f1);

puts( s_rev(f1));
 

s_rev () : String "umdrehen"

Borland- Funktion: strrev()

Prototyp: char * s_rev( char * st) ;

Adresse des "unzudrehenden" Strings
 

char * s_rev( char * st)

{

char *h, *v;

int z;


for( h=st ; *h ; h++ ) ; Leeranweisung

for( ---h , v=st ; v<h ; v++, h-- )

{

z= *v;

*v= *h;

*h= z;

}

return st;

}
 
 

Bsp.: input()

input ("Name", f1);

puts(f1);

input("Entfernung", f2);

x = atof(f2);

printf("%lf\n",x);
 



 
  Wo in C- Programmen automatische Typkonvertierungen vorkommen können (2)double pi()


{

return 4.0 * atan(1.0);

double double


double (1) }

void main()

{

double d;

d = pi(); (3)

printf("%lf\n",d);

}


Speicherklassen

berifft: lokale Variablen

globale Variablen


Funktionen


betrachtete Aspekte: Sichtbarkeit


Lebensdauer
 
Übersicht:
auto
register
siatc
extern
lokale Variablen
(1) x
x
x
 
globale Variablen Ä    
x
x
Funktionen Ä    
x
(1) x

Voreinstellung

Äkommt erst zum Tragen, wenn der Quelltext auf mehrere Dateiein aufgeteilt wird, die getrennt übersetzt werden und dannn zu einer *.EXE Datei zusmmengefasst werden.

Lokale Variablen:

auto "automatic", Voreinstellung Stack

Sichtbarkeit: nur innerhalb des Funktionsblockes, in dem sie deklariert sind.

Lebensdauer: * Eintritt in den Pgm- block in dem sie deklariert sind:


beim Ende de Betreffenden Pgm- Blockes/ Funktion.
 
 


static Datensegment

Sichtbarkeit: weiterhin lokal

Lebensdauer: gesamte Programmlaufzeit

Speicherklasse Typ Name ; Syntax: static int i ;

Bsp.:

int wurfel()

{


static int i=1; Variable wird einmal zu Programmbeginn mit 1 initialisiert.

if(i)

{

srand(time(NULL));

i=0;

}

return rand()% 6+1;

}
 
 

lokale Variablen: register


Bsp: register int i ;

einstellung auto sind. Register passen, die also nicht größer sizeof(int) sind. Neuere Compiler versuchen von sich aus, die am häufigsten in einer Funktion verwendeten int- Variablen in Registern zu halten.

BC 3.1 als Bsp, verwendet für diesen Zweck- sofern noch übrig- die Register SI und DI

globale Variablen: static brenzt die Sichtbarkeit einer globalen Variable auf das Quelltext- Modul, in dem sie deklariert ist.
 
 
 
 

extern teilt dem compiler mit, daß eine globale Variable, die hier benutz wird, in einem anderen Modul deklariert ist.

teil1.c teil2.c

# include<...>

int i;

static int b;

void main();

{

funk99();

printf("%d\n",i);

}

Compiler Compiler

teil1.obj teil2.obj
 
 
 
 

Linker Standatrbibliothek

progi.exe

Funktionen Funktionen sind per Voreinstellung extern, d.h. der Compiler geht davon aus, daß Funktionen die nicht im Quelltext stehen vom Linker schon "irgendwo" gefunden werden.


Funktionen, die static deklariert sind, sind in ihrer Sichtbarkeit auf das Quelltextmodul beschränkt, in dem sie definiert sind.

Bsp.: static c int b_007()

{

?

retutn 7;

}
 
 

Der Modifizierer const ( ANSI- C, C++)

Verwendung:

  1. Deklaration von Variablen, deren Inhalt dann nicht mehr geändert werden kann

  2.  

     


    Konstante.

    Solche Variablen müssen bei der Deklaration gleich initialisiert werden.

    Bsp.: const int x = 7 ;

    int *p;

    x = 13; Error

    p = &x;

    *p = 13;

    Querverweis, siehe benannte konstanten mit #define

  3. in der Parameterliste von Funktionen.
int s_len(const char * st)

{

int i;

/* in diesam Block kann st jetzt explizit nicht mehr geändert werden.*/

st++; Error

}
 
 

Der Modifizierer volatile

v o l a t i l e int i ;

Der Compiler soll für so deklarierte Variablen keine Optimierung vornehmen. Macht Sinn für Variablen, deren Wert sich durch äußere Einflüsse (z. B. Interrupt) änden kann.
 
 

Konzept für eine eigene " wasserdichte" Eingabefunktion
Anzahl der Zeichen, die maximal angenommen werden soll steuerbar sein. Parameter max
Minimal- Anzahl einzugebender Zeichen soll steuerbar sein Parameter min ist min > 0 so entsteht ein Pflichtfeld.
Menge der "erlaubten" Zeichen soll definiert werden können. Zeichenprüffunktion keytest_n()


Eingabefeld aus Unterstrichen am Bildschirm: putchar (‘_’); max ----------------------------------------- cursor (x/y) x positionierbar y mit curpos(); Parameter x und y
Ergebnis: die Funktion hinterläßt ein ASCII- Z String in einem Array, das vom Aufrufer der Funktion zur Verfügung zu stellen ist. mindestens max + 1 Zeichen. Parameter Arrayanfangsadresse int keytest_n ( int z) ;

{

if ( z > = ’0’ && z < = ‘9’ ) return z ;

return 0;

}

int x;


x ASCII- Code;


if( keytest_n(x)) -------- ;

Bsp.- Aufruf: char f[81];

char * string_in(10,5,f,5,2); x y max min

int int char* int int

char* string_in(int x, int y, char *f, int max, int min )

{

Lokale Variablen

for(

z = getch(); <conio.h>

if( z == erlaubtes Zeichen und max noch nicht erreicht)

{

}

else

if( z == BACKSPACE und schon mind 1 Zeichen da )

{

}

else

if( z == RETURN und minimum erreicht)
 
 
 
 

return f;

}

Praktikum:

- spielen - Funktionen nach K & R 30.09.1999 Prototypen im inne von ANSI- C gibt es in K & R nicht, Jedoch gibt es Funktionsdeklarationen nach K & R. Regel hier:

Funktionen müssen deklariert werden, wenn sie einen Typ größer sizeof ( int ) zurückgeben.

Bsp. solcher Funktionsdeklaration:

double sqrt( * );

double pow( * );

bleibt immer leer,

d.h. die Parameterliste

wird nicht beschrieben
 
 

Funktionsdefinitionen: zurückgibt ( gilt in allen Standarts). als Rückgabetyp: einfach weglassen, die Funktion gibt dann formal int zurück, der Rückgabewert sollte jedoch nicht zugewiesen werden. in der Parameterliste: einfach leer lassen. die Parameterwerden zwischen ( und ) nur namentlich der Reihenfolge nach genannt. Deklariert werden sie nach der ) und vor der ersten { der Funktion:
 
 

K & R ANSI- C

funk1(a,b,c)

int a,b,c;

{

return -------;

}

int funk1(int a, int b, int c)

{

return -------;

}

cls()

{

---------;

}

void cls()

---------;

}

char * string_in( x , y , f , max , min )

int x, y, max, min;

char * f;

{

return f;

}

char * string_in( int x, int y, char *f, 

int max, int min )

{

return f;

}

Konzept für ein Programm ( hier Mastermind )

Workflow

  1. Idee/ Aufgabenstellung
  2. Analyse der Aufgabenstellung
  3. Fachkonzept
wie sieht das fertige Produkt aus ??
  1. DV- Konzept

Datenmodell ( Datenbank ? ) festlegen der Elementfunktionen
  1. Implementierung ~ 20 %
  2. Test und Korrektur ~ 20 %

Anwender- Eindruck:

gespielt werden.

void main() Begrüßungstext / Spelregeln

{


srand(); ein Spiel internes Muster erzeugen

{



logo(); void spiel( ) Anwendereingaben entgegennehmen


for(;;) spiel(); belegen();

} versuch();

auswerten();


}


ende();

Abspann und exit(0);

globale Daten:

#define MAX 4

int pc[MAX]; Array des Rechners für 4 eindeutige Zufallszahlen aus [0...5].

int aw[MAX]; Array für einen Versuch des Anwenders.

int posok; Werden von auswerten() gesetzt positionen, die stimmen

int anzok; anzahl richtiger Werte, unabhängig von der richtigen Poition.

2 und mehrdimensionale Arrays (Matritzen)

Deklaration: int matrix [ 3 ] [ 4 ] , i , J ; i= Zeilen J= Spalten


Wichtig:

für jede Dimension beginnt der Index

mit 0 zu llaufen.

matrix [1] [2] = 439;

printf("%d", matrix [1] [2] );

scanf("%d", & matrix [1] [2]);
 
 

Syntax für den Zugriff auf eines der Arrayelemente:

Bsp.: durchlaufen des 2d- Arrays: for( i = 0 ; i < 3 ; i++ )

for( j = 0; J < 4 ; j++ ) marix [ i ] [ j ] = 0;

for( i = 0 ; i < 3 ; i++ )

{

for( j = 0; J < 4 ; j++ )

{

printf("Wert [%d] [%d] ->" ,i+1,j+1);

scanf("%d", & matrix [i] [j] );

fflush(stdin);

}

}

Anordnung im Hauptspeicher:

Die Arrayelemente liegen zeilenweise lückenlos aneinander im Hauptspeicher.

Übungsvorschlag:

  1. Matrix mit Werten vollesen.
  2. Spaltensummen und Zeilensummen bil-

  3. den.
  4. Ergebnisse aus 2. ausgeben.
Initialisierung von einfachen Variblen und Arrays bei der Deklaration. Bsp.:

int i = 7 ; Deklaration mit Initialisierung ----Neue Variable entsteht

i = 8 ; Zuweisung, arbeitet mit schon vorhandener Variable.

int g[ ] = [49 , 7 , 55 , 8 , 13 }; Optischer Unterschied zur Zuweisung !

Anzahl der Initialisierungskonstanten ergibt die größe des Arrays

char f[ ] = " Hallo " ; char *p = " Hallo" ;


Typ : char * Typ : char *

impliziter Pointer expliziter Pointer

= Konstante ! = Variable!

Sichere Variante, da Größe

Nicht mehr änderbar !!!!!
 
 
 
 

Sonderfall: 2d- Arrays von char J char * [ 7 ] wtag



 
0 1 2 3 4 5 6 7 8 9 10
10 M o n t a g Æ        
1 D i e n s t a g Æ    
2 M i t t X o c h Æ    
3 D o n n e r s t a g Æ
4 F r e i t a g Æ      
5 S a m s t a g Æ      
6 S o n n t a g Æ


Einzelnes Arrayelement ansprechen: Typ: char

wtag[ 2 ] [ 4 ] = `X `;

putchar( wtag[ 2 ] [ 4 ] ) ;

Hinweis; greift man in ein 2d- Array mit nur einem Index zu, wird ein Zeilenanfang an-

gesprochen. Typ: Adresse hier: char *
 
 
 
 

char f[81];

typ von f : char *

typ von f[i] : char *

char wtag [7] [11] ;

Typ von wtag : char ** Zeiger auf Zeiger auf char

Typ von wtag [i]; : char * Zeiger auf char

Typ von wtag [i] [j] : char
 
 

(*) werden 2- od. mehrdimensionale Arrays bei der Deklaration gleich initialisiert, so kann in dieser Deklaration die Dimension, die ganz links steht offenbleiben.

Grund: wtag [2] [4]

solche Zugriffe gehen nur, wenn der compiler " weiß", wie lang eine Zeile ist.
 
 

Kommandozeilenparameter ^ Die Argumente von main() die Parameter von main() heißen traditionell argc (" Argument count") und argv (" Argument vector"), oft auch abgekürzt ac und av.

argc Typ: int Anzahl der Parameter in der Kommandozeile.

Achtung: der Programmname zählt mit, gezählt wird ab 1.

ac 1 2 3 4 5 <-- argc

acv [ 0 ] [ 1 ] [ 2 ] [ 3 ] [ 4 ] Kommandozeile. argv enthält die Kommandozeile vom Programmaufruf die bereits als ASCIII – Z Strings aufbereitet ist. argv ist ein 2d- Array von char bzw. ein 1d- Array von Strings. Datentyp: char * argv [ ] 1d- Array aus Poinern vom Typ char*,

diese Arrayelemente sind"Stringanfänge"
 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
argv [ 0 ]

argv [ 1 ]

argv [ 2 ]

argv [ 3 ]

argv [ 4 ]

D : \ C \ P R O G 7 . E X E Æ      
/ x Æ                              
- b Æ                              
7 5 8 Æ                            
H a l l o Æ                        


putchar (argv [ 4 ] [ 3 ] ;

puts( argv [ 2 ] );

x = atoi (argv [ 3 ] ;

int char *
 
 

ANSII- C

int void main( int ac, char * av [ ], char * envp [ ] )

{

if( ac < 2 )

{

...keine Parameter...

}

return 0;

}

Einige Compiler ( zb. GNU ) erwarten

main ( ) mit Rückgabetyp int. Der Wert,

der innerhalb von main ( ) mit return

zurück gegeben wird dient als exit-code

des Programms.
 
 

Hinweis:

NAME = Wert


Querverweis: DOS- Beispiel SET

Der letzte String aus envp ist verarbeitet, wenn envp [ i ] ein FALSE bietet.


NULL- Pointer

Praktikum: Programm, das auf einen oder mehrere der folgenden Kommandozeilenparameter in angegebener Reihenfolge reagiert.

-a -b -c -d

pprog –a –c

pprog –b

pprog –b –c –d
 
 

if ( ! strcmp (av[i], "-a" )) funk_a();

0 bei Gleichhei

Strukturen ^ Datensatz Struktur: Zusammenfassung mehrerer, auch verschiedenartiger Variablen zur

besseren Handhabung.

Mögliche Datentypen für Strukturkomponenten:

Aufbau einer Variable vom Typ mitarbT:

mitarbT a;

Variable a
 
  0 1                 24        
vname                              
  0 1                         34
nname                              
  0 1         10                
persnr                              
  0 1                          
gehalt                              

Zugriff auf die Komponenten einer Strukturvariable

  1. Der Name der Strukturvariable
ist verfügbar


Benutze Punkt- Operator ·



mitarbT a;

gets( a.vname ); (vname aus Quelltext)

scanf("%f",& a.gehalt);

printf("%s %.2f\n",a.vname,a.gehalt);
 
 
 
 
 
 

Strukturen im Hauptspeicher

Die Strukturkomponenten liegen hintereinander im Hauptspeicher.

Dem Compilerhersteller ist es gestattet, Anfänge von Strukturen, aber auch einzelne Komponenten auf bestimme Adressklassen(*) auszurichten.

(*) dies kann sein:


 
 

Daraus folgt:

sizeof( Struktur ) >=S sizeof ( Komponenten )

in Comilerhandbüchern und Online- Help ist dieser Sachverhalt meist beschrie-

ben unter " Aligment" oder "Strukturen".
 
 

Funktionen, die Strukturen verarbeiten
einlesen( & a );
kopieren( & b , & a );
  1. ausgben( & b );
  1. void einlesen( mitarbT * p )

  2.  

     
     
     
     
     
     
     

    {

    printf("Vorname:-->"); gets(p-->vname);

    printf("Nachname:-->"); gets(p-->nname);

    printf("Pers.- Nr.:-->"); gets(p-->persnr);

    scanf("Gehalt:-->"); scanf("%f",& p--> gehalt);

    fflush(stdin);

    }

  3. void auslesen( mitarbT * p )
{

printf("%s %s\n %s %2f\n\n",p-->vname, p-->nname, p-->persnr, p-->gehalt );

}

Ziel quelle

3. void kopieren( mitarbT * z, mitarb * q ) ; Version 1 - Komponentenweise


{

strcpy( z-->vname, q-->vname ) ;


strcpy( z-->nname, q-->nname ) ;

strcpy( z-->persnr, q-->persnr ) ;

z-->gehalt = q-->gehalt ;

}

Ziel quelle
3a. void kopieren( mitarbT * z, mitarb * q ) ; Version 2 - byteweise in Schleife {

char * zi = ( char * ) z ;

char * qu =( char * ) q ;

int n;

for( n=0; n<sizeof(mitarbT); n++) *zi++ = *qu++ ;

}


Unions jedoch: alle Komponenten einer union beginnen an der selben Speicheradresse. lichen Portionen verarbeitet werden. Deklaration einer Union: wie bei Strukturen, allerdings ist --> struct durch union zu ersetzen. Zugriff auf die komponenten einer Union: mit dem Punktoperator,wenn der name der Union verfügbar ist, mit dem Pfeiloperator, wenn die Adresse verfügbar ist. Bsp.: long l; char f[4];

[0] [1] [2] [3]

l

l = 0x12345678;

Adresse z.B.: 1200 1201 1202 1203

typedef union u1s;

{

long l;

char f[4];


} u1t
 
 
 
 

Dateien Datei:
 
 

Grundoperationen auf Dateien und Directories:


md, cd, rd Directories


write ( schreiben ) Dateien Diese Grundoperationen bietet das Betriebssystem in seiner Programmierschnittstelle für Anwendungsprogramme UNIX : System Calls
DOS : Int 21h

Win : Windows API
 
 

Höhere Programmiersprachen stellen portable (!)Funktionen zur Verfügung, die ihrerseits wieder auf die Programmierschnittstelle des Betriebssystems zurückgreifen.

C: Funktionen aus der Standart- bibliothek

in C gibt es seit jeher 2 Gruppen von Funktionen für die Dateizugriffe:

A.) "low level routinen"

UNIX kompatible Funktionen

Prototypen in < io.h >

unter UNIX sind dies System Calls

Dateien aus Sicht von C
Datei: Folge von Bytes, die von einem externen Datenträger gelesen werden

können, bis "keine Daten mehr kommen", das Betriebssystem meldet dem

Programm dann EOF ("End of file").

--> C macht keine Annahme über den Aufbau von Dateien, noch weniger über

Sinn und Zweck der in den Dateien enthaltenen Daten.

--> Es ist Sache des Programmierers eine Datei in sinnvollen Portionen zu

lesen bzw. zu schreiben.

(byte- weise, zeilenweise, satzweise, blockweise)

--> Höher entwickelte Konzepte wie Dateizugriffsmethoden sind in C (UNIX)

nicht enthalten

zB.: ISAM " Index sequential accessing method"

Dateiorganisation – Dateizugriffe Dateien
 
Textdateien Binärdateien
  • sinnvoll einschaubar mit einem ASCII- Editor 
  • druckbar 
  • bestehen aus Zeilen ("Datensätzen") unterschiedlicher Länge.
  • alles andere, was nicht Textdatei ist.

  •  

     
     
     
     
     
     
     

    zB.: *.DOC

    Grafikdateien

    Sounddateien

    *.OBJ

    *.EXE

    besonders interessant sind Datein, die aus lauter Sätzen gleicher Länge bestehen.

    Naheliegend: 

    Struktur ^ Datensatz

    So eine Datei kann sinnvoll in Portionen sizeof (Struktur) Bytes gelesen/ geschrieben werden. In diesem Fall kann der Abstand des n- ten Stzes vom Dateianfang berechnet werden:

    1. soll auf das Datenelement n zugegriffen werden, so müssen vorher die

    2.  

       
       
       
       
       
       
       

      n – 1 Datenelemente ( sätze) die davor stehen (über- ) lesen werden.

    3. Jede Atrt Datei kann sequentiell verarbeitet werden.
    4. Textdateien können nursequentiell verarbeitet werden
    0 1 2 3 4 5 6 7 8 9 Datei

    Anfang n

    n * sizeof(Struktur) Einfacher Ansatz: index – Sequentiell Index mit kleinem Sätzen


    ( wenig Daten) wird sequentiell

    gelesen



     
    KdNR Nname Satznr 

    197

    Müller 3940

    315

    Maier 4712

    420

    Schmidt 4798

     


    Allgemeines Procedere bei Dateizugriffen
    1. Datei öffnen fopen()
    2. lesen oder schreiben
    3. Datei schließen fclose()
    Begriffsklärung:

    File – Pointer , Datentyp: File *

    Pointer auf den Datentyp FILE, der vom Compilerhersteller in <stdio.h> vordefi-

    niert ist.

    typedef struct

    {

    -------;

    -------;

    } FILE;
     
     

    Beim erfolgreichen öffnen einer Datei gibt fopen() einen Wert vom Typ FILE* zurück, der ungleich NULL ist. Alle weiteren Zugriffe auf die geöffnete Datei einschließlich fclose() gehen über diesen "File- Pointer",

    Satzzeiger

    Repräsentiert die aktuelle Schreib/Leseposition in einer geöffneten Datei.

    Datentyp: long.

    Der Satzzeiger enthält die aktuelle Schreib/Leseposition als ganze Zahl, es ist der Abstand zum Dateianfang in Bytes.

    Anzahl der gelesenen / geschriebenen Bytes in richtung Dateiende. fopen() Datei öffnen

    String String

    FILE * fopen(char *, char *);




     
     

    ! = NULL,

    wenn ok, im

    Fehlerfall ein NULL-

    pointer. sollte unbedingt

    abgefragt werden

    Bsp.: "TEST.DAT"

    "home / usr25 / c / daten / test..dat" UNIX

    "D: \\ c \\ daten \\ test.dat DOS/WIN

    FILE * dz

    dz = fopen("Test.dat","w");

    if(!dz)

    {

    "Fehler.....

    }
     
     

    fopen() Modus und Rechte
     

    Satz in einer Binärdatei ändern (update) --> öffnen mit "rb+"

    fopen() Datei öffnen

    fclose() Datei schließen


    int fclose( FILE *);

    Hinweis: wird das Programm mit exit() beendet, so werden "vergessene"

    Dateien noch korrekt geschlossen.

    #include <stdio.h>

    void main()

    {

    FILE * dz;

    dz = fopen("TEST.DAT","r");

    if( !dz ) {printf("Kann TEST.DAT nicht öffnen\n");

    exit (1); }

    Lesezugriffe

    fclose( dz );

    exit(0), } Zeichenweise I/O

    int fgetc(FILE *);
     
     

    gelesenes Zeichen

    EOF deutet auf Dateiende hin. Nur sicher bei Textverarbeitung

    Bsp. Aufruf: x = fgetc(dz);

    int fputc(int, FILE *);
     

    Bsp. Aufruf: fputc (`a‘,dz );

    fputc ( x , dz );

    Blockweise schreiben und lesen size_t fread( void *, size_t, size_t, FILE *)

    size_t:

    je nach Implementierung (Compiler) int oder unsigned, Name des Datentyps, den sizeof() zurückgibt. (ANSI- C)

    Adresse des Puffers, der die Daten aufnimmt, oft die Adresse einer Strukturvariablen.


    void * ist nach ANSI- C der allgemeine Pointer. Er wird verwendet,wenn nicht

    festgelegt ist, auf welche Art Daten im Einzelfall gezeigt wird.


    In K&R wird als allgemeiner Pointer char * verwendet.
     
     

    size_t Größe eines Datensatzes in Bytes, oft Größe einer Struktur.

    Anzahl der zu lesenden Datensätze

    Anzahl der tatsächlich gelesenen Sätze

    size_t fwrite( void *, size_t, size_t, FILE *)

    Adresse des Puffers, der die zu schreibenden Daten enthält, oft die Adresse einer Strukturvariablen.

    Größe eines Datensatzes

    Anzahl der zu schreibenden Datensätze.

    Anzahl der tatsächlich geschriebenen Datensätze.
     
    Datendateien: Quelltexte:
    KOMPO.DAT KOMPO_L?.C
    SOLI.DAT  

     
     

    Funktionen rund um den "Satzzeiger"

    fseek(): "Satzzeiger" bewegen

    int fseek(FILE *, long, int);
     

    Datei
     
     

    Anfang Ende

    akt. Position

    Bsp.: fseek ( dz , -sizeof ( komp_T ) , SEEK_CUR ) ;

    ab akt, Position 1 Datensatz Richtung Dateianfang

    rewind(): "Satzzeiger" auf Dateianfang zurück

    void rewind(FILE *); Dateibezug

    entspricht: fseek(dz, 0, SEEK-SET);

    ftell(): "Satzzeiger" auslesen

    long ftell(FILE *); Dateibezug


    Bsp: Anzahl der Sätze in KOMPO.DAT ermitteln

    FILE * dz;

    long l,n;

    dz=fopen("kompo.dat","rb");

    if(!dz) { printf("Fehler.\n"); exit(!);

    fseek(dz , 0 , SEEK-END);

    l= ftell(dz); Dateilänge in Bytes

    n=l/sizeof(kompo_T);

    printf("KOMPo.DAT %ld Bytes %ld Sätze\n",l,n);

    printf("Satzlgröße: %d\n", sizeof(kompo_T));

    rewind(dz);
     
     

    int size_t, hier unsigned

    fseek(dz,(long) i*sizeof(kompo_t),SEEK_SET);

    Typerzwingung

    long

    *sizeof(kompo_T)

    long 32 bit---[2.147.483.648....+2.147.483.647]

    Übungsvorschläge:

    1. Für den Datenbestand SOLI.DAT Programme der Art erstellen wie für KOMPO.DAT vorhanden
    2. Inhalt von KOMPO.DAT in ein ASCII- Format konvertieren, das von andeen Programmen (zb. Excel od. Informix) gelesen werden könnte.--> neue Datei

    3.  

       
       
       
       
       
       
       

      KOMPO.ASC mit fogendem Aufbau:

      1 Satz pro Zeile, Trennzeichen zwischen den Datenfeldern ist:‘|‘ .

      Bsp.: 5 | Beethoven | ludwig van | 1770 | 1827 |

      Diese Datei nach EXCEL importieren als "DOS / OS2 Textdatei, Trennzeichen: | "

    4. dto. output ist ein SQL- skript, das Sätze in eine Tabelle namens KOMPO in eine

    5.  

       
       
       
       
       
       
       

      SQL- Datenbank einfügen kann.

      Bsp.: INSERT INTO KOMPO VALLUES(5,‘Beethoven‘,‘Ludwig van‘,‘1770‘,‘1827‘);

    6. Pgm, mit dem ein Satz neu erfasst und an KOMPO.DAT angehängt werden kann.
    7. Pgm, mit dem das Datenerement flag bei einem Datz aus KOMPO.DAT gezielt auf 0 gesetzt werden kann. = "logisches löschen".