Dagens tema INF1070. Vektorer (array er) Tekster (string er) Adresser og pekere. Dynamisk allokering

Like dokumenter
Vektorer. Dagens tema. Deklarasjon. Bruk

Dagens tema INF1070. Vektorer (array-er) Tekster (string-er) Adresser og pekere. Dynamisk allokering

Dagens tema. C-programmering. Nøkkelen til å forstå C-programmering ligger i å forstå hvordan minnet brukes.

Dagens tema. C-programmering. Nøkkelen til å forstå C-programmering ligger i å forstå hvordan minnet brukes.

Dagens tema C, adresser og pekere

Ark 3 av 26. printf("i adresse %08x ligger b med verdien %d.\n", &b, b); printf("i adresse %08x ligger a med verdien %d.

Programmeringsspråket C Del 2. Michael Welzl

Programmeringsspråket C Del 2

Programmeringsspråket C Del 2

Programmeringsspråket C Del 2

Dagens tema. Adresser som parametre Dynamisk allokering Signaturer Definisjon av nye typenavn Typekonvertering Pekere og vektorer

Dagens tema: INF2100. Utvidelser av Minila array-er. tegn og tekster. Flass- og Flokkode. prosedyrer. Prosjektet struktur. feilhåndtering.

IN 147 Program og maskinvare

IN 147 Program og maskinvare

Programmeringsspråket C Del 3

Programmeringsspråket C Del 3

Programmeringsspråket C Del 3

Dagens tema. Kort repetisjon om rutiner. Programmering i C Variable og adresser. Vektorer. Tekster. Preprosessoren. Separat kompilering

Programmeringsspråket C Del 3

Offentlig utvalg for punktskrift, OUP Norsk standard for 8-punktskrift punktskrift 24. oktober 2004 sist endret

Velkommen til INF2100. Bakgrunnen for INF2100. Hva gjør en kompilator? Prosjektet. Jeg er Dag Langmyhr

Programmeringsspråket C

Digital representasjon

Dagens tema. Rutiner i LC-2 Og her er tilsvarende kode for LC-2: Funksjoner i C Her er det samme programmet i C: Kort repetisjon om rutiner

Digital representasjon

Velkommen til INF2100

Digital representasjon

IN 147 Program og maskinvare

Velkommen til INF2100

Datamaskinen LC-2. Dagens tema. Tall i datamaskiner Hvorfor kan LC-2 lagre tall i intervallet ? Hvorfor er det akkurat celler i lageret?

Dagens tema. Datamaskinen LC-2 En kort repetisjon. Binære tall Litt om tallsystemer generelt. Binære tall. Heksadesimale og oktale tall

Dagens tema INF2270. Cs preprosessor. Separat kompilering av C funksjoner. C og minnet. Dag Langmyhr,Ifi,UiO: Forelesning 5. februar 2007 Ark 1 av 15

Del 1 En oversikt over C-programmering

Dagens tema. Dynamisk allokering Signaturer Definisjon av typer og nye typenavn Typekonvertering Pekere, vektorer og lister Dokumentasjon

Dagens tema INF1070. Signaturer. Typekonvertering. Pekere og vektorer. struct-er. Definisjon av nye typenavn. Lister

Kapittel 1 En oversikt over C-språket

Signaturer. Dagens tema. En vanlig feil int-funksjon. Dette kan noen ganger gi rare feilmeldinger: INF1070 INF1070 INF1070 INF1070

IN 147 Program og maskinvare

Programmeringsspråket C

Del 4 Noen spesielle C-elementer

Del 2 Tabeller, arrays, strenger

Programmeringsspråket C Del 3. Michael Welzl

Programmeringsspråket C

ISO Dagens tema. Tegn. Uttrykk. I Minila lagres kun heltall, men de kan tolkes som tegn. Det siste om Minila.

OPPGAVE 1 OBLIGATORISKE OPPGAVER (OBLIG 1) (1) Uten å selv implementere og kjøre koden under, hva skriver koden ut til konsollen?

Del 3. Pekere RR 2016

i=0 Repetisjon: arrayer Forelesning inf Java 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker 0*0 0*2 0*3 0*1 0*4

Forelesning inf Java 4

Dagens tema. Mer om C Enkle datatyper Sammensatte datatyper: Vektorer og matriser Tekster Mengder Strukturer Unioner Ringbuffere

INF1000 : Forelesning 4

INF1000 (Uke 5) Mer om løkker, arrayer og metoder

i=0 i=1 Repetisjon: nesting av løkker INF1000 : Forelesning 4 Repetisjon: nesting av løkker Repetisjon: nesting av løkker j=0 j=1 j=2 j=3 j=4

Cs preprosessor. Dagens tema. Betinget kompilering

Dagens tema: Datastrukturer

Programmeringsspråket C Del 3. Hans Petter Taugbøl Kragset

INF1000: Forelesning 7. Konstruktører Static

INF1000: Forelesning 7

Forelesning inf Java 5

Forelesning inf Java 5

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

Dagens tema. Cs preprosessor Separat kompilering av C-funksjoner C og minnet Oversikt over operatorene

Pekere og vektorer. Dagens tema. I C gjelder en litt uventet konvensjon:

Dagens tema. Det siste om C Pekere og vektorer. Pekere til pekere. Vanlige pekerfeil. struct-er og typedef. Lister. Feilsøking

2 Om statiske variable/konstanter og statiske metoder.

IN 147 Program og maskinvare

Dagens tema. Oppsummering om assemblerspråk. Programmering i C. Bakgrunn. Et minimalt eksempel med forklaring. Datatyper i C.

Velkommen til INF2100

Løsningsforslag ukeoppg. 6: 28. sep - 4. okt (INF Høst 2011)

INF1000 EKSTRATILBUD. Stoff fra uke 1-5 (6) 3. oktober 2012 Siri Moe Jensen

Innhold uke 4. INF 1000 høsten 2011 Uke 4: 13. september. Deklarasjon av peker og opprettelse av arrayobjektet. Representasjon av array i Java

public static <returtype> navn_til_prosedyre(<parameter liste>) { // implementasjon av prosedyren

Programmeringsspråket C Del 2. Hans Petter Taugbøl Kragset

INF 1000 høsten 2011 Uke september

INF1000 undervisningen INF 1000 høsten 2011 Uke september

Objekter og referanser

Hvordan en prosessor arbeider, del 1

Dagens program. Operativsystemer Prosesser og systemkall i UNIX Hente prosessens nummer Starte prosesser Vente på prosesser Utføre programmer

Oppgavene 1, 2, 4, 5, 6, 9, 12 og 13 passer best til å løses ved en datamaskin.

Repetisjon: Statiske språk uten rekursive metoder (C1 og C2) Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

Dagens tema Kjøresystemer (Ghezzi&Jazayeri 2.6, 2.7)

UNIVERSITETET I OSLO

Fra Python til Java, del 2

INF Uke 10. Ukesoppgaver oktober 2012

Dagens tema. Cs preprosessor Separat kompilering av C-funksjoner C og minnet Oversikt over operatorene

Dagens tema INF1070. Info om C. Cs preprosessor. Feilsøking. Dag Langmyhr,Ifi,UiO: Forelesning 31. januar 2005 Ark 1 av 29

Informasjon om C. Dagens tema INF1070 INF1070 INF1070 INF1070. Den viktigste kilden til informasjon om C (utenom en god. C-funksjonene.

IN 147 Program og maskinvare

Debuggere En «debugger» er et meget nyttig feilsøkingsverktøy. Det kan analysere en program dump, Dagens tema INF1070 INF1070 INF1070 INF1070

UNIVERSITETET I OSLO

Kort repetisjon av doble (nestede) løkker Mer om 1D-arrayer Introduksjon til 2D-arrayer Metoder

Praktisk informasjon. Repetisjon: While-løkker. I dag. INF1000 (Uke 5) Mer om løkker, arrayer og metoder. Oblig 2 er lagt ut

Oving 2. Oppgave 1. #include <stdio.h> int main(int argc, char **argv) { char *navn = argv[1]; printf ("Navnet ditt er %s\n", navn); } Oppgave 2

Velkommen til INF2100 Jeg er Dag Langmyhr

Oversikt. INF1000 Uke 1 time 2. Repetisjon - Introduksjon. Repetisjon - Program

Programmering i C++ Løsningsforslag Eksamen høsten 2005

Array&ArrayList Lagring Liste Klasseparametre Arrayliste Testing Lenkelister

OBJEKTER SOM EN PROGRAMMERINGS-TEKNIKK

Praktisk informasjon. I dag. Repetisjon: While-løkker. INF1000 (Uke 5) Mer om løkker, arrayer og metoder

Transkript:

Dagens tema Vektorer (array er) Tekster (string er) Adresser og pekere Dynamisk allokering Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 1 av 23

Vektorer Alle programmeringsspråk har mulighet til å definere en såkalte vektor (også kalt matrise eller «array» på engelsk). Dette er en samling variable av samme type hvor man bruker en indeks til å skille dem. Deklarasjon I C deklareres vektorer ved å sette antallet elementer i hakeparenteser etter variabelnavnet: char a, b[4], c;. x3008?? a x3009?? b x300a?? x300b?? x300c?? x300d?? c. Antallet elementer må være en konstant. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 2 av 23

Bruk Ved bruk angir indeksen hvilket element vi ønsker. I C er alltid første element nr. 0, neste nr. 1, osv. a = 3; b[0] = 7; b[a] = 8; Etter dette er situasjonen:. x3008 3 a x3009 7 b x300a?? x300b?? x300c 8 x300d?? c. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 3 av 23

Beregning av adresse Adressen til vanlige variable er kjent men adressen til vektorelementer må beregnes. Formelen er Startadresse + Indeks Størrelse Størrelse over 1 byte Anta at int er 4 byte. int a, b[4], c; x3008?? a x300c?? b x3010?? x3014?? x3018?? x301c?? c Hva skjer med ulovlig indeks? I C sjekkes ikke indeksen. Dette gjør det mulig å ødelegge andre variable, kode eller i noen tilfelle hele systemet... Dette er ikke helt sant, men vi kan tro det er slik en stund. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 4 av 23

Tekster I C lagres tekster som tegnvektorer med en spesiell konvensjon: Etter siste tegn står en byte med verdien 0. Variable Når man deklarerer en tekstvariabel, må man angi hvor mange tegn det er plass til (samt plass til 0 byten). char str[6]; Tekstvariabel str har plass til 5 tegn. En byte med verdien 0 er ikke det samme som sifferet «0»; sifferet «0» er representert av verdien 48, som vist på neste lysark. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 5 av 23

0 000 00 1 001 01 2 002 02 3 003 03 4 004 04 5 005 05 6 006 06 7 007 07 8 010 08 9 011 09 10 012 0A 11 013 0B 12 014 0C 13 015 0D 14 016 0E 15 017 0F 16 020 10 17 021 11 18 022 12 19 023 13 20 024 14 21 025 15 22 026 16 23 027 17 24 030 18 25 031 19 26 032 1A 27 033 1B 28 034 1C 29 035 1D 30 036 1E 31 037 1F ISO 8859 1 32 0! " # $ % & ( ) * +,. / 0 1 2 3 4 5 6 7 8 9 : ; < = >? 04 20 33 041 @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ a b c d e f g h i j k l m n o p q r s t u v w x y z { } ~ 21 41 61 34 042 66 102 98 142 22 42 62 35 043 67 103 99 143 23 43 63 36 044 68 104 100 144 24 44 64 37 045 69 105 101 145 25 45 65 38 046 70 106 102 146 26 46 66 39 047 71 107 103 147 27 47 67 40 050 72 110 104 150 28 48 68 41 051 73 111 105 151 29 49 69 42 052 74 112 106 152 2A 4A 6A 43 053 75 113 107 153 2B 4B 6B 44 054 76 114 108 154 2C 4C 6C 45 055 77 115 109 155 2D 4D 6D 46 056 78 116 110 156 2E 4E 6E 47 057 79 117 111 157 2F 4F 6F 48 060 80 120 112 160 30 50 70 49 061 81 121 113 161 31 51 71 50 062 82 122 114 162 32 52 72 51 063 83 123 115 163 33 53 73 52 064 84 124 116 164 34 54 74 53 065 85 125 117 165 35 55 75 54 066 86 126 118 166 36 56 76 55 067 87 127 119 167 37 57 77 56 070 88 130 120 170 38 58 78 57 071 89 131 121 171 39 59 79 58 072 90 132 122 172 3A 5A 7A 59 073 91 133 123 173 3B 5B 7B 60 074 92 134 124 174 3C 5C 7C 61 075 93 135 125 175 3D 5D 7D 62 076 94 136 126 176 3E 5E 7E 63 077 95 137 127 177 3F ª «± ² ³ µ ¹ º» ¼ ½ ¾ À Á Â Ã Ä Å Æ Ç È É Ê Ë Ì Í Î Ï Ð Ñ Ò Ó Ô Õ Ö Ø Ù Ú Û Ü Ý Þ ß 64 100 96 140 128 200 160 240 192 300 40 60 65 101 97 141 5F 7F 80 129 201 81 130 202 82 131 203 83 132 204 84 133 205 85 134 206 86 135 207 87 136 210 88 137 211 89 138 212 8A 139 213 8B 140 214 8C 141 215 8D 142 216 8E 143 217 8F 144 220 90 145 221 91 146 222 92 147 223 93 148 224 94 149 225 95 150 226 96 151 227 97 152 230 98 153 231 99 154 232 9A 155 233 9B 156 234 9C 157 235 9D 158 236 9E 159 237 9F A0 161 241 à á â ã ä å æ ç è é ê ë ì í î ï ð ñ ò ó ô õ ö ø ù ú û ü ý þ ÿ A1 C1 E1 162 242 194 302 226 342 A2 C2 E2 163 243 195 303 227 343 A3 C3 E3 164 244 196 304 228 344 A4 C4 E4 165 245 197 305 229 345 A5 C5 E5 166 246 198 306 230 346 A6 C6 E6 167 247 199 307 231 347 A7 C7 E7 168 250 200 310 232 350 A8 C8 E8 169 251 201 311 233 351 A9 C9 E9 170 252 202 312 234 352 AA CA EA 171 253 203 313 235 353 AB CB EB 172 254 204 314 236 354 AC CC EC 173 255 205 315 237 355 AD CD ED 174 256 206 316 238 356 AE CE EE 175 257 207 317 239 357 AF CF EF 176 260 208 320 240 360 B0 D0 F0 177 261 209 321 241 361 B1 D1 F1 178 262 210 322 242 362 B2 D2 F2 179 263 211 323 243 363 B3 D3 F3 180 264 212 324 244 364 B4 D4 F4 181 265 213 325 245 365 B5 D5 F5 182 266 214 326 246 366 B6 D6 F6 183 267 215 327 247 367 B7 D7 F7 184 270 216 330 248 370 B8 D8 F8 185 271 217 331 249 371 B9 D9 F9 186 272 218 332 250 372 BA DA FA 187 273 219 333 251 373 BB DB FB 188 274 220 334 252 374 BC DC FC 189 275 221 335 253 375 BD DD FD 190 276 222 336 254 376 BE DE FE 191 277 223 337 255 377 BF 224 340 C0 E0 193 301 225 341 DF FF April 1995, DFL, Ifi/UiO Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 6 av 23

Kopiering av tekst Flytting av tekst skjer med standardfunksjonen strcpy: #include <stdio.h> char *strcpy (char til[], char fra[]) { int i = 0; } while (1) { til[i] = fra[i]; if (fra[i] == 0) return til; ++i; } int main (void) { char t[10]; int i; } strcpy(t, "abc"); for (i = 0; i < 10; ++i) { printf("t[%2d] = %4d = %c \n", i, t[i], t[i]); } return 0; Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 7 av 23

Før. x3010?? t x3011?? x3012?? x3013?? x3014?? x3015?? x3016?? x3017?? x3018?? x3019?? x301a a "abc" x301b x301b b c x301d 0. Etter. x3010 a str x3011 x3012 b c x3013 0 x3014?? x3015?? x3016?? x3017?? x3018?? x3019?? x301a a "abc" x301b x301c b c x301d 0. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 8 av 23

Her er utskriften fra kjøringen: t[ 0] = 97 = a t[ 1] = 98 = b t[ 2] = 99 = c t[ 3] = 0 = t[ 4] = 40 = Ø t[ 5] = 92 = \ t[ 6] = 112 = p t[ 7] = 0 = t[ 8] = 120 = x t[ 9] = 124 = Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 9 av 23

Andre tekstoperasjoner strlen(str) beregner den nåværende lengden av teksten i str. (Dette gjør den ved å lete seg frem til 0 byten.) strcat(str1,str2) utvider teksten i str1 med den i str2. strcmp(str1,str2) sammenligner de to tekstene. Returverdien er < 0 om str1 < str2 0 om str1 = str2 > 0 om str1 > str2 sprintf(str, "... ", v1, v2,... ) fungerer som printf men resultatet legges i str i stedet for å skrives ut. Hva om teksten er for lang? Siden tekstvariable er vektorer, er det ingen sjekk på plassen. Det er derfor fullt mulig å ødelegge for seg selv (og noen ganger for andre). Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 10 av 23

Variable, adresser og pekere Variable ligger lagret i hurtiglageret (ofte kalt RAM) i en eller annen adresse. 0xFFFFFFFC 0xFFFFFFF8 0xFFFFFFF4 0xFFFFFFF0 : 0x0000000C 0x00000008 0x00000004 0x00000000 Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 11 av 23

Operatoren & I C kan man få vite i hvilken adresse en variabel ligger ved å bruke operatoren &. #include <stdio.h> int a, b, c; int main(void) { printf("skriv to tall: "); scanf("%d", &a); scanf("%d", &b); c = a + b; printf("summen er %d.\n", c); } printf("i adresse %08x ligger a med verdien %d.\n", &a, a); printf("i adresse %08x ligger b med verdien %d.\n", &b, b); printf("i adresse %08x ligger c med verdien %d.\n", &c, c); Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 12 av 23

La oss kjøre dette programmet: Skriv to tall: 47 9 Summen er 56. I adresse 00020e00 ligger a med verdien 47. I adresse 00020e04 ligger b med verdien 9. I adresse 00020e08 ligger c med verdien 56. NB! Det kan variere fra gang til gang hvilke adresser man får. Her ser vi at variablene ligger pent etter hverandre og at hver av dem opptar 4 byte. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 13 av 23

Pekervariable I C kan vi legge adresser i variable; disse deklareres med en stjerne: int v, *p; Her er v en vanlig variabel mens p er en peker som kan peke på int variable. (Vi må alltid oppgi hva slags variable pekere skal peke på.) Bruk av pekervariable Vi kan sette adressen til variable inn i pekervariabelen; vi sier at vi får pekeren til å «peke på» variabelen. p = &v; Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 14 av 23

Vi kan «følge en peker» ved å bruke operatoren *; da får vi variabelen som pekeren peker på. v = 7; printf("v = %d, *p = %d.\n", v, *p); v = 17; printf("v = %d, *p = %d.\n", v, *p); Denne koden skriver ut v = 7, *p = 7. v = 17, *p = 17. Både v og *p angir altså samme variabel: *p = 123; printf("v = %d, *p = %d.\n", v, *p); Utskriften av denne koden er v = 123, *p = 123. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 15 av 23

Et eksempel La oss lage en funksjon som bytter om de to parametrene sine. Til selve ombyttingen trengs en hjelpevariabel: temp = v1; v1 = v2; v2 = temp; Her er hele programmet: #include <stdio.h> void swap (int v1, int v2) { int temp; } temp = v1; v1 = v2; v2 = temp; int main (void) { int a = 3; int b = 4; } printf("før: a = %d og b = %d\n", a, b); swap(a, b); printf("etter: a = %d og b = %d\n", a, b); Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 16 av 23

Når vi kjører programmet, får vi en overraskelse: Før: a = 3 og b = 4 Etter: a = 3 og b = 4 Grunnen er: Parametre overføres som verdier i C (som i Java). Følgelig er det bare lokale kopier som endres. Når funksjonen er ferdig, er alt glemt. Løsning Løsningen er å overføre pekere til de to variablene i stedet for verdiene. Pekerne overføres som kopier, men vi kan allikevel endre det de peker på. Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 17 av 23

#include <stdio.h> void swap (int *v1, int *v2) { int temp; } temp = *v1; *v1 = *v2; *v2 = temp; int main (void) { int a = 3, b = 4; } printf("før: a = %d og b = %d\n", a, b); swap(&a, &b); printf("etter: a = %d og b = %d\n", a, b); Legg merke til at både funksjonsdeklarasjonen og kallet er endret! Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 18 av 23

Når dette programmet kjører, skjer alt som vi forventer: Før: a = 3 og b = 4 Etter: a = 4 og b = 3 Konklusjon om parametre Det er ulike måter å overføre parametre på. I C og i Java brukes verdioverføring. Man kan allikevel oppdatere variable ved å sende over pekere til dem. Dette gjøres for eksempel i scanf("%d", &v); Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 19 av 23

Dynamisk allokering Ofte trenger man å opprette objekter under kjøringen i tillegg til variablene. Standardfunksjonen malloc («memory allocate») benyttes til dette. Parameter er antall byte den skal opprette; operatoren sizeof kan gi oss dette. Vi må ha med stdlib.h for at malloc skal fungere skikkelig. #include <stdlib.h>... int *p;... p = malloc(sizeof(int)); Frigivelse av objekter Når objekter ikke trengs mer, må de gis tilbake til systemet med funksjonen free: free(p); Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 20 av 23

Et eksempel Anta at vi skal lese et navn (dvs en tekst) og skrive det ut. For at navnet ikke skal oppta plass når vi ikke trenger det, bruker vi dynamisk allokering. char *navn; : printf("hva heter du? "); navn = malloc(200); scanf("%s", navn); printf("hei, %s.\n", navn); free(navn); Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 21 av 23

Hva hvis noe går galt? Følgende Java program inneholder en feil: 1 class Feil { 2 void m() { 3 } 4 5 public static void main (String args[]) { 6 Feil fp = null; 7 8 fp.m(); 9 } 10 } Når vi kjører det, får vi beskjed om hva som gikk galt: > javac Feil.java > java Feil Exception in thread "main" java.lang.nullpointerexception at Feil.main(Feil.java:8) Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 22 av 23

Her er et C program med tilsvarende feil: 1 #include <stdio.h> 2 3 int main (void) 4 { 5 char *s; 6 7 strcpy(s, "Abc"); 8 return 0; 9 } Når vi kompilerer og kjører det, skjer følgende: > gcc feil.c o feil >./feil Segmentation fault Konklusjon Vær nøye med å få programmet riktig. (Vi kommer ellers tilbake med verktøy for feilfinning siden.) Dag Langmyhr,Ifi,UiO: Forelesning 23. januar 2006 Ark 23 av 23