Løkker, betingelse og arrays.
- skrev denne artikel Fredag, 09 December 2005
forudsætninger: Hvis du har læst og forstået introduktionen så går det nok.

I sidste tutorial lærte vi om variabler, og jeg introducerede betingelser inde i if sætningen havde vi udtrykket mand og jeg forklarede kort at vi her kunne have haft en sammenligning. Når vi sammenligner betingelser gør vi det samme som vi gjorde da vi lærte om uligheder tilbage i folkeskolen vi ser om udtrykket er sandt eller falskt, da tastaturet ikke har en mindre end eller lig med knap improviserer vi denne og større end eller lig med, vi kunne lave en liste over disse operatorer:
==lig med er kun sandt hvis værdierne er ens
>=større end eller lig med er sandt hvis venstre side er større end eller lig med højre side
<=mindre end eller lig med er sandt hvis venstre side er mindre end eller lig med højre side
>større end er sandt hvis venstre side er større end højre side
<mindre end er sandt hvis venstre side er mindre end højre side
!=forskellig fra er kun FALSK hvis værdierne er ens

nogen gange vil vi checke mere end 1 udtryk på denne måde, det kunne f.eks. være at vi ville vide om x var støre end 7 men mindre end y. Dette har vi heldigvis også nemt mulighed for i C, vi har faktisk et sæt af operatorer der gør netop dette:
&&logisk og er sandt hvis og kun hvis både venstresiden og højresiden er sand.
||logisk eller er falskt hvis og kun hvis begge udtryk er falske.
!logisk ikke(not), not operatoren virker på det der står til højre for og inverterer dette

et eksempel på disse operatorer ville nok være på sin plads:
if(!(x!=y||y==z)&&(f>=3||f<x))
dette er noget af en if sætning så lad os se om vi ikke kan forstå den alligevel. Vi starter med en ! så det i parentesen bagefter skal værre falsk for at udtrykket kan blive sandt. Derefter har vi et udtryk efterfulgt af && altså skal begge udtryk være sande samtidig. Så kigger vi på første parentes den er sand hvis x er forskellig fra y eller y har samme værdi som z, der er imidlertid en not på så i disse 2 situationer bliver hele udtrykket falsk og udtrykket efter if eksekveres ikke, hvis x er det samme som y og y er forskellig fra z må vi kigge på næste parentes, denne er samme fremgangsmåde men uden not foran så hvis f er større end eller lig med 3 eller f er mindre end x er denne del sand, igen skal første del være sandt samtidig for at det har en betydning.
Dette udtryk virker måske lidt vildt og vi kunne da også ændre lidt på det, mest af alt vil vi have den der not væk, de er altid overflødige i rent logiske udtryk som dette men nogle gange kan de være nødvendige ved funktionskald. Jeg har allerede lidt røbet hvordan det ser ud uden not på for lidt siden så lad os bare skrive den op uden.
if(x==y&&y!=z&&(f>=3||f<x))
kan du se hvad der skete? not =! er det samme som ==, eller bliver til og, og ! == bliver til !=. havde vi haft større end var det blevet til mindre end eller lig med osv. (hvis du ikke forstår logikken så kig eventuelt på matematisk logik tutorialen, hvor jeg gennemgår simplificering af kompliceret ensformig logik)

men det var jo ikke kun betingelser vi skulle høre om, vi skulle også høre noget om løkker, løkker er en anden form for flow kontrol(if sætninger var den første), forestil dig at du var meget irriteret på en person og ville blære dig lidt med at du kunne lave 10.000 MessageBox'e eller endnu bedre en endeløs mængde af dem, i C er det ikke så svært fordi vi har løkker. En løkke er et stykke kode der kører igen og igen indtil en betingelse er opfyldt, der er 4 typer løkker men den ene er meget dårlig skik (medmindre du koder assembly) så jeg gennemgår kun 3 af dem.
generelt for løkker gæler det at vi putter det kode de skal udfører mellem {} som nævnt i første tutorial er det for at vise dette hører sammen, samme princip kan bruges ved if sætninger hvis de skal gælde for mere end en linie. f.eks.

001   #include <windows.h>
002  
003   int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow){
004    bool x,y,z; //laver 3 bool x, y og z
005    int hs=5,vs=10; //laver variabler til højre side og venstre side og sætter deres værdier nu vi er i gang,
006    int i=0; //laver i og sætter den til 0
007    char output[256];
008    char title[64];
009    strcpy(title,"Jeg håber vi snart kommer til funktioner");
010    x=vs<hs;
011    y=vs>hs;
012    z=vs==hs;
013    if(x){
014      wsprintf(output,"%d er mindre end %d",vs,hs); //vi har ikke brug for sprintf da denne også kan tage floats
015      MessageBox(0,output,title,MB_OK);
016      i++;
017    }
018    if(y){
019      wsprintf(output,"%d er størrer end %d",vs,hs);
020      MessageBox(0,output,title,MB_OK);
021      i++;
022    }
023    if(z){
024      wsprintf(output,"%d er lige så stor som %d",vs,hs);
025      MessageBox(0,output,title,MB_OK);
026      i++;
027    }
028    if(i!=1)
029      MessageBox(0,"hov der er noget galt du har set mere eller mindre end 1 MessageBox","fejl",MB_OK);
030    return 0;
031   }

