Aufgabenkomplex: Programmieren in C (Teil 2 von 2) (Strukturierte Datentypen: Felder, Strukturen, Zeiger; Funktionen mit Parameterübergabe; Dateiarbeit) - Lösungen 1. Eindimensionale Felder 1.1) Summe von n reellen Messwerten /*Summe von n (n>=1) reellen Messwerten; n bekannt; Datenmodell:Einlesen der Messwerte in ein eindim. Feld (Vektor); Steuerstruktur: Zählschleife */ #define DIMENSION 100 void main(void) int i,n; double x[dimension],sum; printf("anzahl der reellen Messwerte (anzahl>=1): "); scanf("%d",&n); for(i=0;i<=n-1;i=i+1) /* i=i+1 entspricht ++i */ printf("%d. reelle Zahl: ",i+1); scanf("%lf",&x[i]); sum=0; for(i=0;i<=n-1;i=i+1) /* i=i+1 entspricht ++i */ sum=sum+x[i]; printf("\nsumme = %g\n\n",sum); 1.2) Eindimensionales Feld aus Zufallszahlen /* wegen printf() */ #include <stdlib.h> /* wegen srand und rand */ #include <time.h> /* wegen time */ int zahl[100],i; srand( (unsigned)time(null) ); for (i=0;i<100;i++) zahl[i]= rand()%100; printf("100 Zufallszahlen zwischen 0 und 99:\n"); for (i=0;i<100;i++) printf("%i\t", zahl[i]); printf("\n"); 1
*1.3 Maximum, Minimum, Mittelwert und Streuung #include <stdlib.h> #include <time.h> int zahl[100],i; double mw,var,max,min; srand((unsigned)time(null)); for (i=0;i<100;i++) zahl[i]= rand()%100; for (i=0;i<100;i++) printf("%i\t", zahl[i]); max=min=zahl[0]; for (i=1;i<100;i++) if (zahl[i]>max) max=zahl[i]; else if (zahl[i]<min) min=zahl[i]; mw=var=0; for (i=0;i<100;i++) mw=mw+zahl[i]; var=var+zahl[i]*zahl[i]; mw=mw/100; var=(var-100*mw*mw)/99; printf("\nmaximum=%g, Minimum=%g ",max,min); printf("\nmittelwert=%g, Varianz=%g\n\n",mw,var); 1.4 Verschachtelte Zählschleifen /* Doppelsumme */ int i,j,n,dopsum; printf("n = "); scanf("%d",&n); dopsum=0; for (i=2;i<=n;++i) for (j=1;j<=i;++j) dopsum=dopsum+(i+j)*(i+j); printf("doppelsumme = %d\n\n",dopsum); 2
1.5 Ausgabe eines Musters aus Sternen /* Zahlendreieck */ int i,j; for (i=1;i<=20;++i) for (j=1;j<=i;++j) printf("*"); printf("\n"); *1.6 Einfaches Ratespiel ( 1 aus 90 ) /* Zahlenratespiel mit Zufallszahlengenerator: Erraten einer Zahl aus dem Bereich [1,90] */ /* wegen printf() und scanf() */ #include <stdlib.h> /* wegen srand und rand */ #include <time.h> /* wegen time */ #include <conio.h> /* wegen getch */ #include <ctype.h> /* wegen toupper */ #define OBERGRENZE 90 int geraten,gesucht,anzahl; char antw; do printf("\n\n****beginn eines neuen Spieles****\n"); srand( (unsigned)time(null) ); /* zuf. Initialisierung des Zufallszahlengenerators mit der aktuellen Zeit als "seed"="keim"; da die Zeit nicht gespeichert werden soll, wird der leere Zeiger NULL uebergeben */ gesucht=rand()%obergrenze+1; printf("\nraten Sie die zufaellig gewaehlte ganze Zahl" "\n aus dem Bereich [1,%d]: ",OBERGRENZE); scanf("%d",&geraten); anzahl=1; while (geraten!=gesucht) if (geraten<gesucht) printf("\n%d ist zu klein",geraten); else printf("\n%d ist zu gross",geraten); printf("\nraten Sie noch einmal: "); scanf("%d",&geraten); ++anzahl; /* aequivalent zu anzahl=anzahl+1 */ 3
printf("\nbeim %d-ten Male richtig geraten\n--> ",anzahl); switch (anzahl) case 1: case 2: printf("super!!!");break; case 3: case 4: printf("sehr gut!");break; case 5: printf("gute Leistung");break; case 6: case 7: case 8: printf("mittelmeassige Leistung");break; default:printf("schwach. Sie muessen sich steigern."); printf("\n\nnoch einmal spielen? (J/N):\n"); antw=getch(); /*getch liest ein Zeichen direkt von Tastatur (also kein <ENTER> notwendig) ohne Bildschirmecho*/ while (toupper(antw)=='j'); /*toupper wandelt Klein- in Grossbuchstaben um*/ 2. Funktionen (mit Parameterübergabe) Hinweis: In den Aufgaben des Abschnitts 2 ist nicht mit globalen Variablen, sondern nur mit lokalen Variablen zu arbeiten. 2.1.a) Volumen und der Oberfläche einer Kugel in gesonderten Funktion #define PI 3.14159 /* Def. von PI als symbolische Konstante */ double ober(double r) /* Definition der Funktion ober */ double s; /* Vereinbarung einer lokalen Variablen s */ s=4*pi*r*r; return s; double vol(double r) /* Definition der Funktion vol */ double v; /* Vereinbarung einer lokalen Variablen v */ v=4.0/3.0*pi*r*r*r; /* Achtung: 4/3 ergaebe das ganzzahlige Resultat 1 */ return v; /* "Hauptprogramm"; hier beginnt zur Laufzeit die Abarbeitung */ double s,v,r; printf("\nreellen Radius eingeben: ");scanf("%lf",&r); s=ober(r); v=vol(r); printf("\n Oberflaeche = %10.2lf",s); printf("\n Volumen = %10.2lf\n\n",v); 4
2.1.b) wie 2.1.a), aber jetzt mit Funktions-Prototypen: #define PI 3.14159 /* Def. von PI als symbolische Konstante */ double ober(double); /* Prototyp der Function ober */ double vol (double); /* Prototyp der Function vol */ /* "Hauptprogramm"; hier beginnt zur Laufzeit die Abarbeitung */ double s,v,r; printf("\nreellen Radius eingeben: "); scanf("%lf",&r); s=ober(r); v=vol(r); printf("\n Oberflaeche = %10.2lf",s); printf("\n Volumen = %10.2lf\n\n",v); double ober(double r) /* Definition der Funktion */ double s; s=4*pi*r*r; return s; double vol(double r1) /* Definition der Funktion */ double v1; v1=4.0/3.0*pi*r1*r1*r1; /* Achtung: 4/3 ergibt das ganzzahlige Resultat 1 */ return v1; 5
2.2 Summe von Fakultäten in gesonderter Function (mehrfacher Aufruf) double fak(int n) int i; double f; f=1; for (i=1;i<=n;++i) f=f*i; return f; /*****************************************************************/ double z; int a,b,c; printf("eingabe von a, b und c: "); scanf("%i%i%i",&a,&b,&c); z=fak(a)+fak(b)+fak(c); printf("%i! + %i! + %i! = %g\n\n",a,b,c,z); *2.3 Summe von Fakultäten in gesonderter Function (jetzt rekursiver Algorithmus) double fak(int n) double f; if (n==0) f=1; else f=n*fak(n-1); return f; /*****************************************************************/ double z; int a,b,c; printf("eingabe von a, b und c: "); scanf("%i%i%i",&a,&b,&c); z=fak(a)+fak(b)+fak(c); printf("%i!+%i!+%i!=%g\n\n",a,b,c,z); 6
2.4 Übergabe von Feldern (Einlesen bei unbekanntem n; Endeerkennung) /*Summe von n (n>=1) reellen Messwerten;n UNBEKANNT*/ #define DIMENSION 100 double summe(double x[], int anz) double sum; int i; /* Vereinbarung lokaler Variablen */ sum=0; for(i=0;i<=anz-1;i=i+1) /* i=i+1 entspricht ++i */ sum=sum+x[i]; return sum; void main(void) int i,n; double x[dimension],sum, ende; printf("endeerkennungszeichen = "); scanf("%lf",&ende); i=0; do printf("%i. reller Wert = ",i+1); scanf("%lf",&x[i]); i=i+1; while (x[i-1]!=ende); n=i-1; sum = summe(x,n); printf("\nsumme = %g\n\n",sum); 7
2.5 Maximum, Minimum, Mittelwert und Streuung von n reellen Messwerten /*Prototypen:*****************************************************/ int eingabe(double []); void ausgabe(double [],int); double maximum(double [],int); double minimum(double [],int); double summe (double [],int); void sort (double [],int); /*******************************************/ double x[100],y[100], max,min,mw,st; int n,i; n=eingabe(x); printf("\nunsortierte Ausgabe der eingelesenen Werte:\n"); ausgabe(x,n); max=maximum(x,n); min=minimum(x,n); mw =summe(x,n)/n; for (i=0;i<n;i++) y[i]=(x[i]-mw)*(x[i]-mw); st=summe(y,n)/(n-1); printf("\n\nmaximum = %g, Minimum = %g\n", max,min); printf( sort(x,n); printf("sortierte Ausgabe der Messwerte:\n"); ausgabe(x,n); printf("\n"); "Mittelwert = %g, Streuung = %g\n\n",mw,st); /*****************************************************************/ int eingabe(double x[]) int i,n; double ende; printf("endeerkennung = ");scanf("%lf",&ende); i=0; do printf("%i.wert = ",i+1); scanf("%lf",&x[i]); i=i+1; while (x[i-1]!=ende); n=i-1; return n; /*****************************************************************/ 8
void ausgabe(double x[],int n) int i; for (i=0;i<n;i=i+1) printf("%i. Wert = %g\n",i+1,x[i]); /*****************************************************************/ double maximum(double x[],int n) int i; double max; max=x[0]; for (i=1;i<n;i=i+1) if (x[i]>max) max=x[i]; return max; /*****************************************************************/ double minimum(double x[],int n) int i; double min; min=x[0]; for (i=1;i<n;i=i+1) if (x[i]<min) min=x[i]; return min; /*****************************************************************/ double summe(double x[],int n) int i; double s; s=0; for (i=0;i<n;i=i+1) s=s+x[i]; return s; /*****************************************************************/ void sort(double x[],int n) /* fakultative Aufgabe */ int i,j,imin; double min; for (j=0;j<n-1;j=j+1) min=x[j]; imin=j; for (i=j+1; i<n; i=i+1) if (x[i]<min) min=x[i]; imin=i; x[imin]=x[j]; x[j]=min; 9
3. Strukturen 3.1 Struktur für eine Bestellung /* Struktur fuer EINE Bestellung */ struct bestellung char datum[11]; int anummer, szahl; double preisps; ; struct bestellung b; printf("datum (Form: tt.mm.jjjj):\t");scanf("%s",&b.datum); printf("artikelnummer:\t\t\t"); scanf("%i",&b.anummer); printf("stueckzahl:\t\t\t"); scanf("%i",&b.szahl); printf("preis pro Stueck (Euro):\t"); scanf("%lf",&b.preisps); printf("\nihre Bestellung lautet:\n"); printf("%s\t%i\t%i\t%0.2f Euro\n\n",b.datum,b.anummer, b.szahl,b.preisps); ------------------------------------------------------------------------------------------------------------------------ 3.2/3.3 Erweiterung: Feld von Strukturen (max. 10 Bestellungen)/Gesamtpreis struct bestellung char datum[11]; int anummer, szahl; double preisps; ; struct bestellung b[10]; int i, n; double gespreis; printf("anzahl der Bestellungen ( <=10 ) = "); scanf("%i",&n); for (i=0; i<n; i++) printf("\ndatum:\t\t\t\t"); scanf("%s",&b[i].datum); printf("artikelnummer:\t\t\t"); scanf("%i",&b[i].anummer); printf("stueckzahl:\t\t\t"); printf("preis pro Stueck (Euro):\t"); scanf("%lf",&b[i].preisps); 10 scanf("%i",&b[i].szahl); gespreis=0; printf("\nausgabe der Bestellungen:\n"); for (i=0;i<n;i++) printf("%s\t%i\t%i\t%0.2f Euro\n", b[i].datum,b[i].anummer,b[i].szahl,b[i].preisps); gespreis = gespreis+b[i].szahl * b[i].preisps; printf("\ngesamtpreis = %0.2f Euro\n\n", gespreis);
3.4* Weitere Erweiterung struct bestellung char datum[11]; int anummer, szahl; double preisps; ; struct bestellung b[10]; int i,n,ant; double mb; printf("anzahl der Bestellungen ( <=10 ) = "); scanf("%i",&n); for (i=0;i<n;i++) printf("\ndatum:\t\t\t"); scanf("%s",&b[i].datum); printf("artikelnummer:\t\t"); scanf("%i",&b[i].anummer); printf("stueckzahl:\t\t"); scanf("%i",&b[i].szahl); printf("preis pro Stueck:\t");scanf("%lf",&b[i].preisps); printf("\neingabe:\n 1 - Ausgabe aller Bestellungen" "\n 2 - Ausgabe der Bestellungen ab best. Mindestbetrag\n"); scanf("%i",&ant);printf("\n"); if (ant==1) for (i=0;i<n;i++) printf("%s\t%i\t%i\t%0.2f Euro\n", b[i].datum,b[i].anummer,b[i].szahl,b[i].preisps); else printf("mindestbetrag = ");scanf("%lf",&mb);printf("\n"); for (i=0;i<n;i++) if (b[i].szahl*b[i].preisps>=mb) printf("%s\t%i\t%i\t%0.2f Euro\n", b[i].datum,b[i].anummer,b[i].szahl,b[i].preisps); 11
4. Mehrdimensionale Felder 4.1 Matrixberechnungen /* Matrixberechnungen */ #include <stdlib.h> #include <time.h> int mat[5][8], maxi[5], i, j, n, m, max, min; srand((unsigned)time(null)); printf("anzahl der Zeilen : "); scanf("%i",&n); printf("anzahl der Spalten: "); scanf("%i",&m); for (i=0; i<n; i++) for (j=0;j<m;j++) mat[i][j]= rand()%100; printf("\nzufaellig generierte Matrix:\n"); for (i=0;i<n;i++) for (j=0;j<m;j++) printf("%i\t", mat[i][j]); printf("\n"); max = min = mat[0][0]; for (i=0; i<n; i++) for (j=0; j<m; j++) if (mat[i][j] > max) max=mat[i][j]; else if (mat[i][j] < min) min=mat[i][j]; printf("\nmaximum = %i, Minimum = %i ",max,min); for (i=0; i<n; i++) maxi[i] = mat[i][0]; for (j=1;j<m;j++) if (mat[i][j] > maxi[i]) maxi[i]=mat[i][j]; for (i=0;i<n;i++) printf("\nmaximum[%i,*] = %i",i,maxi[i]); printf("\n\n"); 12
*4.2 Matrizenmultiplikation double a[20][20], b[20][20], c[20][20]; int m, n, k, l, i, j, p; do printf("\nfuer a und b gilt: Zeilenanzahl<=20, Spaltenanzahl<=20"); printf("\nausserdem: (Spaltenanzahl von a)=(zeilenanzahl von b)\n\n"); printf("eingabe fuer a: Zeilenanz., Leerz., Spaltenanz.: "); scanf("%i%i",&m,&n); printf("eingabe fuer b: Zeilenanz., Leerz., Spaltenanz.: "); scanf("%i%i",&l,&k); while (l!=n m>20 n>20 k>20); printf("zeilenweise Eingabe der reellen (%i,%i)-matrix a:\n",m,n); for (i=0; i<m; i++) for (j=0;j<n;j++) printf(" Eingabe von a[%i,%i]: ",i,j); scanf("%lf",&a[i][j]); printf("\nzeilenweise Eingabe der reellen (%i,%i)-matrix b:\n",n,k); for (i=0; i<n; i++) for (j=0;j<k;j++) printf(" Eingabe von b[%i,%i]: ",i,j); scanf("%lf",&b[i][j]); /* Berechnung der Produktmatrix:*/ for (i=0; i<m; i++) for (j=0;j<k;j++) c[i][j]=0; for (p=0;p<n;p++) c[i][j]=c[i][j]+a[i][p]*b[p][j]; printf("\nzeilenweise Ausgabe der (%i,%i)-produktmatrix c:\n",m,k); for (i=0; i<m; i++) for (j=0;j<k;j++) printf("%.2lf\t",c[i][j]); printf("\n"); 13
5. Zeiger 5.1a)b) Erweiterung des gegebenen C-Programms /* Tests mit Zeigern: Vereinbarung, Adressoperator "&" und Dereferenzierungsoperator "*" */ int a,b,c; int *pa,*pc; a = 2; pa = &a; /* pa zeigt auf a (ist Zeiger auf a); mittels *pa kann auf a zugegriffen werden. --> Mit Hilfe des Dereferenzierungsoperators "*" erhaelt man aus einem Zeiger, der Referenz auf ein Objekt, das Objekt selbst. */ printf("a=%i pa=%i *pa=%i \n", a, pa, *pa); *pa = 5; printf("a=%i pa=%i *pa=%i \n", a, pa, *pa); /* 5.1.b) Erweiterung von 5.1.a: */ printf("\neingabe einer zweiten ganzen Zahl: b = "); scanf("%i",&b); pc= &c; *pc= *pa+b; printf("\n Summe mit / ohne Zeiger:\n *pc=%i c=%i\n\n", *pc, c); 5.2 int func(double x, double y, double *pz1, double *pz2) int error; error = 0; if (y!= 0) *pz1 = x / y; else error = 1; *pz2 = x * y; return error; double a, b, c, d; int error; printf("zwei reelle Zahlen a und b eingeben: "); scanf("%lf%lf",&a,&b); error = func(a, b, &c, &d); /* a und b sind Eingangsparameter der Funktion func, c und d sind in func berechnete Resultatparameter */ if (error == 0) printf("\nquotient: a/b = %g\n",c); else printf("\nfehler: Division durch 0\n"); printf("produkt: a*b = %g\n\n",d); Zur ersten Frage in 5.2: Die Resultatrückgabe ist nur mit Zeigern als formale Parameter möglich, d.h. ein Verzicht auf Zeiger ist nicht möglich. 14
5.3 Resultatrückgabe über Parameterliste /* Funktionen mit Zeiger - Kugelberechnung Resultatrueckgabe durch "call by reference" */ #define PI 3.14159 /*******************************************************/ void berech(double r,double *vol,double *ober) /* Formale Parameter: - in r wird der uebergebene Wert gespeichert ("Call by value") - an vol und ober werden die Adressen von v und o uebergeben; Wertzuweisungen an *vol und *ober werden folglich in die Speicherbereiche von v und o eingetragen ("Call by reference") */ *ober = 4*PI*r*r; *vol = 4.0/3.0*PI*r*r*r; /*******************************************************/ void main(void) double r,v,o; printf("reellen Radius eingeben: "); scanf ("%lf",&r); berech(r,&v,&o); /* Funktionsaufruf; Parameter: r Eingangsparameter --> Wert wird uebergeben v, o Resultatparameter --> Adressen &v und &o uebergeben */ printf("\noberflaeche: %10.2lf",o); printf("\nvolumen: %10.2lf\n\n",v); 15
*5.4 Dynamische Reservierung von Speicherplatz /* DYNAMISCHE Reservierung von Speicherplatz fuer ein Messwertfeld mit Hilfe der Funktion malloc() aus <stdlib.h> */ #include <stdlib.h> double *x, s, max; int i, n; printf("anzahl der Messwerte: "); scanf("%i",&n); x = (double*) malloc (n*sizeof(double)); /* Erklaerung: malloc() reserviert n*sizeof(double) Bytes und gibt void-zeiger auf diesen Speicherbereich zurueck (im Fehlerfall: Zeiger NULL wird zurueckgegeben). Der void-zeiger muss bei Zuweisung implizit in den gewuenschten Zeigertyp konvertiert werden */ printf("\neingabe des reellen Messwertfeldes:\n"); for (i=0; i<n; i++) printf("x[%i] = ",i+1); scanf("%lf",&x[i]); printf("\nkontrollausgabe der eingelesenen Werte:\n"); for (i=0;i<n;i++) printf("%g\t", x[i]); printf("\n"); s=max=x[0]; for (i=1; i<n; i++) s=s+x[i]; if (x[i]>max) max=x[i]; printf("\nresultate:\n Maximum = %g, Summe = %g\n\n",max,s); /* Hinweis: Dynamischer Speicher kann im Programm mit free() wieder dynamisch freigegeben werden */ ------------------------------------------------------------------------------------------------------------------------ 16
6. Dateiarbeit (Der Datentyp File) 6.1 Dateiarbeit (Datentyp File) /* Beispiel fuer die Dateiarbeit (mit Dateityp FILE) */ void main () FILE *fp; /* Vereinbarung eines File-Pointers fp, der auf eine Struktur vom (in <stdio.h> definierten) Typ FILE zeigt. Eine solche Struktur vom Typ FILE wird beim Oeffnen einer Datei mit fopen () automatisch angelegt und enthaelt Informationen ueber die Datei.*/ char zeichen; fp = fopen("l:\\prog_c\\geheim.txt","r"); /* Achtung: Dieser Pfad gilt nur fuer den PC-Pool Weisbach-Bau. Im PC-Pool Rammlerbau ist stattdessen zu verwenden: fp = fopen("y:\\lehre\\prog_c\\geheim.txt","r"); - Mit fopen() wird die existierende Datei geheim.txt zum Lesen ("r") geoeffnet. - In C ist in Zeichenketten "\" als "\\" zu schreiben. - Der Return-Wert von fopen() ist ein Zeiger ("File-Pointer") auf die Struktur vom Typ FILE, die von fopen() fuer die entsprechende Datei eingerichtet wurde. Im Fehlerfall (z.b. falls der Dateiname falsch ist) wird der NULL-Zeiger zurueckgegeben. */ if ( fp == NULL) printf("fehler: Zu oeffnende Datei existiert nicht\n\n"); else while (!feof(fp)) /* solange nicht das Datei-Ende erreicht ist */ fscanf(fp,"%c",&zeichen); /* oder alternativ: zeichen=fgetc(fp); */ /* fgetc(fp) liest ein Zeichen von der akt. Position */ switch (zeichen) case 'e': zeichen='l'; break; case 'l': zeichen='e'; break; case 'a': zeichen='r'; break; case 'r': zeichen='a'; break; case 't': zeichen='s'; break; case 's': zeichen='t'; break; printf("%c",zeichen); /*Ausgabe des entschluesselten Texts auf Bildschirm*/ /* Ende der if-anweisung */ fclose(fp); /* Schliessen der Datei, auf die ueber fp zugegriffen wird */ 17