Programmeringsteknik för mediaingenjörer, ht -98 1 Niklas Frykholm, Gunnar Gunnarsson Mål och innehåll Kursens mål är - att orientera om användning av datorn i naturvetenskapliga och tekniska tillämpningar, - att ge kännedom om ett datorsystems uppbyggnad och funktion, - att ge kunskaper och färdigheter i programkonstruktion och organisation av programsystem och - att orientera om datastrukturer och algoritmer. Inriktning: Högnivåprogrammering: Genomgång av programspråket C. Träning i konstruktion av algoritmer, programmeringsmetodik och strukturerad programmering. Genomgång av algoritmer för sökning och sortering. Datoranvändning: Datoranvändning och programutveckling i persondatormiljö. Orientering om ett datorsystems uppbyggnad och funktion illustrerad med aktuellt datorsystem. Lågnivåprogrammering: Datarepresentation. Pekare och dynamisk minneshantering. Gränssnitt till operativsystem och perifera enheter. Programmeringsteknik för mediaingenjörer, ht -98 2 Niklas Frykholm, Gunnar Gunnarsson hastighet = 100; tid = 2.5; stracka = hastighet * tid; liter_per_mil = 0.9; bensinforbrukning = stracka/10 * liter_per_mil; bensinpris = 8.00; kostnad = bensinforbrukning * bensinpris; Programmeringsteknik för mediaingenjörer, ht -98 if (hastighet printf("Du else { diff = 110 printf("Du "%i utan } 3 Niklas Frykholm, Gunnar Gunnarsson > 110) kör för fort."); – hastighet; kan öka din hastighet med " att köra för fort", diff); Programmeringsteknik för mediaingenjörer, ht -98 4 Niklas Frykholm, Gunnar Gunnarsson if (hastighet > 140) printf("Du kan bli av med körkortet."); else if (hastighet > 110) printf("Du kör för fort."); else { diff = 110 – hastighet; printf("Du kan öka din hastighet med " "%i utan att köra för fort", diff); } Programmeringsteknik för mediaingenjörer, ht -98 5 Niklas Frykholm, Gunnar Gunnarsson /* Beräkna 10! = 1*2*3*...*10 */ res = 1; for (i=1; i<=10; i++) res = res * i; /* Hur många tal i serien 1, 1/2, 1/3, 1/4, ... måste vi addera för att summan skall bli >= 10? */ sum = 0; i = 0; while (sum < 10) { i = i + 1; sum = sum + 1/i; } Programmeringsteknik för mediaingenjörer, ht -98 6 Niklas Frykholm, Gunnar Gunnarsson y = sin(2*x + 0.1); /* Returnerar det största av talen x och y. */ int max(int x, int y) { if (x > y) return x; else return y; } blir_fem = max(3,5); Programmeringsteknik för mediaingenjörer, ht -98 7 #include <stdio.h> int main(void) { printf("Hello, world!"); } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 8 Niklas Frykholm, Gunnar Gunnarsson /* Borsta tänderna */ Applicera tandkräm på borsten Borsta utsidan av tänderna i överkäken Borsta tuggsidan av tänderna i överkäken ...osv /* Ta sig igenom en labyrint. */ Placera handen på högra väggen. Gå tills du kommer ut ur labyrinten. /* Största gemensamma delare (Euklides algoritm) */ Givet två tal a och b, där a > b Sätt r till resten vid division av a genom b Om r = 0 är vi klara och b är SGD för de två talen. I annat fall sätt a = b och b = r och fortsätt med steg 2. Programmeringsteknik för mediaingenjörer, ht -98 9 Niklas Frykholm, Gunnar Gunnarsson /* Hitta alla primtal mellan 1 och n. (Erastotenes såll) */ Skriv upp alla tal mellan 1 och n. Sätt k = 2. Stryk alla tal som är delbara med k utom k själv, dvs stryk vart k:te tal, med början i talet 2k. Om det finns något tal > k som inte är struket, så sätt k till det talet och fortsätt med steg 3. I annat fall är vi klara. Programmeringsteknik för mediaingenjörer, ht -98 r = a % b; while (r != 0) { a = b; b = r; r = a % b; } 10 Niklas Frykholm, Gunnar Gunnarsson /* % är rest-operatorn i C */ /* != betyder skilt ifrån */ Programmeringsteknik för mediaingenjörer, ht -98 11 Niklas Frykholm, Gunnar Gunnarsson /* Returnerar den största gemensamma */ /* delaren för talen a och b. */ int gcd(int a, int b) { int r = a % b; while a = b = r = } (r != 0) { b; r; a % b; return r; } Programmeringsteknik för mediaingenjörer, ht -98 12 Niklas Frykholm, Gunnar Gunnarsson Repetition En dator består i princip av processor, minne, indataenheter och utdataenheter. Processorn förstår bara enkla instruktioner, maskinkod. C-program översätts till maskinkod av en kompilator. C skapades för att skriva operativsystem - det var därför viktigt att språket ”låg nära” maskinkoden, så att det gick att skriva snabba program. Att skriva direkt i maskinkod kan ge snabbare program, men det är mycket krångligare. Dessutom blir man låst till en viss maskin. C-program kan kompileras om för olika maskiner. Det finns strikta regler för hur ett C-program skall se ut - det är bra för det förhindrar missförstånd. Ett datorprogram kan ses som en följd av beräkningar. Datorprogram innehåller dock några saker som inte finns i vanliga beräkningar: Variabler Val Slingor/loopar (platser att lagra värden) (göra på olika sätt i olika situationer) (göra samma sak flera gånger) Programmeringsteknik för mediaingenjörer, ht -98 13 Niklas Frykholm, Gunnar Gunnarsson Egendefinierade funktioner (egna kodblock som kan användas på många ställen) Repetition En algoritm är en detaljerad beskrivning av hur man kan gå till väga för att lösa ett visst problem. Det finns inga generella metoder för att konstruera algoritmer, men divide & conquer (dela upp i delproblem och lös dessa) är en bra strategi. Det svåraste är i allmänhet att komma på en bra algoritm. När vi har en algoritm är det relativt enkelt att skriva om den i ett programspråk. Programmeringsteknik för mediaingenjörer, ht -98 14 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> int main(void) { int i; /* Deklarerar en heltalsvariabel. */ float f; /* Deklarerar en flyttalsvariabel. */ printf("Hej!\n"); printf("Skriv in ett heltal: "); scanf("%i",&i); printf("Du skrev in talet %i.\n", i); printf("Skriv in ett decimaltal: "); scanf("%f", &f); printf("Du skrev in talet %f.\n", f); } Programmeringsteknik för mediaingenjörer, ht -98 15 int main(void) { int i, k, j; double x; long double ld; unsigned char c; long r = 14; float f = 3.75; ... Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 16 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> int main(void) { char c; printf("Skriv in ett tecken: "); scanf("%c", &c); printf("Tecknets talvärde är %i\n",c); /* Om c ligger mellan 'A' och 'Z' */ if (c >= 'A' && c <= 'Z') c = c – 'A' + 'a'; printf("Omvandlat till gemener är tecknet %c.\n", c); } Programmeringsteknik för mediaingenjörer, ht -98 17 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> int main(void) { int i, j; int summa; float x, y, res; printf("Skriv in två heltal: "); scanf("%i %i", &i, &j); summa = i + j; printf("Summan blir %i.\n", summa); printf("Beräkningen ser ut som %i + %i = %i.\n", i, j, summa); printf("%5i + %5i = %5i\n", i, j, summa); printf("Skriv in två decimaltal: "); scanf("%f %f", &x, &y); res = x * y; Programmeringsteknik för mediaingenjörer, ht -98 18 Niklas Frykholm, Gunnar Gunnarsson printf("%f * %f = %f\n", x, y, res); printf("%6.2f * %6.2f = %6.2f\n", x, y, res); } int a[4]; /* Fyra heltal */ int x[4] = {0, 1, 2, 3}; int r[] = {5, 6, 7}; Programmeringsteknik för mediaingenjörer, ht -98 19 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> int main(void) { char namn[50]; char halsning[] = "Hejsan"; printf("Skriv ditt namn: "); scanf("%s", namn); printf("%s %s!\n", halsning, namn); } Programmeringsteknik för mediaingenjörer, ht -98 20 Niklas Frykholm, Gunnar Gunnarsson Repetition En bit är ett tal som är 0 eller 1. En byte byggs upp av 8 bitar: 00011101. En byte betyder i sig ingenting, för att veta hur vi ska tolka bitarna måste vi veta vilken typ av data byten innehåller. Vi kan t ex tolka byten som ett positivt binärt tal, då kan vi lagra tal mellan 0 och 255. Vi kan också tolka byten som ett tal med tecken (där första biten anger tecknet). Då kan vi lagra tal mellan -128 och +127. Om vi vill lagra större heltal än så kan vi använda fler bytes. C har fyra heltalstyper: char, short, int och long. En char rymmer minst och en long mest. Normalt arbetar vi med typen int. Varje heltalstyp kan dessutom vara signed eller unsigned. Ett flyttal (2.35*107) består av decimaldel (2.35) och exponent (7). Ju mer minne vi har för exponenten, desto större tal kan vi lagra. Ju mer minne vi har för decimaldelen, desto bättre noggrannhet (= mindre avrundningsfel) får vi. C:s flyttalstyper heter float, double och long double. Om vi skriver ett vanligt tal i koden (3, 45, 6) får det typen int (eller long om det är för stort för en int). Skriver vi ett decimaltal i koden (3.2, 3., 4e10, .0) så får det typen double. En variabeldeklaration kan t ex se ut som const unsigned long u = 70000; const talar om att variabelns värde inte kan ändras i programmet. Variabeln får vid programmets start värdet 70000. (Om vi inte anger något värde får variabeln ett slumpmässigt värde.) När man programmerar använder man ofta hexadecimala och oktala tal. I C tolkas 0xab hexadecimalt och ger värdet (10 * 16 + 11 = 171). 054 tolkas oktalt och ger värdet (5 * 8 + 4 = 44). printf och scanf används för in- och utmatning av data. Programmeringsteknik för mediaingenjörer, ht -98 21 Niklas Frykholm, Gunnar Gunnarsson Repetition Ett fält är en speciell typ av varibel som innehåller ett antal positioner. Varje position fungerar som en egen variabel. Om vi skapar ett fält med int a[4] kan vi sedan använda a[0], a[1], a[2] och a[3] som vanliga variabler. Vi måste se upp så att vi inte råkar använda a[-1] eller a[5]. Det ger fel och vi får inga varningar från kompilatorn. Vi kan inte kopiera fält genom tilldelning: a = b. Vill vi kopiera fält måste vi skriva en loop som kopierar varje position i fältet för sig. Tecken/bokstäver skrivs i C med enkla citationstecken 'a'. Varje tecken motsvarar/representeras av ett visst tal. 'A' motsvarar t ex 64. C gör ingen skillnad på tal och tecken. Vi kan använda varje tecken precis som det tal det motsvarar, t ex 'A' + 1. Tecken lagras i vanliga heltalsvariabel, vanligen används char.. En sträng är ett stycke text, t ex "Hejsan" och "Hallå". I C lagras strängen som ett fält av tecken (char s[20]). En nolla i fältet markerar var strängen tar slut. När en beräkning utförs mellan två tal i C måste talen först omvandlas till samma typ. Det tal som är av "mindre typ" omvandlas till den större typen. I 2.0 + 3 omvandlas 3 till 3.0. Resultatet av en beräkning får alltid samma typ som talen i beräkningen. 11/3 ger således ett resultatet 3 (av typen int), eftersom det riktiga resultatet (3.66666....) inte kan lagras i en int. Vi kan skriva 11.0/3 för att få rätt resultat. Skrivsättet (float)x omvandlar värdet i variabeln x till en float. Det är nödvändigt för att få rätt resultat när vi delar heltalsvariabler. Divisionen x/y, kan alltså skrivas som (float)x/y. Programmeringsteknik för mediaingenjörer, ht -98 22 Niklas Frykholm, Gunnar Gunnarsson /* Maskning, plocka ut de 8 bitarna */ /* längst till höger */ j = i & 0xff; /* Sätta bit – sätta biten i position n */ i = i | (1 << n); /* Rensa bit - rensa biten i position n */ i = i & ~(1 << n); /* Inspektera bit – vilket värde har biten */ /* i position n */ j = (i >> n) & 1; Programmeringsteknik för mediaingenjörer, ht -98 Niklas Frykholm, Gunnar Gunnarsson 23 /* Alla variabler får värdet 0. */ i = j = k = 0; /* Detta uttryck har värdet 4. */ (i = 3) + (k = j = 1); i i i i += 3; *= 2; >>= 2; &= 0xA; /* /* /* /* Samma Samma Samma Samma som som som som i i i i = = = = i i i i + 3 */ * 2 */ >> 2 */ & 0xA */ Programmeringsteknik för mediaingenjörer, ht -98 24 Niklas Frykholm, Gunnar Gunnarsson Repetition - Operatorer Operatorer är symboler som vi räknar med: + - * / .. osv. Operander är det som operatorerna arbetar på. Operatorer och operander bildar tillsammans uttryck. I vilken ordning operatorerna i ett uttryck skall beräknas bestäms av deras prioritet. Operatorn med högst prioritet beräknas först. I a = 3 * 4 + 2; beräknas multiplikationen först eftersom * har högst prioritet. Tilldelningen utförs allra sist eftersom = har lägst prioritet. Om operatorerna har samma prioritet bestäms i stället beräkningsordningen av associativiten. Om operatorn är vänsterassociativ beräknas uttrycket längst till vänster först. Är den högerassociativ beräknas uttrycket längst till höger först: i = j = 2 - 3 + 4 beräknas som i = (j = ( (2 -3) + 4) ) eftersom + är vänsterassociativ och = högerassociativ. Unära operatorer (en operand) har alltid högre prioritet än binära. Postfixoperatorer (står efter variabeln) har högre prioritet än prefix. Programmeringsteknik för mediaingenjörer, ht -98 25 Niklas Frykholm, Gunnar Gunnarsson Repetition - Operatorer (forts.) Matematiska + - * / % % ger resten vid heltalsdivision Ökning/minskning ++ -- finns i prefix- och postfix-variant med olika innebörd Jämförelse < > <= >= == != skilj på = och == Logiska && || ! kortsluten utvärdering Bit-operatorer & | ~ ^ >> << kan användas för att sätta/rensa en viss bit Konstiga operatorer [] elementoperatorn - hämta ett element ur ett fält a[3] () funktionsanropsoperatorn - printf(”hej”) sizeof ger antalet bytes som en typ eller variabel använder ?: villkorsoperatorn - liten if-sats: x = b > 3 ? ”j” : ”n”; , kommaoperatorn - staplar uttryck Programmeringsteknik för mediaingenjörer, ht -98 26 Niklas Frykholm, Gunnar Gunnarsson /* Satser med sidoeffekter. */ i = 3; printf("Hej"); /* Satser utan sidoeffekter. */ 2 + 3; ;;;; /* Några tomma satser – de är tillåtna i C */ /* Satsblock */ { a = b + 3; c = 2 * a; } Programmeringsteknik för mediaingenjörer, ht -98 27 /* Variabeldeklarationer */ { int a, c; c = 2; a = 2 * c; { int b; b = 2*c – a; a = a + b; } } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 28 Niklas Frykholm, Gunnar Gunnarsson /* En inre variabel döljer en yttre. */ { int a; { long a; /* a är en long här */ } /* och en int här */ } Programmeringsteknik för mediaingenjörer, ht -98 if (uttryck1) sats1 else if (uttryck2) sats2 else if ... ... else sats_n 29 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 30 Niklas Frykholm, Gunnar Gunnarsson if (n > 0) medel = sum / n; if (a > b) { temp = b; b = a; a = temp; } /* Vi kan undvika satsblock genom att skriva om det sista uttrycket på följande sätt (men det är inte att rekommendera). */ if (a > b) temp = b, b = a, a = temp; Programmeringsteknik för mediaingenjörer, ht -98 31 Niklas Frykholm, Gunnar Gunnarsson if (command == 'q') printf("Avslutar programmet."); else if (command == 's') printf("Sparar dokumentet."); else if (command == 'n') printf("Skapar nytt dokument."); else printf("Okänt kommando!"); Programmeringsteknik för mediaingenjörer, ht -98 32 /* Dangling else problem */ if (a < 3) if (a < -1) printf("a är för litet"); else printf("a är för stort"); if (a < 3) { if (a < -1) printf("a är för litet"); } else printf("a är för stort"); Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 33 switch (heltalsuttryck) { case konstant_heltalsuttryck: satser break; case konstant_heltalsuttryck: satser break; ... default: satser break; } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 34 Niklas Frykholm, Gunnar Gunnarsson switch (command) { case 'q': printf("Avslutar programmet"); break; case 's': printf("Sparar dokumentet"); break; case 'n': printf("Skapar nytt dokument"); break; default: printf("Ogiltigt kommando"); break; Programmeringsteknik för mediaingenjörer, ht -98 } 35 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 36 Niklas Frykholm, Gunnar Gunnarsson switch (command) { case 'q': case 'Q': printf("Avslutar programmet"); break; case 's': case 'S': printf("Sparar dokumentet"); break; ... Programmeringsteknik för mediaingenjörer, ht -98 37 Niklas Frykholm, Gunnar Gunnarsson printf("Vill du fortsätta? (j/n) "); scanf("%c", &c); while (c != 'j' && c != 'n') { printf("Vill du fortsätta? (j/n) "); scanf(" %c", &c); } Programmeringsteknik för mediaingenjörer, ht -98 38 Niklas Frykholm, Gunnar Gunnarsson c = 'X'; while (c != 'j' && c != 'n') { printf("Vill du fortsätta? (j/n) "); scanf(" %c", &c); } do { printf("Vill du fortsätta? (j/n) "); scanf(" %c", &c); } while (c != 'j' && c != 'n'); Programmeringsteknik för mediaingenjörer, ht -98 39 Niklas Frykholm, Gunnar Gunnarsson for (i = 1; i < 10; i++) { ... for (uttryck_1; uttryck_2; uttryck_3) sats uttryck_1; while (uttryck_2) { sats uttryck_3; } Programmeringsteknik för mediaingenjörer, ht -98 40 Niklas Frykholm, Gunnar Gunnarsson for (i = i_start, j = j_start; i < i_max && j < j_max; i++, j += i) ; for (;;) /* En oändlig loop */ for (i=1; i<=3;i++) for (j=1; j<=2; j++) printf("%i, %i\n", i, j); /* 1, 1, 2, 2, 3, 3, Ger utskriften: */ 1 2 1 2 1 2 Programmeringsteknik för mediaingenjörer, ht -98 41 Niklas Frykholm, Gunnar Gunnarsson /* Ännu en variant av ett exempel som vi har sett tidigare. */ for (;;) { printf("Vill du fortsätta? (j/n) "); scanf(" %c", &c); if (c == 'j' || c == 'n') break; printf("Du måste svara med j eller n.\n"); } Programmeringsteknik för mediaingenjörer, ht -98 42 Niklas Frykholm, Gunnar Gunnarsson while (uttryck) sats do sats while (uttryck) do { printf("Vill du fortsätta? (j/n) "); scanf(" %c", &c); if (c != 'j' && c != 'n') printf("Du måste svara med j eller n.\n"); } while (c != 'j' && c != 'n'); Programmeringsteknik för mediaingenjörer, ht -98 43 Niklas Frykholm, Gunnar Gunnarsson /* Läser in tio tal mellan 1 och 10 */ int main(void) { int tal[10]; int lasta = 0; int summa; while (lasta < 10) { scanf("%i", &tal[lasta]); if (tal[lasta] < 1 || tal[lasta] > 10) continue; lasta++; summa+=tal[lasta]; } ... Programmeringsteknik för mediaingenjörer, ht -98 } 44 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 45 Niklas Frykholm, Gunnar Gunnarsson int main(void) { int tal[10]; int lasta = 0; int summa; while (lasta < 10) { scanf("%i", &tal[lasta]); if (tal[lasta] >= 1 && tal[lasta] <= 10) { lasta++; summa+=tal[lasta]; } } ... Programmeringsteknik för mediaingenjörer, ht -98 } 46 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 47 Niklas Frykholm, Gunnar Gunnarsson if (i>10) goto done; ... done: /* Här fortsätter programkoden. */ Programmeringsteknik för mediaingenjörer, ht -98 48 for (i=0; i<a_len; i++) for (j=i+1; j<a_len; j++) if (a[i] > a[j]) { temp = a[i]; a[i] = a[j]; a[j] = temp; } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 49 i=0; loop_1: if (i<a_len) goto out_1; j=i+1; loop_2: if (j<a_len) goto out_2; if (a[j] > a[i]) goto next_2; temp = a[i]; a[i] = a[j]; a[j] = temp; next_2: j++; goto loop_2; out_2: i++; goto loop_1; out_1: Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 Niklas Frykholm, Gunnar Gunnarsson 50 Repetition Ett C-program är uppbyggt av satser. En enkel sats är ett utryck följt av ett semikolon. Uttrycket behöver inte ha någon mening. a = 3; 5; ; a < 7; i++; a = 3, b = 2; En sammansatt sats består av ett antal satser inom krullparenteser. När satsen utförs så utförs var och en av satserna inom krullparenteserna i tur och ordning. Fastän en sammansatt sats kan innehålla många satser så är den själv bara en enda sats och kan användas över allt där satser kan användas. Vi kan ha deklarationer av variabler i början av en sammansatt sats. { int temp = a; b = temp * 2; } Förutom enkla och sammansatta satser innehåller C även kontrollsatser i form av val (if / switch) och loopar (while / for). Satsen break hoppar ut ur en loop. Satsen continue hoppar till nästa varv av loopen. C innehåller också en goto-sats som låter oss hoppa hur som helst i ett program, men den ska ni inte använda. Programmeringsteknik för mediaingenjörer, ht -98 51 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 /* En enkel funktion */ int ganger_tva (int i) { return 2*i; } 52 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 53 Niklas Frykholm, Gunnar Gunnarsson /* Pre: c innehåller något tecken. Post: om tecknet är en svensk versal returneras motsvarande gemen, annars returneras tecknet oförändrat. */ char gemen(char c) { if (c >= 'A' && c <= 'Z') return c – 'A' + 'a'; else switch (c) { case 'Å': return 'å'; case 'Ä': return 'ä'; case 'Ö': return 'ö'; } return c; } Programmeringsteknik för mediaingenjörer, ht -98 54 #include <stdio.h> int dubbla(int a) { a = a * 2; return a; } void main(void) { int a, b; a = 3; b = dubbla(a); printf("%i\n%i\n",a,b); } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 int f_1(int i); double f_2 (double x); void main(void) { ... int f_1(int i) { ... double f_2 (double x) { ... 55 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 56 Niklas Frykholm, Gunnar Gunnarsson /* Detta går bra. */ #include <math.h> /* Men om vi bara använder sin-funktionen är det ibland enklare att direkt skriva: */ double sin(double x); /* Det här går också, sin har bara en parameter. */ double sin(double); /* Svårförståeligt – vad ska parametrarna ges för värden? */ double effektiv_ranta(double, int, double); /* Detta är bättre. */ double effektiv_ranta(double lanstorlek, int aterbetalningstid, double manadskostnad); Programmeringsteknik för mediaingenjörer, ht -98 57 Niklas Frykholm, Gunnar Gunnarsson /* Returnerar fakulteten av ett positivt tal n. */ int fak(int n) { return n==0 ? 1 : n*fak(n-1); } Programmeringsteknik för mediaingenjörer, ht -98 58 Niklas Frykholm, Gunnar Gunnarsson /* Denna funktion skriver ut ett tals bitmönster. Talet ska ligga mellan 0 och 255. Funktionen returnerar det tal som skickas in. */ int print_bits(int x) { int i; for (i=128; i>=0; i/=2) { if (x & i) printf("1"); else printf("0"); } return x; } Programmeringsteknik för mediaingenjörer, ht -98 59 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> void test(int x) { printf("I test x = %i.\n", x); x = 7; printf("I test x = %i.\n", x); } int main(void) { int x = 10, y = 12; printf("x = %i, y = %i\n", x, y); test(y); printf("x = %i, y = %i\n", x, y); test(x); } Programmeringsteknik för mediaingenjörer, ht -98 60 Niklas Frykholm, Gunnar Gunnarsson /* Rekursiv beräkning av funktionen upphöjt till. */ int upphojt_till(int x, int y) { if (y==0) return 1; else return x * upphojt_till(x, y-1); } Programmeringsteknik för mediaingenjörer, ht -98 61 Niklas Frykholm, Gunnar Gunnarsson /* Rekursiv funktion för att hitta det största talet från och med position start till och med position stopp i en lista. (Notera att vi inte behöver någon for-loop.) */ void max(int lista[], int start, int stopp) { /* Om start == stopp finns det bara ett tal i listan, och då är det givetvis störst. */ if (start == stopp) return lista[start]; else { /* Annars delar vi listan i två halvor. */ int mitt, max1, max2; mitt = (start + stopp)/2; max1 = max(lista, start, mitt); max2 = max(lista, mitt + 1, stopp); return max1 > max2 ? max1 : max2; } } Programmeringsteknik för mediaingenjörer, ht -98 62 Niklas Frykholm, Gunnar Gunnarsson /* Skriver ut strängen s baklänges med början i positionen start. */ void print_reverse(char s[], int start) { if (s[start]!=0) { print_reverse(s, start+1); printf("%c", s[start]); } } Algoritm: 1. Skriv först ut resten av strängen (från start+1 till slutet) baklänges. 2. Skriv sedan ut det första tecknet. Problemet blir mindre och mindre (den sträng vi skall skriva ut baklänges blir kortare och kortare). När problemet är tillräckligt litet (när strängen vi skall skriva ut inte innehåller några tecken alls) avbryts rekursionen. Programmeringsteknik för mediaingenjörer, ht -98 63 Niklas Frykholm, Gunnar Gunnarsson Repetition En funktion är en bit kod som utför någonting, t ex beräknar ett värde eller skriver ut någonting på skärmen. När vi väl har skrivit funktionen kan vi använda den på många olika ställen i vårt program. Att använda den kallas för att göra ett funktionsanrop. När vi anropar funktionen kan vi skicka med ett antal parametrar - dessa värden skickas till funktionen och används för att beräkna ett returvärde som sedan skickas tillbaka till huvudprogrammet. Ett funktionsanrop kan ingå i ett komplicerat uttryck, precis som när vi räknar i matematiken. x = sin(3 + cos(x)) * a; En funktionsparameter "finns bara" i själva funktionskroppen (precis som variabler som skapas i ett satsblock). Det kan finnas variabler med samma namn på andra ställen i programmet, men dessa har ingenting att göra med parametrarna och de olika variablerna påverkar inte varandra. När vi anropar en funktion så kopieras värdet vi skickar in till den lokala parametern. Vi kan ändra den lokala parametern i funktionen, men det påverkar inte värdet som vi skickade in. När vi definierar funktioner kan vi använda den speciella datatypen void, som betyder ingenting. En funktion vars returtyp är void returnerar ingenting. En funktion vars parameterlista är void tar inga parametrar. Varje funktion i programmet bör ha en tydlig och avgränsad uppgift. Framför varje funktion sätter vi en kommentar, som beskriver vad funktionen gör, vilka parametrar den tar, vilket värde den returnerar och om den har några begränsningar. (Detta skall även finnas med i labrapporten under rubriken "Systembeskrivning".) Programmeringsteknik för mediaingenjörer, ht -98 64 Niklas Frykholm, Gunnar Gunnarsson Repetition Om vi vill placera våra funktioner efter main-funktionen (eller, mer generellt, efter den funktion där de anropas) måste vi först tala om att de finns. Det gör vi med en funktionsdeklaration (”funktionsprototyp”) överst i programmet. Funktionsdeklarationen består av funktionshuvudet följt av ett semikolon. Syftet med funktionsprototypen är att ange funktionens returtyp och parametertyper, så att kompilatorn kan kontrollera att den används på rätt sätt. Själva funktionsdefinitionen behöver inte finnas i vårt program, det räcker om den finns någonstans. Funktionsdeklarationen måste dock finnas i programmet. Vad som händer när vi använder en #include-sats är att en fil med funktionsdeklarationer klistras in i programmet. En rekursiv funktion är en funktion som anropar sig själv för att lösa ett problem. För att rekursion skall fungera krävs två saker. Problemet måste bli "mindre och mindre" varje gång vi anropar oss själva. Det måste också finnas ett stoppfall (”basfall”), när problemet har blivit tillräckligt litet för att lösas utan att vi anropar oss själva. Programmeringsteknik för mediaingenjörer, ht -98 65 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 66 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 67 Niklas Frykholm, Gunnar Gunnarsson /* En variabel som står utanför funktioner blir global. */ #include <stdio.h> int x; /* x är global */ int main(void) { /* Vi kan använda x här. */ } void test(void) { /* Och här */ } void test2(int x) { /* Här kommer vi inte åt den globala variabeln x, eftersom den döljs av funktionens egna parameter x. */ Programmeringsteknik för mediaingenjörer, ht -98 } 68 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 69 Niklas Frykholm, Gunnar Gunnarsson /* Om vi vill komma åt x i en annan fil måste vi använda extern. */ extern int x; /* När vi använder extern får vi en variabeldeklaration, utan extern får vi en variabeldefinition. Precis som för funktioner så måste vi deklarera variabeln i varje fil där vi vill använda den. Vi får dock bara definiera den en enda gång. */ Programmeringsteknik för mediaingenjörer, ht -98 70 Niklas Frykholm, Gunnar Gunnarsson /* En funktion som håller reda på hur många gånger den anropats och returnerar det värdet. Fråga: Vad skulle hända om count inte deklarerats static? */ int raknare(void) { static int count = 0; return ++count; } Programmeringsteknik för mediaingenjörer, ht -98 71 Niklas Frykholm, Gunnar Gunnarsson void test(void) { static int i=0; /* Skapas när programmet startar. */ int j=0; /* Skapas varje gång funktionen anropas. */ i++; j++; } Programmeringsteknik för mediaingenjörer, ht -98 72 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 1 av 6) Före Efter #include <math.h> double sin(double x); double cos(double x); double sqrt(double x); ... int main(void) { ... } int main(void) { ... } Programmeringsteknik för mediaingenjörer, ht -98 73 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 2 av 6) Före #define N #define HEJ Efter 100 int main(void) printf("Hej!\n"); { int a[100], i; int main(void) for (i=0; i<100; i++) { a[i] = i; int a[N], i; printf("Hej!\n"); for (i=0; i<N; i++) } a[i] = i; HEJ ... } Programmeringsteknik för mediaingenjörer, ht -98 74 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 3 av 6) Före #define MAX(x,y) #define loop #define exit_on(x) Efter x > y ? x : y while(1) if (x) break; int main(void) { loop { ... exit_on(y == -1); ... } a = MAX(sin(b), 0.5); ... } int main(void) { while(1) { ... if (y==-1) break;; ... } a = sin(b) > 0.5 ? sin(b) : 0.5; ... } Programmeringsteknik för mediaingenjörer, ht -98 75 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 4 av 6) Före Efter #define KVAD(x) x * x int main(void) #define KVAD2(x) (x) * (x) { #define KVAD3(x) ( (x) * (x) ) ... a = 3+2 * 3+2; int main(void) b = (3+2) * (3+2); { c = ~(7) * (7); ... d = ~( (7) * (7) ); a = KVAD(3+2); e = ( (x++) * (x++) ); b = KVAD2(3+2); } c = ~KVAD2(7); d = ~KVAD3(7); e = KVAD3(x++); } Programmeringsteknik för mediaingenjörer, ht -98 76 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 5 av 6) Före Efter #define LANG 1 int main(void) { printf("What is your name?"); ... } int main(void) { #if LANG == 0 printf("Vad heter du?"); #elif LANG == 1 printf("What is your name?"); #elif LANG == 2 printf("Was ist dein name?"); #else printf("Tu t'apelles quoi?"); #endif ... } Programmeringsteknik för mediaingenjörer, ht -98 77 Niklas Frykholm, Gunnar Gunnarsson Gör om mig (del 6 av 6) Före Efter #define DEBUG int main(void) { ... printf("x = %i\n", x); ... } int main(void) { ... #ifdef DEBUG printf("x = %i\n", x); #endif ... } Programmeringsteknik för mediaingenjörer, ht -98 78 Niklas Frykholm, Gunnar Gunnarsson Repetition Ett C-program kompileras i tre steg: Preprocessorn klistrar in och klipper ut text. Kompilatorn omvandlar till maskinkod och länkaren klistrar ihop flera maskinkodsfiler till ett färdigt program. Preprocessorn förbehandlar ett program genom att klippa och klistra i texten. Kommandon till preprocessorn börjar med #. För att dela upp ett projekt på flera filer gör vi en header-fil för varje C-fil. I header-filen lägger vi alla deklarationer som behövs för att komma åt funktionerna i C-filen. En variabel som definieras utanför en funktion blir global och kan användas av alla funktioner i alla filer. För att komma åt den i en annan fil är den där den är skapad måste vi dock deklarera variabeln (= tala om att den finns). En variabeldeklaration ser ut som en variabeldefinition, men med ordet extern framför. extern int x; Nyckelordet static låter oss skapa globala variabler som bara är synliga i vissa delar av koden. En global variabel som är deklarerad static finns bara i den fil där den definieras. static int i; Vi kan också använda static inuti en funktion. Vi får då en global variabel som vi bara kan komma åt inuti funktionen. (Notera att variabeln fortfarande är global, så den skapas och förstörs med programmet, inte med funktionen. Man kan säga att den har global livslängd men lokal räckvidd.) Programmeringsteknik för mediaingenjörer, ht -98 79 Niklas Frykholm, Gunnar Gunnarsson void main(void) { int i1 = 1, i2 = 2; int *p1, *p2; p1 = &i1; p2 = &i2; *p1 = *p2; p1 = p2; *p1 = 4; } /* /* /* /* /* p1 pekar nu på i1... */ och p2 på i2 */ i1 får nu värdet 2 */ p1 pekar nu på i2 */ i2 får nu värdet 4 */ Programmeringsteknik för mediaingenjörer, ht -98 80 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> void dubbel(int *a); void main(void) { int a = 3; dubbel(&a); printf("%i\n", a); } void dubbel(int *a); { *a *= 2; } /* Skriver ut 6 */ Programmeringsteknik för mediaingenjörer, ht -98 81 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> int *test(void); void main(void) { int *a; a = test(); *a = 3; /* Inte bra – variabeln finns */ /* inte längre. */ } int *test(void) { int b = 5; return &b; Programmeringsteknik för mediaingenjörer, ht -98 } 82 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 83 Niklas Frykholm, Gunnar Gunnarsson /* Reserverar plats för 100 heltal (int). */ int *a; a = malloc(sizeof(int)*100); if (a == NULL) {error();} /* Det är inte säkert vi får minnet. */ /* Vi kan nu komma åt minnet vi har allokerat som ett fält (eftersom pekare och fält är utbytbara). */ a[45] = 3; Programmeringsteknik för mediaingenjörer, ht -98 84 Niklas Frykholm, Gunnar Gunnarsson /* a är en konstant pekare till en föränderlig variabel. Deklarationen utläses som "konstant pekare till char". */ char * const a; /* b är en pekare till en konstant char. */ char const * b; const char * b; /* c är en konstant pekare till en konstant char. */ const char * const c; /* Detta är tillåtna operationer. */ (*a)++; b++; /* Detta är otillåtna operationer (ger varning i C, */ /* fel i C++). */ a++; (*b)++; c++; (*c)++; Programmeringsteknik för mediaingenjörer, ht -98 85 Niklas Frykholm, Gunnar Gunnarsson /* En vanlig funktion deklareras t ex på följande sätt. */ int f(int); /* En funktionspekare till en sådan funktion deklareras nu som (utläses f pekar på och sedan en vanlig funktionsdeklaration) */ int (*f)(int); /* Notera speciellt att följande inte duger ty () är en postfix unär operator och har företräde framför den prefixa unära operatorn *. Detta blir en funktion som returnerar pekare till int. */ int *f(int); Programmeringsteknik för mediaingenjörer, ht -98 86 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> /* Exempel på funktionspekare. */ int kvadrat(int); int summera_fran_till(int, int, int (*f)(int)); void main(void) { int x; x = summera_fran_till(1,5,kvadrat); printf("1^2 + 2^2 + ... + 5^2 = %i", x); } int kvadrat(int x) { return x*x; } Programmeringsteknik för mediaingenjörer, ht -98 87 Niklas Frykholm, Gunnar Gunnarsson int summera_fran_till(int start, int stop, int (*f)(int)) { int i, sum = 0; for (i=start; i<=stop; i++) sum += f(i); return sum; } Programmeringsteknik för mediaingenjörer, ht -98 88 Niklas Frykholm, Gunnar Gunnarsson Repetition En pekare är en variabel som pekar på en annan variabel. Vi deklarerar en pekare som en vanlig variabel, men med en * mellan typen och variabelnamnet. För att använda pekare behöver vi två nya operatorer: & ger oss en pekare till en variabel (&i ger oss en pekare till i). * ger oss det som en pekare pekar på (*p ger oss det som p pekar på, dvs i). Den speciella konstanten NULL kan användas för en pekare som inte pekar på någonting. (p = NULL) Vi kan skriva en funktion som ändrar en variabels värde genom att skicka in en pekare till variabeln till funktionen: dubbel(&i); ... void dubbel(int *a) { *a = *a * 2; } Man kan också låta en funktion returnera en pekare. Man får dock inte returnera pekare till lokala variabler eftersom de försvinner när funktionen returnerar - vi får i så fall en pekare till någonting som inte finns. Programmeringsteknik för mediaingenjörer, ht -98 89 Niklas Frykholm, Gunnar Gunnarsson #include <stdio.h> char dagar[7][20] = {"Måndag", "Tisdag", "Onsdag", "Torsdag", "Fredag", "Lördag", "Söndag"}; int main(void) { int i; for (i=0; i<7; i++) printf("%i. %s\n", i+1, dagar[i]); return 0; } Programmeringsteknik för mediaingenjörer, ht -98 Niklas Frykholm, Gunnar Gunnarsson 90 Strängar som fält och strängar som pekare s1 h e j 0 h e j 0 0 0 0 0 0 0 s2 s1 pekar på strängen hej som finns lagrad i programkoden. Vi kan sätta s1 att peka på en annan sträng, men vi kan inte ändra det som s1 pekar på. (Eftersom vi på de flesta datorsystem inte får ändra vår egen programkod.) Deklarationen av s2 skapar ett fält med tio positioner. s2 pekar på den första positionen. Vi kan ändra det som s2 pekar på. Däremot kan vi inte sätta s2 att peka på någonting annat. s2 pekar alltid på det fält som den hör till. Programmeringsteknik för mediaingenjörer, ht -98 91 /* Inte bra - vi läser till en */ /* slumpmässig plats i minnet. */ char *s; scanf("%s", s); /* Detta är däremot OK! */ char s[80]; scanf("%s", s); Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 92 /* Utskrift av sträng */ void print_string(char *s) { while (*s != ’\0’) { printf("%c", *s); s++; } } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 93 Niklas Frykholm, Gunnar Gunnarsson int main(void) { int i, n, *a; printf("Ange antal poster i fältet: "); scanf("%i", &n); a = malloc(n * sizeof(int)); for (i = 0; i<n; i++) { printf("Post %i: ", i+1); scanf("%i", &a[i]); } printf("Baklänges blir fältet: "); for (i=n-1; i>=0; i--) printf("%i ", a[i]); printf("\n"); free(a); } Programmeringsteknik för mediaingenjörer, ht -98 94 Niklas Frykholm, Gunnar Gunnarsson /* Fält av pekare. */ int main(void) { int i; char *s[5] = {"ett", "två", "tre", "fyra", "fem"}; for (i=0; i<5; i++) printf("%s ", s[i]); /* Varför behövs %s? */ return 0; } Programmeringsteknik för mediaingenjörer, ht -98 95 Niklas Frykholm, Gunnar Gunnarsson int main(void) { int i, j, *l[5], len[5]; for (i=0; i<5; i++) { printf("Ange längden på lista %i: ", i); scanf("%i", &len[i]); l[i] = malloc(sizeof(int)*len[i]); for (j=0; j<len[i]; j++) { printf("Post %i i lista %i: ", j, i); scanf("%i", &l[i][j]); } } for (i=0; i<5; i++) { printf("\nLista %i: ",i); for (j=0; j<len[i]; j++) printf("%i ", l[i][j]); } } Programmeringsteknik för mediaingenjörer, ht -98 96 /* Pekare till en pekare. */ int main(void) { int i1=3, i2=5, *p1, *p2, **p; p1 = &i1; p2 = &i2; p = &p1; /* Vad gör nu denna sats? */ **p = *p2; } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 97 Niklas Frykholm, Gunnar Gunnarsson /* Pekare till en pekare till en pekare. */ int main(void) { int ***p; p = malloc(sizeof(int **)); *p = malloc(sizeof(int *)); **p = malloc(sizeof(int)); ***p = 3; } Programmeringsteknik för mediaingenjörer, ht -98 98 Niklas Frykholm, Gunnar Gunnarsson Repetition Namnet på ett fält fungerar som en pekare till första elementet. Det gäller även vid funktionsanrop. Om vi skriver. int a[10]; funk(a); ...så är det alltså en pekare till det första elementet som skickas till funktionen. Funktionen kan vara deklarerad t ex som void funk(int x[]); void funk(int *x); Ett flerdimensionellt fält är ett fält med fler än ett index, t ex int a[3][4] = {{1,2,3,4},{2,3,4,5},{3,4,5,6}}; Vi kan tänka på ett sådant fält som ett rutnät: Programmeringsteknik för mediaingenjörer, ht -98 99 Niklas Frykholm, Gunnar Gunnarsson Repetition Med flerdimensionella fält kan vi skapa ett fält av strängar. Eftersom en sträng är ett fält av tecken, blir ett fält av strängar, ett fält av fält av tecken. char s[3][10] = {"Hej", "på", "dej"}; De tre strängarna har nu namnen s[0], s[1] och s[2]. Ett alternativt sätt att skapa en sträng i ett program är att skriva char *s = "Hej på dej!"; Vi har i detta fall inte skapat något fält där strängen kan lagras. Det behövs inte eftersom strängen automatiskt lagras i maskinkoden för det kompilerade programmet. Uttrycket ovan sätter s att peka på den plats i koden där strängen finns lagrad. Vi kan inte ändra innehållet i strängar som skapas på detta sätt. (Vi kan t ex inte skriva s[0] = 'J'.) Fält och pekare har en mycket speciell relation i C. Namnet på ett fält är nämligen samma sak som en pekare till första positionen i fältet (a==&a[0]). Detta för med sig fyra saker: 1. Vi kan använda ett fältnamn som en pekare. 2. Vi kan använda en pekare som ett fältnamn. 3. Om vi adderar 1 till en pekare som pekar på någon position i ett fält, så får vi en pekare till nästa position i fältet. 4. Att skriva a[5] är exakt samma sak som att skriva *(a + 5). Programmeringsteknik för mediaingenjörer, ht -98 100 Niklas Frykholm, Gunnar Gunnarsson Repetition Funktionen malloc skapar ett minnesutrymme av en viss storlek åt vårt program och returnerar en pekare till det. Vi kan sedan använda pekaren för att lagra information där. int *p; p = malloc(100 * sizeof(int)); p[45] = 14; Det är viktigt att vi håller oss inom det utrymme vi har skapat, annars får vi en krasch. Malloc låter oss bestämma hur stort ett fält skall vara när programmet körs, vilket innebär att vi kan göra våra fält precis lagom stora. När vi är klara med minnet använder vi free för att ge tillbaka minnet till operativsystemet. Efter detta kan vi inte använda minnet mer. free(p); Det är viktigt att ge tillbaka minnet. (Om inga program gjorde det skulle minnet snabbt ta slut.) Minnet ges automatiskt tillbaka när programmet avslutas. Programmeringsteknik för mediaingenjörer, ht -98 101 Niklas Frykholm, Gunnar Gunnarsson /* Kopplar hjärter till siffran 1, ruter till 2, */ /* spader till 3, osv. */ enum {hjarter = 1, ruter = 2, spader = 3, klover = 4}; /* Ruter blir 2 och klöver 11 (räkningen ökar med */ /* 1 automatiskt). */ enum {hjarter = 1, ruter, spader = 10, klover}; /* Hjärter blir 0, ruter 1, osv (räkningen startar */ /* på 0 automatiskt). */ enum {hjarter, ruter, spader, klover}; Programmeringsteknik för mediaingenjörer, ht -98 102 Niklas Frykholm, Gunnar Gunnarsson struct { char titel[50], forfattare[50]; int antal_sidor, pris; float vikt; } bok_1; strcpy(bok_l.titel, "Furstens hus"); strcpy(bok_l.forfattare, "Åke Lundgren"); bok_1.antal_sidor = 162; bok_1.pris = 140; bok_1.vikt = 0.35; Programmeringsteknik för mediaingenjörer, ht -98 103 registrera_inkop(bok_1); registrera_inkop(&bok_1); struct { int i[100]; } a, b; a = b; Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 104 Niklas Frykholm, Gunnar Gunnarsson struct bok { char titel[50], forfattare[50]; int antal_sidor, pris; float vikt; }; struct bok bok_1; struct bok bok_2; Programmeringsteknik för mediaingenjörer, ht -98 105 struct bok las_bok(void) { struct bok boken; printf("Titel: "); scanf("%s", boken.titel); printf("Författare: "); scanf("%s", boken.forfattare); printf("Antal sidor: "); scanf("%i", &boken.antal_sidor); printf("Pris: "); scanf("%i", &boken.pris); printf("Vikt: "); scanf("%f", &boken.vikt); return boken; Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 } 106 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 107 Niklas Frykholm, Gunnar Gunnarsson void skriv_bok(struct bok *b) { printf("Titel: %s\n" "Författare: %s\n" "Antal sidor: %i\n" "Pris: %i\n" "Vikt: %f\n", b->titel, b->forfattare, b->antal_sidor, b->pris, b->vikt); } Programmeringsteknik för mediaingenjörer, ht -98 108 typedef unsigned char u_char; typedef int ifalt[100], *ipek; u_char c; ifalt if; ipek ip; Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 109 Niklas Frykholm, Gunnar Gunnarsson typedef struct nod { ... } nodtyp; /* Nu är båda dessa deklarationer tillåtna. */ struct nod n; nodtyp n; /* Däremot kan vi inte skriva på följande sätt. */ nod n; struct nodtyp n; Programmeringsteknik för mediaingenjörer, ht -98 struct node { int data; struct node *next; }; 110 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 111 Niklas Frykholm, Gunnar Gunnarsson void double_list(struct node *first) { struct node *current = first; while (current != NULL) { current->data *= 2; current = current->next; } } Programmeringsteknik för mediaingenjörer, ht -98 112 Niklas Frykholm, Gunnar Gunnarsson void double_list(struct node *first) { if (first != NULL) { first->data *= 2; double_list(first->next); } } Programmeringsteknik för mediaingenjörer, ht -98 113 Niklas Frykholm, Gunnar Gunnarsson /* Skapar ett nytt element efter e. */ void new_element_after(struct node *e, int data) { struct node *new_e; new_e = malloc(sizeof(struct node)); new_e->data = data; new_e->next = e->next; e->next = new_e; } Programmeringsteknik för mediaingenjörer, ht -98 114 Niklas Frykholm, Gunnar Gunnarsson /* Tar bort posten efter posten e. */ void delete_element_after(struct node *e) { struct node *old = e->next; e->next = old->next; free(old); } Programmeringsteknik för mediaingenjörer, ht -98 115 Niklas Frykholm, Gunnar Gunnarsson int main(void) { FILE *f; int tal; f = fopen("talet.txt", "w"); if (f == NULL) { printf("Filen talet.txt gick inte att öppna!\n"); exit(1); } fprintf(f, "Talet är %d\n", tal); fclose(f); } Programmeringsteknik för mediaingenjörer, ht -98 116 int main(void) { int count; FILE *f = fopen("count.txt", "r"); if (f == NULL) count = 0; else fscanf(f, "%i", &count); fclose(f); count++; f = fopen("count.txt", "w"); if (f==NULL) perror("error"); else fprintf(f, "%i", count); Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 fclose(f); } 117 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 118 int main(void) { FILE *f1 = fopen("fil1.txt", "r"); FILE *f2 = fopen("fil2.txt", "w"); int c; if (f1==NULL || f2==NULL) exit(1); while (1) { c = fgetc(f1); if (c==EOF) break; fputc(c, f2); } fclose(f1); fclose(f2); } Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 119 Niklas Frykholm, Gunnar Gunnarsson FILE *f = fopen("reg.txt", "r"); while(1) { char namn[80], anvnamn[80]; int alder; int res; res = fscanf(f, "%s", anvnamn); if (res == EOF) break; fscanf(f, "%s", namn); fscanf(f, "%i", &alder); if (strcmp("Håkan", namn)==0) printf("Håkan är %i år gammal.\n", alder); } Programmeringsteknik för mediaingenjörer, ht -98 120 Niklas Frykholm, Gunnar Gunnarsson Programmeringsteknik för mediaingenjörer, ht -98 121 Niklas Frykholm, Gunnar Gunnarsson