Programexempel från C-föreläsning 10, torsdag 10 december 2009 ============================================================== 1. Pekare! 2. Fortsättning på pekare: pekare, poster och arrayer 3. Funktioner 4. Allegro-biblioteket 5. Om vi hinner: Filhantering med stdio-paketet 1. Pekare ========= En pekare är adressen till den plats i minnet där något finns lagrat. Men dessutom har pekaren en typ (nämligen pekare till vad-det-nu-är), så det är inte bara en adress, utan man håller reda på vilken typ av data som pekaren kan peka på. Kom ihåg scanf -------------- int i; printf("Värde: %d\n", i); /* Värdet, dvs innehållet i variabeln i, skickas */ scanf("%d", &i); /* Här skickar vi i stället en pekare till variabeln i */ Exempel med pekare ------------------ (Vi ritar upp allt detta, både som lådor och pilar och som minnesadresser!) float x; scanf("%f", &x); float *pf; pf = &x; /* rita två bilder här: lådor respektive adresser */ *pf = -9.9; int i; pf = &i; /* Fel! Kompilatorn varnar. */ float y; float *pf2; y = x; pf2 = &y; pf2 = y; /* Fel! Kompileringsfel. */ *pf = *pf2 + 2; *pf2 = *pf; pf2 = pf; scanf("%f", &x); scanf("%f", pf); Strängar (och andra arrayer) ---------------------------- Om man skriver namnet på en array-variabel (t ex en char-array = sträng) i ett C-program, så kommer den (för det mesta) att konverteras till en pekare till det första elementet i arrayen. Kom ihåg gets och scanf ----------------------- int i; scanf("%d", &i); /* &-tecken */ char s[3+1]; gets(s); /* Inget &-tecken */ scanf("%s", s); /* Inget &-tecken */ Fortsättning ------------ char *cp; cp = &s; /* Fel! Kompilatorn varnar. */ cp = s; s[1] = 'o'; cp[1] = 'o'; Kort repetion/sammanfattning av pekare -------------------------------------- int heltalsvariabel; heltalsvariabel = 17; int* pekarvariabel; pekarvariabel = &heltalsvariabel; *pekarvariabel = *pekarvariabel + 1; Allt på en gång: poster, pekare, arrayer (jfr: Gunnar kap 4 sid 11) ------------------------------------------------------------------- struct Motor { int cyl; double effekt; }; struct Motor m = { 4, 120 }; Pekare till struct (fortsättning) --------------------------------- struct Motor *mp; mp = &m; (*mp).cyl = 6; (*mp).effekt = 160.0; /* Inte: *mp.effekt = 160.0; */ Alternativ: mp->cyl = 6; mp->effekt = 160.0; Array av poster ("vektor av structar) -- jfr "punktuppgifterna" fö 7 -------------------------------------------------------------------- struct Motor a[5]; a[0].cyl = 8; a[0].effekt = 185; struct Motor *mp; mp = a; /* Inte: mp = &a; */ mp[1].cyl = 4; mp[1].effekt = 110; 3. Funktioner ============= Funktioner ---------- "Funktion" i matematiken = avbildning, t. ex. y = f(x) = 2x + 3, där t. ex. värdet x=7 avbildas på y=17 "Funktion" i C: programsnutt En C-funktion kan ta emot värden (via parametrar) och returnera ett värde ("retur-värdet"). (Med olika trick kan man returnera flera värden.) Exempel på funktioner: main, printf, scanf, sqrt En ren programsnutt ------------------- time_t nu; char* nu_text; nu = time(NULL); nu_text = ctime(&nu); printf("Klockan är nu %.8s\n", nu_text + 11); Gör en funktion, och anropa den (klockan.c) ------------------------------------------- #include #include void skriv_tiden() { time_t nu; char* nu_text; nu = time(NULL); nu_text = ctime(&nu); printf("Klockan är nu %.8s\n", nu_text + 11); } int main() { skriv_tiden(); skriv_tiden(); skriv_tiden(); return 0; } /* main */ En funktion som returnerar ett värde (som rand och main) -------------------------------------------------------- int kolla_losenordet() { char s[100 + 1]; printf("Lösenord: "); fgets(s, sizeof s, stdin); if (strcmp(s, "dungeon\n") == 0) return 1; else return 0; } Alternativ ---------- int kolla_losenordet() { char s[100 + 1]; printf("Lösenord: "); fgets(s, sizeof s, stdin); return strcmp(s, "dungeon\n") == 0; } Olika anrop ----------- int main() { int ok_losen; kolla_losenordet(); if (kolla_losenordet()) printf("Rätt!\n"); else printf("Fel!\n"); ok_losen = kolla_losenordet(); if (ok_losen) printf("Rätt!\n"); else printf("Fel!\n"); return 0; } /* main */ 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.0); 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 4. Allegro-biblioteket ====================== Inlämningsuppgift 6 Boken 5. 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 */