programmet burde være selvforklarende med hvad du ved indtil nu, det nyeste er måske i++ som betyder det samme som i=i+1, i++ er bare lidt hurtigere at skrive. i++ har også en anden funktion det kan erstatte i, i dette tilfælde tages i's værdi før der lægges 1 til, ønsker man først at lægge en til og derefter bruge i's værdi skriver man i stedet ++i. Den anden ændring er fra sprintf til wsprintf, årsagen er at med wsprintf kan stdio.h undværes wsprintf har bare ikke %f til floats så den tager ikke imod komma tal.
Men nu var det jo løkker og ikke if sætninger det skulle handle om, den første er selvfølgelig den simpleste, dette er en while løkke, en while løkke kører så længe betingelsen i den er sand, while løkkens syntaks er while(betingelse), igen kan { og } bruges til at vise hvilke linier løkken gælder over (ellers gælder den kun over 1 linie). hvis betingelsen for en while løkke er falsk starter løkken aldrig.
Som alternativ til while løkken har vi do while løkken, den virker næsten lige som en while løkke men den checker først betingelsen efter løkken er kørt syntaxis for do while, er do{}while(betingelse) hvor sætningerne der skal udføres er mellem { og }, nå den når bunden checker den betingelsen er det sandt hopper den tilbage til do.
Den sidste mulighed er for løkken, for løkken er delt i tre dele den har et initialiserings område et betingelses område og et inkrementerings område, det første køres en gang når løkken starter og kan bruges til at sætte en start værdi for f.eks. en tæller, det andet er en betingelse ligesom den i while løkken, det sidste er et felt som normalt bruges til at tælle en op på en tæller, de tre dele er separeret af ; undertiden kan man benytte , hvis man vil have flere aen ene slags eksempelvis flere variabler der sættes til 0 når løkken starter. for løkker bruges ofte hvis man kan se på problemet som noget der skal tælles.
jeg vil nu give et eksempel på hver type løkke:

001   #include <windows.h>
002  
003   int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow){
004    char output[256];
005    int i=0; //vi bruger i til at tælle med
006    int max=3;
007    while(++i<max){
008      wsprintf(output,"Jeg kan tælle til %d",i);  //tæller 1,2,3 osv.
009      MessageBox(0,output,"While",MB_OK);
010    }
011    i=0;
012    do{
013      wsprintf(output,"Jeg kan tælle til %d",i);  //tæller 0,1,2,3 osv.
014      MessageBox(0,output,"Do-While",MB_OK);
015    }while(++i<max);
016    for(i=0;i<max;i++){
017      wsprintf(output,"Jeg kan tælle til %d",i);  //tæller 0,1,2,3 osv.
018      MessageBox(0,output,"For",MB_OK);
019    }
020    return 0;
021   }


Prøv at sætte max til forskellige værdier (nok ikke over 5 for så er de da kedelige at klikke væk de bokse :-P), prøv f.eks. -1 eller 0 så er do while den eneste der kører. Prøv også at sætte ++ efter i hvad sker der så(gæt før du prøver det er sjovest at se man har ret).
så mangler vi vidst 'kun' arrays indtil nu har vi set på char output[256] som en variabel der kunne indeholde 255 bogstaver, men det er ikke hele forklaringen, i virkeligheden er char en variabeltype der kan indeholde et bogstav [] indikerer at der er tale om et array og tallet inde i hvor mange pladser dette array har, forestil dig at du skulle skrive et program der lavede et tal om til navnet på en måned, det ville kræve utroligt mange if sætninger eller hvis man var lidt smart kunne man måske lave en liste over navne på måneder, og det er faktisk hvad arrays er, lister. Disse lister kan f.eks. være lister af heltal (integer array, int a[256]) eller lister af bogstaver som vi har set indtil nu. Et problem der opstår med lister er at vi ikke direkte kan sammenligne dem med andre lister, heldigvis er der ofte lavet funktioner til at gøre netop dette og ellers kan de hurtigt skrives (se mere om dette under lister).
Som eksempel på arrays kan vi jo tage de måneder jeg skrev om tidligere, men så kommer vi til et nyt begreb, multidimensionale array, dette kan vi se på som eksempelvis en liste af lister, da en tekststreng i sig selv er en list og da vi for at have alle månederne med er nødt til at have mere end 1 navn for en måned har vi en liste af tekststrenge dvs. en liste af arrays, forvirret? Du er helt sikkert ikke den eneste men det er ikke så mystisk igen når man først vender sig til det (kig eventuelt på det som matricer fra matematikken når de er i 2 dimensioner).
Lad os tage et eksempel inden vi går videre:

