b) 0
c) 1 (true är fel svar, men ger inget poängavdrag)
#include <stdio.h> int main(void) { int antal, min, max; int hittat_utanfor = 0; printf("Ange antal: "); scanf("%d", &antal); printf("Ange min: "); scanf("%d", &min); printf("Ange max: "); scanf("%d", &max); for (int i = 0; i < antal; ++i) { int talet; printf("Ange tal nr %d:\n", i + 1); scanf("%d", &talet); if (talet < min || talet > max) hittat_utanfor = 1; } if (hittat_utanfor) printf("Inte Ok\n"); else printf("Ok\n"); return 0; }
int tre_lika(double x, double y, double z) { return x == y && y == z; }
En kommentar: Observera att det inte fungerar att skriva x == y == z. Det här är ett exempel på att som programmerare behöver man veta vad man gör, för den konstruktionen går igenom kompilatorn utan fel, men betyder något helt annat! Det är inte heller säkert att man upptäcker felet vid testning, för med en del testfall ger båda konstruktionerna samma resultat.
b)
c)int tre_olika(double x, double y, double z) { return x != y && x != z && y != z; }
int main(void) { double x, y, z; printf("Skriv tre flyttal: "); scanf("%lf %lf %lf", &x, &y, &z); printf("tre_lika(%f, %f, %f) = %d\n", x, y, z, tre_lika(x, y, z)); printf("tre_olika(%f, %f, %f) = %d\n", x, y, z, tre_olika(x, y, z)); return 0; }
En kommentar: Det kan vara lockande att göra en lösning som den här nedanför, med else-grenar, för om alla tre talen är lika så kan de inte vara olika, och så vidare. Men kom ihåg att meningen är att testa funktionerna, så vi kan inte förutsätta att de gör rätt!
if (tre_lika(x, y, z)) printf("Alla talen är lika.\n"); else if (tre_olika(x, y, z)) printf("Alla talen är olika.\n"); else printf("Två av talen är lika.\n");
#define MAX_NAMNLANGD 30 struct Termos { char typnamn[MAX_NAMNLANGD + 1]; double volym; char innehallets_namn[MAX_NAMNLANGD + 1]; double innehallets_volym; };
struct Termos termosen = { "Sahara MWS-A500", 0.5, "kaffe", 0.4 };
void visa_termos(struct Termos* tp) { printf("Typ: %s\n", tp->typnamn); printf("Volym: %.2f\n", tp->volym); printf("Innehåll: %s\n", tp->innehallets_namn); printf("Innehållets volym: %.2f\n", tp->innehallets_volym); }
void las_termos(struct Termos* tp) { printf("Typ: "); gets(tp->typnamn); printf("Volym: "); scanf("%lf", &tp->volym); while (getchar() != '\n') ; printf("Innehåll: "); gets(tp->innehallets_namn); printf("Innehållets volym: "); scanf("%lf", &tp->innehallets_volym); while (getchar() != '\n') ; }
Beroende på vad som fanns på de platser som skrevs över, kan programmet antingen krascha, ge fel svar, eller fungera som förväntat. Även andra fel kan uppstå, till exempel att programmet gör något helt annat än vad som var tänkt. Det kan bli olika fel olika gånger man provkör. C-standarden kallar det för odefinierat beteende, och enligt standarden får vad som helst hända, till exempel att programmet raderar alla filer på hårddisken eller att datorn smälter och rinner ner på golvet i en pöl.
En kommentar: Det här är ett bra exempel på att som C-programmerare behöver man veta vad man gör. Det är inte säkert att man upptäcker felet vid testningen, för programmet kan mycket väl råka fungera som man tänkt sig för alla testfallen. Men sen när man installerat det i produktionsmiljön och kör det på riktigt, då ger programmet fel svar. Eller så smälter datorn.
int rimlig_termos(struct Termos* tp) { return tp->innehallets_volym <= tp->volym; }
int main(void) { struct Termos termos; las_termos(&termos); visa_termos(&termos); if (!rimlig_termos(&termos)) printf("*** Varning! Termosens data är orimliga!\n"); return 0; }
double volymsumma(struct Termos termosar[], int antal_termosar) { double summa = 0; for (int i = 0; i < antal_termosar; ++i) summa += termosar[i].volym; return summa; }
int main(void) { struct Termos termosar[] = { { "Typ 1", 0.1, "slem", 0.1 }, { "Typ 2", 10.0, "vakuum", 0.0 }, { "Typ 3", 1.1, "klägg", 0.1 }, { "Typ 4", 0.9, "kladd", 0.7 }, }; if (volymsumma(termosar, 4) != 12.1) printf("*** Varning! Oväntat svar från volymsumma!\n"); return 0; }
En kommentar: Man måste vara försiktig med likhetsjämförelser av flyttal, som den i programkoden ovan. Eftersom flyttal lagras med ett begränsat antal binära siffror (bitar), går det inte att representera alla tal exakt. Jämför med att man inte kan skriva exakt 1/3 som ett decimaltal med ändligt många siffror när man skriver med vanliga decimala siffror. Därför kan vi här mycket väl få en varning om ett oväntat svar, trots att funktionen "volymsumma" räknar (nästan) helt rätt.
#include <stdlib.h> #include <stdio.h> // Definitioner av struct Termos, las_termos och rimlig_termos int main(void) { struct Termos termos; FILE* termosfilen; termosfilen = fopen("termosar.bin", "wb"); if (termosfilen == NULL) { fprintf(stderr, "Kunde inte öppna filen 'termosar.bin'\n"); exit(EXIT_FAILURE); } las_termos(&termos); while (rimlig_termos(&termos)) { fwrite(&termos, sizeof termos, 1, termosfilen); las_termos(&termos); } fclose(termosfilen); return 0; }
#include <stdlib.h> #include <stdio.h> // Definitioner av struct Termos och visa_termos int main(void) { struct Termos termos; FILE* termosfilen; double volymgrans; termosfilen = fopen("termosar.bin", "rb"); if (termosfilen == NULL) { fprintf(stderr, "Kunde inte öppna filen 'termosar.bin'\n"); exit(EXIT_FAILURE); } printf("Volymgräns: "); scanf("%lf", &volymgrans); printf("Termosar på filen som är minst %.2f stora:\n", volymgrans); while (fread(&termos, sizeof termos, 1, termosfilen) == 1) { if (termos.volym >= volymgrans) visa_termos(&termos); } fclose(termosfilen); return 0; }