Programexempel från C-föreläsning 11, onsdag 16 december 2009 ============================================================= Idag: 1. Lite mer om funktioner 2. Filhantering med stdio-paketet 3. Binärfiler 1. Lite mer om funktioner ========================= Repetition: Parametrar och argument, formella och aktuella ---------------------------------------------------------- Funktion: void f(int x, float y, double z) { ... } Anrop: f(3, r, sqrt(r + 2)); x, y och z: "parametrar", "formella parametrar" 3, r och sqrt(r + 2): "argument", "aktuella parametrar" Ett anrop till: f(i, 2.0, 3.5 * a[i]); parametrar.c ------------ #include #include void f(int x, float y, double z) { printf("x = %d\n", x); printf("y = %f\n", y); printf("z = %f\n", z); } int main() { float r; int i; r = 6.2; i = 12; f(3, r, sqrt(r + 2)); f(i, 2.0, 3.0); return 0; } /* main */ parametrar-2.c -------------- #include #include double g(int x, float y, double z) { double summan; summan = x + y + z; return summan; } int main() { float r; int i; double resultat; r = 6.2; i = 12; resultat = g(3, r, sqrt(r + 2)); printf("resultat = %f\n", resultat); printf("resultat = %f\n", g(i, 2.0, 3.0)); return 0; } /* main */ Returnera flera värden ---------------------- 1. Pekare (exempel: scanf) 2. Globala variabler (exempel: errno) 3. Poster (se nedan) Poster som argument och returnerade värden -- helt okej ------------------------------------------------------- Arrayer som argument och returnerade värden -- se upp ----------------------------------------------------- Det som skickas respektive returneras är en pekare till första elementet i arrayen! Ex: en funktion som beräknar medelvärdet av en reell vektor Mer exempel ----------- Ex 1: Funktionen "udda", som returnerar sant om talet är udda (Gunnar 2. 5-7) Ex 2: Funktionen "swap" (som inte fungerar och som fungerar) Poster som argument och returnerade värden -- helt okej: punkter.c ------------------------------------------------------------------ #include #include #include #include struct Punkt { double x; double y; }; struct Punkt hitta_mitten(struct Punkt p1, struct Punkt p2) { struct Punkt resultat; resultat.x = (p1.x + p2.x) / 2; resultat.y = (p1.y + p2.y) / 2; return resultat; } int main(void) { struct Punkt ena = { -1, 1 }, andra = { 3, 3 }; struct Punkt mittpunkten; mittpunkten = hitta_mitten(ena, andra); printf("mittpunkten = ( %f, %f )\n", mittpunkten.x, mittpunkten.y); return EXIT_SUCCESS; } // main Arrayer som argument och returnerade värden -- se upp ----------------------------------------------------- Det som skickas respektive returneras är en pekare till första elementet i arrayen! Ex: en funktion som beräknar medelvärdet av en vektor med flyttal (Rita upp "talen" och "a") En funktion som beräknar medelvärdet av en vektor med flyttal ------------------------------------------------------------- #include double medel(double a[], int antal) { // Eller: *a int i; double summan = 0; for (i = 0; i < antal; ++i) summan += a[i]; if (antal > 0) // Eller inte? return summan / antal; else return 0; } int main() { double talen[] = { 3.2, 3.3, 3.4, 3.1, 3.1 }; printf("Medel = %f\n", medel(talen, 5)); return 0; } /* main */ Funktionen "swap" (som inte fungerar): swap-1.c ----------------------------------------------- #include void swap(int a, int b) { int temp; temp = a; a = b; b = temp; } int main() { int x = 7; int y = 13; printf("Före: x = %d, y = %d\n", x, y); swap(x, y); printf("Efter: x = %d, y = %d\n", x, y); return 0; } /* main */ Funktionen "swap" (som fungerar): swap-2.c ------------------------------------------ #include void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } int main() { int x = 7; int y = 13; printf("Före: x = %d, y = %d\n", x, y); swap(&x, &y); printf("Efter: x = %d, y = %d\n", x, y); return 0; } /* main */ arrayfel.c (om vi hinner) ------------------------- #include #include char* smart_fgets() { char s[100 + 1]; printf("Skriv en rad: "); fgets(s, sizeof s, stdin); int sista = strlen(s) - 1; if (s[sista] == '\n') s[sista] = '\0'; return s; } int main() { char *raden; raden = smart_fgets(); printf("Raden var: %s\n", raden); return 0; } /* main */ Körexempel ---------- Skriv en rad: Hej alla glada fotogenkaminer! Raden var: Hej alla glada fotogenkaminer! Kompileringsvarning ------------------- arrayfel.c: In function `smart_fgets': arrayfel.c:11: warning: function returns address of local variable 2. Filhantering med stdio-paketet ================================= "Ström" (datatypen FILE): transporterar data mellan programmets primärminne och sekundärminnet (normalt disken) Textström (vanligast, enklast): omvandlar mellan binära data (i primärminnet) och text (på sekundärminnet) Binärström: bara transporterar, utan omvandling filer-1.c --------- #include int main() { int tal = 130; printf("Nu är talet = %d\n", tal); FILE *tsut; tsut = fopen("tal.txt", "wt"); fprintf(tsut, "%d", tal); fclose(tsut); printf("Nu är talet = %d\n", tal); FILE *tsin; tsin = fopen("tal.txt", "rt"); fscanf(tsin, "%d", &tal); fclose(tsin); printf("Nu är talet = %d\n", tal); return 0; } /* main */ reellatal.txt ------------- 4.92927 8.52385 6.1061 5.49319 3.16384 6.47934 0.405324 3.10623 7.66471 4.43504 0.0 filmedel.c ---------- #include #include int main() { FILE *tsin; double talet, summan; int antal; tsin = fopen("reellatal.txt", "rt"); if (tsin == NULL) { printf("Kunde inte öppna filen.\n"); return EXIT_FAILURE; } summan = 0.0; antal = 0; fscanf(tsin, "%lf", &talet); while (talet != 0.0) { summan += talet; ++antal; fscanf(tsin, "%lf", &talet); } fclose(tsin); printf("Medel = %f\n", summan / antal); return EXIT_SUCCESS; } /* main */ filmedel-2.c ------------ #include #include int main() { FILE *tsin; double talet, summan; int antal; if ((tsin = fopen("reellatal.txt", "rt")) == NULL) { printf("Kunde inte öppna filen.\n"); return EXIT_FAILURE; } summan = 0.0; antal = 0; while (fscanf(tsin, "%lf", &talet) != EOF) { summan += talet; ++antal; } fclose(tsin); printf("Medel = %f\n", summan / antal); return EXIT_SUCCESS; } /* main */ Filen medlemmar.txt ------------------- 13 Olle Svensson 14 Svea Olofsson 17 Kajsa Karlsson Två körexempel -------------- Ange ett medlemsnr: 17 Medlemmens namn: Kajsa Karlsson Ange ett medlemsnr: 15 Medlemmen finns inte. medlemmar.c ----------- #include #include #include struct Medlem { int nr; char namn[40 + 1]; }; /* Returnerar en medlem med nummer 0 om filen är slut */ struct Medlem las_medlem(FILE* tsin) { struct Medlem m; if (fscanf(tsin, "%d", &m.nr) == EOF) { m.nr = 0; return m; } while (getc(tsin) != '\n') ; fgets(m.namn, sizeof m.namn, tsin); int sista = strlen(m.namn) - 1; m.namn[sista] = '\0'; return m; } int main() { FILE *tsin; if ((tsin = fopen("medlemmar.txt", "r")) == NULL) { printf("Kunde inte öppna filen.\n"); return EXIT_FAILURE; } int sokt_nr; printf("Ange ett medlemsnr: "); scanf("%d", &sokt_nr); struct Medlem m; m = las_medlem(tsin); while (m.nr != 0 && m.nr != sokt_nr) { m = las_medlem(tsin); } if (m.nr == sokt_nr) printf("Medlemmens namn: %s\n", m.namn); else printf("Medlemmen finns inte.\n"); return EXIT_SUCCESS; } /* main */ medlemmar-2.c (om vi hinner) ---------------------------- #include #include #include struct Medlem { int nr; char namn[40 + 1]; }; // Returnerar 1 om det gick att läsa, 0 annars int las_medlem(FILE* tsin, struct Medlem* mp) { if (fscanf(tsin, "%d", &mp->nr) == EOF) return 0; while (getc(tsin) != '\n') ; fgets(mp->namn, sizeof mp->namn, tsin); int sista = strlen(mp->namn) - 1; mp->namn[sista] = '\0'; return 1; } int main() { FILE *tsin; if ((tsin = fopen("medlemmar.txt", "r")) == NULL) { printf("Kunde inte öppna filen.\n"); return EXIT_FAILURE; } int sokt_nr; printf("Ange ett medlemsnr: "); scanf("%d", &sokt_nr); struct Medlem m; while (las_medlem(tsin, &m)) { if (m.nr == sokt_nr) { printf("Medlemmens namn: %s\n", m.namn); return EXIT_SUCCESS; } } printf("Medlemmen finns inte.\n"); return EXIT_SUCCESS; } /* main */ 3. Binärfil, binärström ======================= På en binärfil har man inte översatt data till text, utan kopierat bitmönstren som de ser ut i primärminnet till filen. För att skriva eller läsa en binärfil används en binärström, som inte gör någon konvertering. Funktioner: fread, fwrite Två sorters format: textformat och binärformat ---------------------------------------------- int tal = 130; Binärt: 0000 0000 0000 0000 0000 0000 1000 0010 (128) (2) (0) (0) (0) (130) (32-bitars heltal i big-endian-ordning, dvs MSB först) Som text: 0011 0001 0011 0011 0011 0000 (49 = '1') (51 = '3') (48 = '0') Annat binärt: 0100 0001 0000 0000 (2) (128) (130) (0) (16-bitars heltal i little-endian-ordning, dvs LSB först) binart.c -------- #include int main() { int tal = 130; printf("Nu är talet = %d\n", tal); FILE *bsut; bsut = fopen("tal.bin", "wb"); fwrite(&tal, sizeof(tal), 1, bsut); fclose(bsut); printf("Nu är talet = %d\n", tal); FILE *bsin; bsin = fopen("tal.bin", "rb"); fread(&tal, sizeof(tal), 1, bsut); fclose(bsin); printf("Nu är talet = %d\n", tal); return 0; } /* main */ medlemmar-binart.c ------------------ #include #include #include struct Medlem { int nr; char namn[40 + 1]; }; int main() { FILE *bsin; if ((bsin = fopen("medlemmar.bin", "rb")) == NULL) { printf("Kunde inte öppna filen.\n"); return EXIT_FAILURE; } int sokt_nr; printf("Ange ett medlemsnr: "); scanf("%d", &sokt_nr); struct Medlem m; while (fread(&m, sizeof m, 1, bsin) == 1) { if (m.nr == sokt_nr) { printf("Medlemmens namn: %s\n", m.namn); return EXIT_SUCCESS; } } printf("Medlemmen finns inte.\n"); return EXIT_SUCCESS; } /* main */ kopiera.c --------- #include #include #include struct Medlem { int nr; char namn[40 + 1]; }; // Returnerar 1 om det gick att läsa, 0 annars int las_medlem(FILE* tsin, struct Medlem* mp) { if (fscanf(tsin, "%d", &mp->nr) == EOF) return 0; while (getc(tsin) != '\n') ; fgets(mp->namn, sizeof mp->namn, tsin); int sista = strlen(mp->namn) - 1; if (mp->namn[sista] == '\n') mp->namn[sista] = '\0'; return 1; } int main() { FILE *tsin; if ((tsin = fopen("medlemmar.txt", "r")) == NULL) { printf("Kunde inte öppna filen 'medlemmar.txt'.\n"); return EXIT_FAILURE; } FILE *bsut; if ((bsut = fopen("medlemmar.bin", "wb")) == NULL) { printf("Kunde inte öppna filen 'medlemmar.bin'.\n"); return EXIT_FAILURE; } struct Medlem m; while (las_medlem(tsin, &m)) fwrite(&m, sizeof m, 1, bsut); return EXIT_SUCCESS; } /* main */ Filer ----- -rw-r--r-- 1 padrone padrone 7862 Jan 9 16:58 anteckningar.txt -rw-rw-r-- 1 padrone padrone 419 Jan 9 16:19 binart.c -rw-rw-r-- 1 padrone padrone 453 Jan 8 17:01 filmedel-2.c -rw-rw-r-- 1 padrone padrone 502 Jan 8 16:56 filmedel.c -rw-rw-r-- 1 padrone padrone 906 Jan 9 16:25 kopiera.c -rw-rw-r-- 1 padrone padrone 104 Jan 8 14:55 Makefile -rw-rw-r-- 1 padrone padrone 930 Jan 9 16:09 medlemmar-2.c -rw-rw-r-- 1 padrone padrone 144 Jan 9 16:27 medlemmar.bin -rw-rw-r-- 1 padrone padrone 603 Jan 9 16:27 medlemmar-binart.c -rw-rw-r-- 1 padrone padrone 987 Jan 9 16:04 medlemmar.c -rw-rw-r-- 1 padrone padrone 52 Jan 9 15:52 medlemmar.txt -rw-rw-r-- 1 padrone padrone 802 Jan 8 16:52 reellatal.txt -rw-rw-r-- 1 padrone padrone 4 Jan 9 16:20 tal.bin -rw-rw-r-- 1 padrone padrone 3 Jan 8 16:45 tal.txt