Programexempel från C-föreläsning 8, torsdag 3 december 2009 ============================================================ Idag: Lite mer om arrayer: Vad som inte går! Strängar Poster ("structar") Om vi hinner: Pekare Mer om arrayer -------------- Arrayer kan inte direkt (a) jämföras, (b) tilldelas, eller (c) skickas till och från funktioner, utan det måste göras element för element Exempel på saker som inte fungerar (som man tror): a = { 1, -3, 2 }; b = a; if (a == b) .... fnorble(a); b = gnorble(a); Textsträngar (= strängar = teckensträngar) ------------------------------------------ Textsträng i C = array av char, som avslutas med tecknet med teckenkoden 0 (skrivs '\0') Fyra sätt att stoppa in "Hej" i strängen s: char s[4]; s[0] = 'H'; s[1] = 'e'; s[2] = 'j'; s[3] = '\0'; char s[4] = { 'H', 'e', 'j', '\0' }; char s[4] = "Hej"; char s[] = "Hej"; Exempel ------- Gunnar kapitel 4 sid 4: Läs en sträng med scanf("%s") + skriv ut baklänges Gunnar kapitel 4 sid 5: Läs en textrad med gets + räkna antalet mellanslag Varning om både scanf("%s") och gets ------------------------------------ Buffer overflow! Använd fgets! Två körexempel för programmet strangar -------------------------------------- Ge ett namn: Klas Hej, Klas! Ge lösenord: Olle Nähä du! Ge ett namn: Olle Hej, Olle! Ge lösenord: anakin Välkommen! strangar.c ---------- #include #include int main(void) { char namn[80 + 1]; printf("Ge ett namn: "); fgets(namn, sizeof namn, stdin); /* Undvik gets! */ /* Men fgets behåller radslutstecknet - ta bort det */ int sista_positionen = strlen(namn) - 1; if (namn[sista_positionen] == '\n') namn[sista_positionen] = '\0'; printf("Hej, %s!\n", namn); char losenord[80 + 1]; printf("Ge lösenord: "); fgets(losenord, sizeof losenord, stdin); /* Undvik gets! */ if (strcmp(losenord, "anakin\n") == 0) printf("Välkommen!\n"); else printf("Nähä du!\n"); return 0; } Körexempel för programmet punkter-1 ----------------------------------- Mata in punkter genom att skriva x- och y-koordinater, utan komma emellan. Avsluta med punkten 0 0. 3 17 4 9 5 12 2 6 0 0 Punkten med minsta x: x = 2, y = 6 Punkten med största x: x = 5, y = 12 punkter-1.c ----------- #include #include #include struct Punkt { int x; int y; }; const int max_antal_punkter = 100; // Funkar med en tillräckligt modern C int main(void) { struct Punkt a[max_antal_punkter]; int antal = 0; printf("Mata in punkter\n" "genom att skriva x- och y-koordinater, utan komma emellan.\n" "Avsluta med punkten 0 0.\n"); int x; int y; do { scanf("%d %d", &x, &y); if (x == 0 && y == 0) { // Avsluta } else { // Lägg in i arrayen if (antal == max_antal_punkter) { printf("Fullt!"); return EXIT_FAILURE; } a[antal].x = x; a[antal].y = y; ++antal; } } while (x != 0 || y != 0); // Hitta punkterna med minsta och största x-värden, // och skriv ut dem! if (antal == 0) { printf("Inga punkter.\n"); return EXIT_SUCCESS; } struct Punkt min, max; min.x = INT_MAX; // Eller: min = a[0]; max.x = INT_MIN; // Eller: max = a[0]; for (int i = 0; i < antal; ++i) { if (a[i].x < min.x) min = a[i]; if (a[i].x > max.x) max = a[i]; } printf("Punkten med minsta x: x = %d, y = %d\n", min.x, min.y); printf("Punkten med största x: x = %d, y = %d\n", max.x, max.y); return EXIT_SUCCESS; } // main Om vi hinner: Körexempel för programmet punkter-2 ------------------------------------------------- Mata in punkter genom att skriva x- och y-koordinater, utan komma emellan. Avsluta med punkten 0 0. 3 17 4 9 5 12 2 6 0 0 Punkterna (x = 3, y = 17) och (x = 2, y = 6) har störst avstånd: 11.05 Om vi hinner: punkter-2.c ------------------------- #include #include #include #include struct Punkt { int x; int y; }; const int max_antal_punkter = 100; int main(void) { struct Punkt a[max_antal_punkter]; int antal = 0; printf("Mata in punkter\n" "genom att skriva x- och y-koordinater, utan komma emellan.\n" "Avsluta med punkten 0 0.\n"); int x; int y; do { scanf("%d %d", &x, &y); if (x == 0 && y == 0) { // Avsluta } else { // Lägg in i arrayen if (antal == max_antal_punkter) { printf("Fullt!"); return EXIT_FAILURE; } a[antal].x = x; a[antal].y = y; ++antal; } } while (x != 0 || y != 0); // Vilka punkter ligger längst ifrån varandra? struct Punkt p1, p2; double max_avst; for (int i = 0; i < antal; ++i) { for (int j = i + 1; j < antal; ++j) { double avst = sqrt(pow(a[i].x - a[j].x, 2) + pow(a[i].y - a[j].y, 2)); if (avst > max_avst) { max_avst = avst; p1 = a[i]; p2 = a[j]; } } } printf("Punkterna (x = %d, y = %d) och (x = %d, y = %d) har störst avstånd: %.2f\n", p1.x, p1.y, p2.x, p2.y, max_avst); return EXIT_SUCCESS; } // main Om vi hinner: Körexempel för programmet monster ----------------------------------------------- Hur många monster (max 10)? 3 Monster 1. Namn? Hulken Antal hit points? 1000 Vikt? 300 Monster 2. Namn? Varulven Antal hit points? 100 Vikt? 80 Monster 3. Namn? Mumien Antal hit points? 30 Vikt? 50 Varje monster biter ett annat monster... Hulken biter Mumien. Varulven biter Mumien. Mumien biter Hulken. Det är mest synd om Mumien. Om vi hinner: monster.c ----------------------- #include #include #include #define MAX_NAMN 10 #define MAX_MONSTER 10 struct Monster { char namn[MAX_NAMN + 1]; int hp; double vikt; int bett; }; int main(void) { struct Monster monstren[MAX_MONSTER]; int antal_monster; int i; struct Monster maxbiten; do { printf("Hur många monster (max %d)? ", MAX_MONSTER); scanf("%d", &antal_monster); while (getchar() != '\n') ; } while (antal_monster > MAX_MONSTER || antal_monster < 2); for (i = 0; i < antal_monster; ++i) { printf("\n"); printf("Monster %d. Namn? ", i + 1); gets(monstren[i].namn); /* Varning: gets */ printf("Antal hit points? "); scanf("%d", &monstren[i].hp); printf("Vikt? "); scanf("%lf", &monstren[i].vikt); while (getchar() != '\n') ; monstren[i].bett = 0; } printf("\n"); printf("Varje monster biter ett annat monster...\n"); srand(time(0)); for (i = 0; i < antal_monster; ++i) { int stackarn; do stackarn = rand() % antal_monster; while (stackarn == i); printf("%s biter %s.\n", monstren[i].namn, monstren[stackarn].namn); monstren[stackarn].bett++; } maxbiten = monstren[0]; for (i = 1; i < antal_monster; ++i) { if (monstren[i].bett > maxbiten.bett) maxbiten = monstren[i]; } printf("Det är mest synd om %s.\n", maxbiten.namn); return EXIT_SUCCESS; } /* main */ 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'; 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;