001   #include <windows.h>
002  
003   int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow){
004    int maaned=12; //vi er lige nu i december
005    char mNavn[12][64]; // der er 12 måneder og der er ingen af dem på over 63 bogstaver
006    strcpy(mNavn[ 0],"Januar");
007    strcpy(mNavn[ 1],"Febuar");
008    strcpy(mNavn[ 2],"Marts");
009    strcpy(mNavn[ 3],"April");
010    strcpy(mNavn[ 4],"Maj");
011    strcpy(mNavn[ 5],"Juni");
012    strcpy(mNavn[ 6],"Juli");
013    strcpy(mNavn[ 7],"August");
014    strcpy(mNavn[ 8],"September");
015    strcpy(mNavn[ 9],"Oktober");
016    strcpy(mNavn[10],"November");
017    strcpy(mNavn[11],"December");
018    MessageBox(0,mNavn[maaned-1],"vi er lige nu i:",MB_OK);
019   }


skift variablen maaned så du kan se det virker. Bare husk den skal stå mellem 1 og 12 for ellers risikerer du at der sker slemme ting med din computer (sæt eventuelt selv if sætningen ind som sikrer mod fejl).
Som du sikkert kan se starter jeg ved 0, alle arrays i C starter ved 0 og hvis jeg ville lave det om til 1 skulle jeg dimensionere mit array til 13 i stedet, dette ville så reservere 64 byte unødvendigt og dette vil vi ALTID gerne undgå (lad være med at klage over at der ikke er nogen måneder på 63 bogstaver alligevel).
Noget andet du lige bør bemærke er måden vi tager elementer ud af disse lister mNavn[0] er element 0 i arrayet mNavn, havde vi skulle bruge første bogstav i element 3 havde vi skrevet mNavn[3][0], dette er i vores tilfælde 'A'.
vi kan godt sætte værdierne i et array mens vi opretter det, og hvis vi gør behøver vi ikke at sige hvor stort det skal være (selvom dette ofte er klogt at gøre alligevel). et eksempel kunne være linien:
int pelle[5]={1,2,3,4,5};
dette ville lave et array 5 pladser langt og på plads 0 ville der stå 1 plads 1 ville der stå 2 osv. Skal man gennemløbe et array for data bruger man næsten altid for løkker, vi kunne f.eks. tage en for lykke der tæller antallet af bogstaver i en streng nu ved vi, at vi udelukkende skal bruge denne streng som en konstant så lad os sætte const foran så kan vi ikke senere ændre indholdet nu vil jeg så også gå med til at vi kan undlade at fortælle nøjagtigt hvor stort vores array er.

001   #include <windows.h>
002  
003   int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpszArgument,int nCmdShow){
004    int i,mellemrum;
005    char output[512];
006    const char streng[]="Tæl antallet af mellemrum i denne streng";
007    for(i=0,mellemrum=0;streng[i];i++)
008      if(streng[i]==' ')
009        mellemrum++;
010    wsprintf(output,"der er %d mellemrum i strengen \"%s\"",mellemrum,streng);
011    MessageBox(0,output,"færdig!",MB_OK);
012   }


OK lad os kigge lidt på de små tricks jeg har brugt undervejs,
i linie 6 har jeg lavet en streng kaldet streng og uden at specificere hvor stor den er, årsagen til at det normalt er dumt er at jeg senere kunne komme til at gemme i denne streng, og hvis det jeg gemmer er stører end det der er i forvejen falder jeg ud af arrayet og begynder at skrive steder i hukommelsen hvor jeg næppe laver små skader.
i linie 7 har jeg en for løkke der sætter både i og mellemrum til 0, jeg kunne bare have skrevet i=mellemrum=0; men jeg syntes jeg ville give et eksempel på flere initialiseringer i en for løkke. Under betingelsen kan det godt se lidt mystisk ud hvis man da ikke lige husker på at alle strenge i C slutter med ascii værdien 0 og at se ser alt andet end 0 som sandt.
i linie 8 ser jeg om der på plads i er et mellemrum, startende med plads 0 for der starter alle arrays i C jo. hvis det er mellemrum lægger jeg 1 til variablen mellemrum, læg mærke til at der er forskel på ' ' og " " da " " er en streng bestående af 2 tegn (mellemrum og ascii 0) mens ' ' er et tegn.
i linie 10 viser jeg hvordan man får " ind som et egn, man sætter simpelthen bare \ foran, skulle man bruge et \ ville man skrive \\ skal man bruge et ascii 0 skriver man \0, linieskift har vi set det er \n der er flere af den slags, men de andre må du selv finde og ellers giver jeg nogle stykker i andre tutorials (blandt andet et sted hvor windows og C er uenige om linieskift).

Nu forstår du forhåbentlig hvad et array er og du har lært nogle små tricks, du kan finde ud af at bruge løkker og kan skrive logiske udtryk der får enhver til at flå håret af i et forsøg på af forstå det.

har du spørgsmål så skriv til mig på:
admin@AODASoft.net