Strukturen und Dateien 8-1
Strukturierte Datenobjekte, die in C zur Verfügung stehen, heißen Strukturen (records) und Unions Definition: Eine Struktur (struct) implementiert ein heterogenes Feld, das aus mehreren Komponeten unterschiedlicher Typen und unterschiedlicher Größe besteht. Beispiel: struct erste_struktur nr bezeichnung preis 8-2
Definition im Programm besteht aus der Deklaration der sog. Schablone der Struktur und der Definition von konkreten Strukturen (strukt. Variablen). Beispiel: Deklaration der Schablone der Struktur erste_struktur : struct erste_struktur { int nr; char bezeichnung[16]; double preis; Definition der Strukturen vom Typ: erste_struktur : struct erste_struktur REC1, REC2, HILF; 8-3
Definition kann auch gemeinsam (in einem Schritt) ausgeführt werden: struct erste_struktur { int nr; char bezeichnung[16]; double preis; REC1, REC2, HILF; Syntax der Deklaration: struct [<Name der Struktur>] { Deklaration der Komponente1; Deklaration der Komponente2;... ; 8-4
Strukturen können auch mit Initialisierung definiert werden: struct person { int p_zahl; char nachname[12]; char vorname[10]; int geburtsjahr;... ; struct person P1 = {2483,"MEYER","Karl",1953,, P2 = {4417,"BROD","Max",1969,, P3 = {3659,"KLANG","Ute",1978, ; 8-5
Zugriff zu den Komponenten 1. Punkt Notation: P1.p_zahl = 2483; strcpy(p1.nachname, "MEYER"); strcpy(p1.vorname, "Karl"); P1.geburtsjahr = 1953;... 2. Über Zeiger: struct person *pp1;... (*pp1).p_zahl = 2483; strcpy((*pp1).nachname, "MEYER");... 8-6
3. Über Zeiger, mit -> Notation: struct person *pp1, *pp2, *pp3;... pp1->p_zahl = 2483; strcpy(pp1->nachname, "MEYER"); strcpy(pp1->vorname, "Karl"); pp1->p_zahl = 1953;... pp3->p_zahl = 3659; strcpy(pp3->nachname, "KLANG"); strcpy(pp3->nachname, "Ute"); pp3->p_zahl = 1978;... 8-7
Verwendung von Strukturen /* Programm C13_1.c Demonstration von Strukturen */ # include <stdio.h> # include <string.h> struct person { /* Struktur deklarieren */ char name [31]; char vorname [21]; char geburtsdatum [9]; /* Format JJJJMMTT */ char geschlecht; /* W M */ unsigned int kundennummer; ; void main ( ) { struct person kunde; /* Variable definieren */ 8-8
strcpy ( kunde. name, "Mayerhofer" ); /* Werte zuweisen */ strcpy ( kunde. vorname, "Dietmar" ); strcpy ( kunde. geburtsdatum, "19621023" ); kunde. geschlecht = 'M' ; kunde. kundennummer = 4711 ; printf (" \n Name : %s ", kunde. name ) ; /* Auf Struktur */ printf (" \n Vorname : %s ", kunde. vorname ); /* zugreifen */ printf (" \n Geburtsdatum: %s ", kunde. geburtsdatum ) ; printf (" \n Geschlecht : %c ", kunde. geschlecht ) ; printf (" \n Kundennummer: %i ", kunde. kundennummer ) ; printf (" \n\n " ); printf (" \n 1.Buchstaben: %c", kunde. vorname [0] ) ; printf (" %c ; ", kunde. name [0] ); printf (" Geschlecht = %s ", ( kunde. geschlecht == 'W' )? "weiblich" : "männlich") ; printf ( " \n\n " ) ; 8-9
/* Programm C13_1b.c Demonstration der Zuweisung von Strukturen */ # include <stdio.h> main ( ) { struct { char name [30] ; int alter ; a, b; strcpy (a. name, "Mayerhofer Kurt" ) ; a. alter = 21 ; b = a ; printf ( "\n Komponente b. name = %s ", b. name ) ; printf ( "\n Komponente b. alter = %i ", b. alter ) ; printf ( "\n\n" ) ; 8-10
Beispiel: Funktion für den Vertausch von Komponenten: #include <stdio.h> void tauschen (struct koor*); /* Funktions-Prototyp */ struct koor { /* Deklaration der Struktur-Schablone */ double xk; /* zwei Gleitkommakomponenten */ double yk; ; struct koor position = {12.34, 43.21; /* Definition */ void main() { printf("\nvorher %.2lf %.2lf", position.xk, position.yk); tauschen (&position); printf("\nnachher %.2lf %.2lf", position.xk,position.yk); 8-11
void tauschen (struct koor *werte) { double hilf; hilf = werte->xk; werte->xk = werte->yk; werte->yk = hilf; Ausgaben: Vorher 12.34 43.21 Nachher 43.21 12.34 8-12
Merkmale des Zugriffs zu den Strukturen Verweisungen auf die Strukturen und ihre Komponenten Gegeben sei eine einfache Struktur: struct ein { int x; /* ganzzahlige Komponente */ int *y; /* Zeiger auf ganzzahl. Variable */ *P; /* Zugriff über den Zeiger P */ /* Dynamische Erzeugung der Struktur */ 8-13
Dann können folgende Zugriffe verwendet werden: ++P->x; /* inkrementiert x vorm Zugriff */ (++P)->x; /* inkr. P vorm Zugriff zu x */ P->x++; /* inkrementiert x nach dem Zugriff */ P++->x; /* inkr. P nach dem Zugriff zu x */ *P->y; /* liefert Inhalt des Speicher- */ /* platzes, auf den y verweist */ *P->y++; /* inkrementiert y nach dem Zugriff */ /* zum Speicherplatz, auf den y verweist */ (*P->y)++; /* inkrementiert Inhalt des Spei- */ /* cherplatzes, auf den y verweist */ *P++->y; /* inkrementiert P nach dem Zugriff */ /* zum Speicherplatz, auf den y verweist */ 8-14
Verwendung von typedef : Syntax: typedef <Typdefinition> <Typbezeichner> ; Beispiel:... typedef unsigned short KURZ; main() { KURZ var1 = 135;... printf("%u", var1);... 8-15
Beispiel:... 8. Strukturen und Dateien typedef struct { /* Struktur deklarieren */ char name [31]; char vorname [21]; char geburtsdatum [9]; /* Format JJJJMMTT */ char geschlecht; /* W M */ unsigned int kundennummer; person; void main() { int i, j; person X, Y; /* Definition von zwei lokalen Strukturen */... 8-16
Beispiel: typedef struct { int warennr; char warenname[20]; float einzelpreis;... item; void main() { item W1, W2, *pw; 8. Strukturen und Dateien... W1.warennr = 4711; strcpy (W1.warenname, "Plotter");... pw->warennr = 6552; strcpy (pw->warenname, "Drucker");... 8-17
Unions Unions sind spezielle Formen von Strukturen Komponenten einer Union liegen übereinander, d.h. der Speicherplatz für jede Komponente der Union fängt an der gleichen Stelle (Adresse) an und immer nur eine der Komponenten kann gespeichert werden (eine momentan gespeicherte Komponente überschreibt die vorhergehende). Syntax: union [<Name der Union>] { Deklaration der Komponente1; Deklaration der Komponente2;... ; [<Name der definierten Union>]; 8-18
Beispiel: union { int ganzzahl; char name[10]; U1; Abspeicherung: union U1 ganzzahl name 8-19
Zuweisungen: strcpy (U1.name, "Schneider"); U1.ganzzahl = 1040; Inhalt der Union nach der Zuweisung strcpy (U1.name, "Schneider"); union U1 S c h n e i d e r \0 Inhalt der Union nach der Zuweisung U1.ganzzahl = 1040; union U1 00 00 04 10 e i d e r \0 8-20
Verwendung von Unions /* Programm C13_3.c - Ausgabe int in hexa (Funktion outih(x)) */ #include <stdio.h> void outih (short); /* Funktionsprototyp */ int main (void) { int eingabe; /* Variablen definieren */ char c; printf ("\n\t\t Ausgabe von INT Zahlen im Hexa-Zahlensystem"); printf ("\n\n Die integer-zahl eingeben (mit '0' beenden): "); scanf ("%i", &eingabe); /* Zahl eingeben */ while (eingabe!= 0) { printf (" Die Zahl %i ist in Hexa: ", eingabe); outih ((short)eingabe); /* Ausgabe in Hexa */ printf ("\n Die integer-zahl eingeben (mit '0' beenden):"); scanf ("%i", &eingabe); 8-21
printf ("\n\n"); return (0); void outih (short x) { union { unsigned short num; /* 16 bit integer */ unsigned char s[2]; /* array of hexa-characters */ val; char *p = "0123456789abcdef"; /* list of hexa-characters */ val.num = x; /* converted short value */ putchar (p[val.s[0] >> 4]); /* high byte conversion */ putchar (p[val.s[0] & 15]); putchar (p[val.s[1] >> 4]); /* low byte conversion */ putchar (p[val.s[1] & 15]); putchar ('\n'); 8-22
Zusammenfassung (Strukturen und Unions) Strukturen vereinfachen das Programmieren dadurch, dass sie zusammengehörenden Daten unter einem Variablennamen zusammenfassen. Strukturmitglieder (Komponenten) können nicht die Speicherklassen register, static oder void haben. Durch Zuweisung einer Struktur zu einer anderen können Arrays verdoppelt werden, was sonst nur mit der Funktion strcpy möglich ist. Strukturen können geschachtelt werden. Das heisst, in einer Struktur können wiederum andere Strukturen oder Unions erscheinen. Die Gesamtlänge einer Union ist gleich der Länge des größten Mitglieds (Komponente) dieser Union. Unions weden häufig eingesetzt, wenn innerhalb einer Struktur ein bestimmter Speicherbereich unterschiedliche Daten aufnehmen soll; diese Technik spart wertvollen Speicherplatz. 8-23
Dateien (Files) Datenstrukturen, die auf den externen Speichermedien gespeichert werden können. Sie ermöglichen effiziente Abspeicherung von großen Datenmengen. Sie besitzen verschiedene interne Organisationen. Sie werden mit speziellen Ein-/Ausgabeoperationen (Funktionen) behandelt: Definition der Datei Öffnen der Datei Lesen vo Daten Schreiben (Abspeichern) von Daten Schliessen der Datei 8-24
Vordefinerter Datentyp FILE: typedef struct { int level; /* fill/empty level of buffer */ unsigned flags; /* file status flags */ char fd; /* file descriptor */ unsigned char hold; /* ungetc char if no buffer */ int bsize; /* buffer size */ unsigned char *buffer; /* data transfer buffer */ unsigned char *curp; /* current active pointer */ unsigned istemp; /* temporary file indicator */ short token; /* used for validity checking */ FILE; /* this is the FILE object */ 8-25
Funktionen für die Bearbeitung von Dateien: Datei definieren: FILE *fp, *fp2, *fopen(); fp, fp2 sind Dateizeiger, über die die Dateien zugegriffen werden können fopen ist ein Prototyp der Funktion zum Öffnen der Datei Datei öffnen: <Dateizeiger> = fopen(<dateiname>, <Modus>); fp = fopen("abc.txt", "r"); fp2 = fopen("xyz.dat", "w"); Ein Zeichen von der Datei lesen: c = fgetc(fp); Modus: "r" "w" "a" 8-26
Ein Zeichen auf die Datei schreiben (aufzeichnen): fputc(c,fp); Ein record (struct) lesen: fscanf(<dateizeiger>, <Formatstring>, <Argumente>); fscanf(fp, "%i %s %lf", pw->nr, pw->name, pw->preis); Ein record aufzeichnen: fprintf(<dateizeiger>, <Formatstring>, <Argumente>); fprintf(fp, "%5i %s %8.2lf", pw->nr, pw->name, pw->preis); Eine Textzeile lesen: fgets(<textvariable>, <Länge>, <Dateizeiger>); fgets(pw->name, 20, fp); 8-27
Eine Textzeile aufzeichnen: 8. Strukturen und Dateien fputs(<textvariable>, <Dateizeiger>); fputs(pw->name, fp); Datei schliessen: fclose(fp); Beispiel: main () { FILE *datei_ptr; datei_ptr = fopen ("abc.txt", "w"); if (datei_ptr!= NULL) { fputs (pw->name, datei_ptr); fclose(datei_ptr); 8-28
/* Programm C11_1.c Demonstration des Kopierens einer Textdatei */ # include <stdio.h> main ( ) { char c; int count = 0; FILE *fopen ( ), *fr, *fw; fr = fopen ( "x.txt", "r" ); fw = fopen ( "y.txt", "w" ); while ( ( c = fgetc ( fr ) )!= EOF ) { count ++ ; fputc (c, fw); putchar (c); printf ("\n Insgesamt %i Zeichen wurden kopiert \n\n", count); fclose ( fr ) ; fclose ( fw ) ; 8-29
/* Programm C11_1a.c Demonstration des Kopierens einer Textdatei */ # include <stdio.h> main ( int argc, char *argv [ ] ) { char c; int count = 0; FILE *fopen ( ), *fr, *fw; if ( argc < 2 ) { /* ist kein Parameter vorhanden? */ printf ("\n Kein Kommandozeilen-Parameter gefunden! \n"); exit ( 1 ) ; if ( argc == 2 ) { /* nur ein Dateiname eingegeben */ printf ("\n Nur eine Datei eingegeben! \n"); exit ( 1 ) ; 8-30
fr = fopen ( argv [1], "r" ) ; fw = fopen ( argv [2], "w") ; while ( ( c = fgetc ( fr ) )!= EOF ) { count ++ ; fputc (c, fw); putchar (c); 8. Strukturen und Dateien printf ("\n Insgesamt %i Zeichen wurden kopiert \n\n", count); fclose ( fr ) ; fclose ( fw ) ; 8-31
# include <stdio.h> # include <stdlib.h> # define N 5 # define LS 5 typedef struct dat_satz { int num; char name[ls]; float e_preis; int anzahl; float ges_preis; item; int main ( void ) { int i, j; item TAB[N], BUFFER; FILE *f, *fopen ( ) ; 8-32
f = fopen ( "file1.dat", "r" ) ; printf ("\n Eingabe: \n"); i = 0; while (fscanf (f,"%d %s %f %d %f\n", &TAB[i].num, &TAB[i].name, &TAB[i].e_preis, &TAB[i].anzahl, &TAB[i].ges_preis)!= EOF) { i++; printf (" Der %d. Datensatz wurde eingelesen \n", i); fclose ( f ) ; f = fopen ( "file2.dat", "w" ) ; for ( i=0; i<n; i++) { fprintf ( f, "%3d ", TAB[i].num ) ; fprintf ( f, "%s ", TAB[i].name ) ; fprintf ( f, "%8.2f ", TAB[i].e_preis ) ; fprintf ( f, "%5d ", TAB[i].anzahl ) ; fprintf ( f, "%8.2f\n", TAB[i].ges_preis ) ; fclose ( f ) ;. 8-33
f = fopen ( "file2.dat", "r" ) ; printf ( "\n Ausgabe: \n" ) ; while ( fscanf ( f, "%d %s %f %d %f \n", &BUFFER.num, &BUFFER.name, &BUFFER.e_preis, &BUFFER.anzahl, &BUFFER.ges_preis)!= EOF) { printf (" %d ", BUFFER.num); printf (" %20s ", BUFFER.name); printf (" %8.2f ", BUFFER.e_preis); printf (" %5d ", BUFFER.anzahl); printf (" %8.2f", BUFFER.ges_preis); printf ("\n"); fclose ( f ) ; for (j = 0; j < i; j++) { printf ( "%d %s %f %d %f \n", TAB [ j ].num, TAB [ j ].name, TAB [ j ].e_preis, TAB [ j ].anzahl, TAB [ j ].ges_preis); return 0 ; 8-34
Bearbeitung von binären Dateien Datei definieren: FILE *fp, *fp2, *fopen(); gleich wie bei den Textdateien Datei öffnen: <Dateizeiger> = fopen(<dateiname>, <Modus>); Modus: "rb" "wb" "ab" fp = fopen("abc.dat", "rb"); fp2 = fopen("xyz.dat", "wb"); Aber: Daten lesen und speichern wir nach den binären Records, d.h. in gleicher Form, in der sie im Operationsspeicher gespeichert werden!!! 8-35
Dazu müssen weitere Angaben definiert und eingegeben werden. Diese Angaben sind: Länge des Record (record size) in Byte Anzahl der (gespeicherten) Records Ein record (struct) lesen: fread(<buffer-adresse>, <Record-size>, <Zahl von Records>, <Dateizeiger>); i = 0; while(n_item=fread(&tabelle[i],sizeof(tab_item),1,fp)!=0) i++; Ein record aufzeichnen: fwrite(<buffer-adresse>, <Record-size>, <Zahl von Records>, <Dateizeiger>); fwrite(tabelle, sizeof(tab_item), N, fp); 8-36
Beispiel: Kopieren von zwei Dateien #include <stdio.h> #define N 5 #define LS 20 typedef struct dat_satz { int num; char name[ls]; float e_preis; int anzahl; float ges_preis; item; int main (void) { int i, j, n_satz; item TAB[N], BUFFER; FILE *f, *fopen(); 8-37
f = fopen("file1.dat", "r"); printf ("\n Eingabe: \n"); i = 0; while (fscanf(f,"%d %s %f %d %f\n", &TAB[i].num, &TAB[i].name, &TAB[i].e_preis, &TAB[i].anzahl, &TAB[i].ges_preis)!= EOF) { i++; printf (" Der %d. Datensatz wurde eingelesen \n", i); fclose(f); f = fopen("file2.dat", "wb"); n_satz = 0; for (i=0; i<n; i++) n_satz += fwrite (&TAB[i], sizeof(item), 1, f); fclose(f); printf (" %i records wurden aufgezeichnet \n", n_satz); 8-38
f = fopen("file2.dat", "rb"); printf ("\n Ausgabe: \n"); while ((n_satz = fread (&BUFFER,sizeof(item),1,f))!= 0) { printf (" %d ", BUFFER.num); printf (" %-20s ", BUFFER.name); printf (" %8.2f ", BUFFER.e_preis); printf (" %5d ", BUFFER.anzahl); printf (" %8.2f", BUFFER.ges_preis); printf ("\n"); fclose(f); printf ("\n Demonstration End \n\n"); 8-39
Beispiel: Kopieren von zwei Dateien zweite Alternative #include <stdio.h> #define N 5 #define LS 20 typedef struct dat_satz { int num; char name[ls]; float e_preis; int anzahl; float ges_preis; item; int main (void) { int i, j, n_satz; item TAB[N], BUFFER; FILE *f, *fopen(); 8-40
f = fopen("bbb.txt", "r"); printf ("\n Eingabe: \n"); i = 0; while (fscanf (f,"%d %s %f %d %f\n", &TAB[i].num, &TAB[i].name, &TAB[i].e_preis, &TAB[i].anzahl, &TAB[i].ges_preis)!= EOF) { i++; printf (" Der %d. Datensatz wurde eingelesen \n", i); fclose(f); f = fopen("bbb2.dat", "wb"); n_satz = 0; for (i=0; i<n; i++) n_satz += fwrite (&TAB[i], sizeof(item), 1, f); fclose(f); printf (" %i records wurden aufgezeichnet \n", n_satz); 8-41
f = fopen("bbb2.dat", "rb"); printf ("\n Ausgabe: \n"); while ((n_satz = fread (&BUFFER, sizeof(item), 1, f))!= 0) { printf (" %d ", BUFFER.num); printf (" %-20s ", BUFFER.name); printf (" %8.2f ", BUFFER.e_preis); printf (" %5d ", BUFFER.anzahl); printf (" %8.2f", BUFFER.ges_preis); printf ("\n"); fclose(f); printf ("\n Demonstration End \n\n"); 8-42
Zusammenfassung (Dateien) Wir haben elf Funktionen kennengelernt, die der Bearbeitung von Dateien dienen. Sie stellen nur eine kleine Auswahl aus der Vielzahl der zur Verfügung stehenden Bibliotheksfunktionen dar: fopen Datei öffnen fclose Datei schliessen feof Prüfung auf Dateiende fseek Dateizeiger positionieren fgetc Einzelnes Zeichen lesen fgets Zeichenkette einlesen fputc Einzelnes Zeichen schreiben fputs Zeichenkette schreiben fscanf Daten formattiert einlesen fprintf Daten formattiert ausgeben (schreiben) remove Datei löschen 8-43