
			  
			  UTTRYCK OCH SATSER


Vi har nu en lngre tid svngt oss med termerna uttryck och sats utan att 
egentligen veta vad vi talar om, s det r dags att reda ut begreppen.

En sats r ungefr detsamma som i de flesta andra programsprk, allts ett
grundlggande programsteg. Vanligen ingr det uttryck i satser.

Ett uttryck bestr av operatorer och operander. En ensam operand utan opera-
tor r den enklaste formen av uttryck, sedan kan de bli hur komplicerade som
helst. Vi tar ett par exempel:

		7

		- q

		11 + c

		7 * (11 - c * a + 5 / b) / q

		c = 5 / 7

		q = c + a

		c < 7

Operanderna r konstanter eller variabler eller kombinationer av bdadera. 
Mer komplicerade uttryck bestr oftast av flera uttryck, deluttryck.

I C har alla uttryck ett vrde. Det r bara att evaluera uttrycket i den ord-
ning som anges av operatorernas prioritet. Om det finns ett likhetstecken i
uttrycket som i ett par av exemplen ovan s blir vrdet av uttrycket detsamma
som vrdet av variabeln till vnster om likhetstecknet. Uttryck med rela-
tionsoperatorer fr vrdet 1 om relationen r sann, annars 0. Dessa regler 
gr ibland att uttryck kan se aningen underliga ut fr den som r van vid den
mer konventionella aritmetiken:

		c = 5 + ( 7 > 2 ) + ( b = 11 + 3 )

Vrdet av detta uttryck blir helt enkelt 20, eftersom det r en summa av tre
deluttryck som vart och ett har sitt vrde. 

En sats skiljer sig till utseendet frn ett uttryck genom att den avslutas 
med ett semikolon. Funktionsmssigt r skillnaden den att satsen utfr ngot.
Sledes r vrt senaste exempel ovan ett uttryck med ett visst vrde, medan
om vi stter ett semikolon efter s blir det en sats som ber datorn att be-
rkna vrdet av uttrycket och lagra resultatet i den minnesposition som sva-
rar mot variabeln c. Den enklaste satsen man kan tnka sig innehller inte 
ens ngot uttryck:

			;

Detta r den tomma satsen, den innehller ingenting och gr ingenting heller.
Den kan dock vara till nytta ibland dr C fordrar en sats men det inte finns
ngot vettigt att utfra, eller om man i kllkoden srskilt vill utmrka ett 
stlle.



		        	BLOCK 	


Ett block r en sammansatt sats, bestende av flera satser placerade inom 
klammer. Den konstruktionen anvnds nr man mste utfra flera satser i ett
sammanhang dr det normalt skulle vara en enda, till exempel i en while-sats.
Utifrn sett behandlas blocket som en enda sats. Det r inget som hindrar att
ett block innehller flera block som i sin tur kan innehlla block som ... 



			    PROGRAMSTYRNING


Mnga anser att en dator ska anvndas till det trkiga och monotona berk-
ningsarbetet och verlta fattandet av kloka beslut till mnniskan. Emeller-
tid har datorn en inte fraktlig kapacitet ven fr snabbt beslutsfattande
som man kan dra nytta av. Till det ndamlet finns det i C liksom i alla 
andra programsprk, instruktioner som lter datorn vlja alternativ och vara
logisk mer allmnt. 



			OM SANNING OCH LGN I C


Under avsnittet om logiska operatorer konstaterade vi helt kort att i C s
r vrdet 0 och 0.0 alltid falskt medan allt annat r sant. C r allts
ganska generst med sanningen och detta kan f ovntade konsekvenser om man
inte aktar sig. Om man dessutom inte lyckas hlla reda p skillnaden mellan
tilldelningsoperatorn = och den logiska operatorn == s r man verkligen illa
ute. Vi visar det med ett enkelt exempel:

 	1	bulle = 5

 	2	kaka = 0

 	3	kanelbulle == 5

De tv frsta exemplen r tilldelningar, och vrdet av uttrycken r alltid
detsamma som vrdet av variabeln till vnster. Uttrycket bulle = 5 r allts
alltid sant, medan uttrycket kaka = 0 alltid r falskt. Det tredje uttrycket
kanelbulle == 3 undersker om variabeln kanelbulle r lika med 5, och i s 
fall blir vrdet av uttrycket lika med 1, allts sant. Annars blir vrdet 
lika med noll, allts falskt. I en if-sats och andra logiska sammanhang r 
det nog oftast denna senare variant man r ute efter, s se upp med vilken
operator du anvnder.



				IF-SATSEN


Vi frsker att fr en gngs skull vara lika logiska som datorn och brjar
med att sammanfatta if-satsen och dess olika former:

  	1	if ( uttryck )
		   
  		   sats


  	2	if ( uttryck )

  		      sats 1

  		   else

  		      sats 2


  	3	if ( uttryck 1 )

  		      sats 1

  		   else if ( uttryck 2 )

  		      sats 2

  		   else
 		
  		      sats 3  


I samtliga fall kan "sats" vara en enkel sats eller ett block av satser, som
ven kan innehlla if-satser. 

I det frsta fallet utfrs "sats" om "uttryck" r sant.

I det andra fallet utfrs "sats 1" om "uttryck" r sant, annars "sats  2".

I det tredje fallet utfrs "sats 1" om "uttryck 1" r sant, annars om " ut-
tryck 2" r sant utfrs "sats 2", och om bda uttrycken r falska utfrs
"sats 3". Denna variant av if-satsen kan utvidgas till godtyckligt antal val
genom att flera "if else" lggs till.

Om man har flera if-satser inuti varandra s kan det vara lite trassligt att
hlla reda p till vilket if som ett else ska hnfra sig. Den enda och enkla
regeln r att i C hr ett else ihop med det nrmast fregende if som inte 
redan har ett eget else. Om du vill stta dig ver den regeln mste du gra
det med hjlp av klamrar.


                                 ?

Villkorsoperatorn ?: kan i vissa sammanhang helt erstta en if-else-konstruk-
tion av den enklaste sorten. Villkoret fr det r bara att bde if och else
mste hnfra sig till enkla uttryck, inte satser. Den allmnna formen fr 
denna konstruktion r:

		uttryck1 ? uttryck2 : uttryck3

Nr programkrningen kommer hit evalueras frst uttryck1. Om det r sant s
berknas uttryck2, och hela uttrycket fr detta vrde. Annars berknas i 
stllet uttryck3 och hela uttrycket fr dess vrde.

Men riktigt s begrnsad r inte villkorsoperatorn. Eftersom i C alla funk-
tioner har ett vrde, om de inte r deklarerade void frsts, gr det att som
uttryck stta in funktionsanrop. Vid krningen anropas d funktionen fr att
dess vrde ska kunna bestmmas. Exempel:

		x ? funk1(x) + funk2(y) : printf("Frsk igen");

Om x r skilt frn noll anropas funk1() och funk2() och deras vrden adderas,
om x r noll, skrivs upmaningen ut i stllet. Se hr upp med ordningen mellan
funktionerna vid utfrandet. C-kompilatorn r alltid fri att vlja i vilken
ordning den vill berkna ett uttryck.

Om man vill skriva effektiv kod s rekommenderas det att man anvnder vill-
korsoperatorn i stllet fr en if-else-konstruktion om det gr eftersom C kan
generera mycket kompakt och snabb kod i denna situation. 


				SWITCH


I stllet fr att skriva lnga listor med if-else-if osv kan man klara ett
flerval elegantare med switchsatsen. En variabel testas hr mot en lista med
int eller charkonstanter. Om likhet intrffar utfrs en tillhrande sats 
eller satsblock. Den allmnna formen r:

		switch (uttryck) {

		   case konstant1:
		      satsfljd
		      break;

		   case konstant2:
		      satsfljd
		      break;

		   case konstant3:
		      satsfljd
		      break;

			.
			.
			.

		   default:
		      satsfljd
		}

Satsfljden efter default utfrs om ingen likhet hittas. Ordet default r 
inte obligatoriskt, och om det saknas hnder inget alls utan krningen bara 
fortstter. Om en likhet konstateras utfrs den tillhrande satsfljden tills
break ptrffas. D hoppar exekveringen ut ur casesatsen och fortstter med 
nsta sats efter switchkonstruktionen.

Switchsatsen kan till skillnad frn ifsatsen bara testa fr likhet, och inte
berkna uttryck.

Tv case-konstanter i samma switchsats fr inte ha samma vrde.

Om man anvnder charkonstanter omvandlas de till motsvarande intvrden.

Ett vanligt anvndningsomrde fr switchsatsen r vid menyhantering frn tan-
gentbordet. Ett kort fragment som exempel:

	ch=getchar() /* ls in ett tecken frn tangentbordet. */

	switch (ch) {

	   case '1':
	      funk1();
	      break;

	   case '2':
	      funk2();
	      break;

	   case '3':
	      funk3();
	      break;

	   default:
	      printf("Vlj ett giltigt tal i stllet, pundhuvud!")
	}

Rent syntaktiskt r breaksatserna inuti switchsatsen inte obligatoriska. Om
de fattas fortstter exekveringen med den satsfljd som hr till nsta case
nda tills ett break ptrffas eller tills switchsatsen tar slut. Det hr kan
man utnyttja om till exempel flera olika cases ska medfra att samma sak ut-
frs. Ett case kan nmligen sakna satsfljd och break,s hr:

	case 1:
	case 2:
	case 3:
	   flagga=0;
	   break;

	case 4:
	   flagga=1;

	case 5:
	   error(flagga);
	   break;

	default:
	   printf("Frsk igen");    

Hr konstaterar man frst att de tre frsta valen alla utfr samma sats. Vid
case 4 stts flaggan till 1 och sedan kallas funktionen error, och om case 5
vljs anropas error utan att flaggan stts.

Observera noga att ett case nrmast motsvarar en label, dit exekveringen ska
hoppa. De satser som kommer efter ett case r inte ett block, utan en fljd 
av satser, vilket bland annat medfr att de flesta kompilatorer inte till-
ter deklaration av en autovariabel i en sdan satsfljd. 

Det r naturligtvis tilltet att anvnda switchsatser inuti andra switchsat-
ser i s mnga niver man vill och kan hlla reda p.  

 
			      SLINGOR


En bra egenskap hos datorn r att den utan att trttna kan hlla p med samma
fniga uppgift hur lnge som helst. D r det inte s dumt att p ett bekvmt
stt be den upprepa ngot tills den har lyckats uppfylla ett visst villkor. 
Fr det ndamlet finns det i C ett antal konstruktioner av slingor.



			   WHILE - SATSEN


Den enklaste slingkonstruktionen r den som kallas while-satsen. Den utfr
helt enkelt en sats, enkel eller sammansatt, s lnge ett givet villkor r
uppfyllt. Drefter utfrs nsta sats och programmet gr vidare:

 		while ( uttryck )

 		   sats

 		nsta sats

Det allra frsta som hnder i denna konstruktion r att "uttryck" berknas.
Om det r noll, allts falskt, s utfrs genast "nsta sats". Om dremot vr-
det av "uttryck" r skilt frn noll, allts sant, s utfrs "sats" och dr-
efter brjar slingan om med att "uttryck" berknas. Satsen i slingan utfrs
allts ingen gng, en gng eller flera gnger, beroende p nr "uttryck" fr
vrdet noll. Om man inte vill att satsen ska utfras nda tills ngon barm-
hrtig anvndare stnger av maskinen, s r det lmpligt att modifiera "ut-
tryck" under krningen, till exempel genom upprkningsoperatorn ++. Vi tar 
ett enkelt exempel som skriver upp alla heltal mindre n ett visst vrde n.
Programfragmentet frutstter att n r ett heltal strre n noll och att i r
satt till noll frn brjan:

 		while ( i++ < n )

 		   printf ( "\n%d", i-1 );

Det hr programmet brjar med att jmfra i med n och direkt drefter rknas
i upp med ett. Om operatorn ++ hade sttt fre i, s hade i rknats upp redan
fre jmfrelsen. Hrefter kommer funktionsanropet till printf() att medfra
att vrdet av i minskas med ett och skrivs ut. Styrstrngen "\n%d" betyder 
att frst skrivs ett nyradstecken, drefter skrivs talet ut som decimalt hel-
tal. Om vi inte hade tnkt p att dra bort ett frn i s hade vi ftt ut-
skrift av alla heltal frn 1 och till och med vrdet av n. Hnder det d inte
ngot konstigt med slingvillkoret? Vi hade ju just rknat upp i med ett, och
s drar vi genast bort ett igen, d borde vi aldrig komma lngre n till noll
och loopen skulle bli ondlig. D ska vi komma ihg en grundlggande egenskap
hos funktionsanrop i C. Nr ett funktionsargument verfrs, s r det aldrig
variabeln sjlv, utan bara dess vrde. Funktionen fr allts bara en egen ko-
pia att leka med. Originalet finns kvar ofrndrat hos den anropande funk-
tionen.

	

			   FOR - SATSEN


Nra beslktad med while-satsen och lika vanlig r for-satsen. Vi brjar med 
ett exempel som berknar summan av heltalen frn 1 till 10:

 		int i, summa;


 		summa = 0;

 		for ( i = 1; i <= 10; ++ i )

 			summa += i;

Den sista satsen skulle kunna skrivas som "summa = summa + i;" men eftersom 
det nu finns en kortare konstruktion fr det i C s lt oss anvnda den. 

Uppbyggnaden av for-satsen kan vi skriva mer generellt s hr:

 		for ( uttryck1; uttryck2; uttryck3 )

 			sats

 		nsta sats

Sjlva for-konstruktionen inleds med "uttryck1" som bestmmer startvrdet i
slingan, i exemplet stts i till ett. S berknas vrdet av "uttryck 2", och 
om det r sant s utfrs "sats", varefter "uttryck3" berknas och slingan 
gr om igen, dock utan att "uttryck1" berknas, det hade ju bara till upp-
gift att ge startvrdet. Detta fortstter tills vrdet av "uttryck2" blir 
falskt, d utfrs i stllet "nsta sats" och programmet gr vidare.
 
Det r inget som hindrar att ett eller flera av uttrycken i for-satsen saknas
men semikolonen mste finnas med som markering. Om "uttryck1" saknas sker 
ingen initiering, men den kan man gra sjlv i en tilldelningssats innan om
man vill. Saknas "uttryck2" s gller att det tomma uttrycket alltid r sant,
och slingan blir ondlig. Det som normalt grs i berkningen av "uttryck3" 
kan lika grna utfras i "sats".

Berkningen av vr summa skulle allts kunna gras s hr i stllet:

 		i = 1;

 		summa = 0;

 		for ( ; i <= 10; )

 			summa += i++;

For-satsen kan anvndas som "sats" i if-satser av olika slag eller i en for-
sats. Konstruktionen:

 		for (         )
 			for (         )
 				for (        )
 					sats

r slunda en enda for-sats.

Vilken av de bda konstruktionerna for eller while man vill anvnda r helt 
en frga om personlig smak. En frdel som for-satsen har r dock det faktum 
att styrning och upprkning sker redan i brjan av slingan, vilket gr pro-
grammen mer lttlsta. 



			       DO - SATSEN


Do-satsen r egentligen bara en variant av while-satsen, dr villkorstestet 
sker i slutet av slingan och inte i brjan och nyckelordet do markerar br-
jan av slingan:

 		do

 		   sats

 		while ( uttryck )

 		nsta sats

Nr programmet kommer till denna konstruktion, brjar det med att "sats" ut-
frs. S berknas vrdet av "uttryck", och om detta r sant brjar slingan 
om vid do igen. Om dremot vrdet av "uttryck" r noll, allts falskt, s 
fortstter programmet med "nsta sats". Det hr innebr att eftersom testet
sker eftert, s utfrs alltid "sats" minst en gng. I bde while-satsen och
for-satsen finns ju mjligheten att "sats" verhuvudtaget inte utfrs. Ett
lmpligt anvndningsomrde fr do-satsen kan vara att kontrollera en inmat-
ning. Antag att du vill mata in tal och att dessa mste vara positiva heltal:

 	do  {

 		printf("\n\nmata in ett positivt heltal, tack:   ");

 		scanf("%d", &n);

 	}   while (n <= 0);

S lnge det inmatade talet inte r ett positivt heltal s kommer maskinen 
att vnligt men bestmt att upprepa sin begran. Nr den till slut blivit 
uppfylld gr programmet vidare.

Do-satsen anvnds inte srskilt ofta i C, s drfr hr det till god ton att
anvnda klammer som i exemplet ovan ven om "sats" bara r en enkel sats, fr
att det omedelbart ska synas att "while" ingr i en do-sats och inte i en 
while-sats som fljs av en tom sats.



			TESTVILLKOR OCH NOGGRANNHET


Ett problem som r gemensamt fr alla de tre slingkonstruktionerna vi har
gtt igenom, r konsten att skapa villkor som verkligen fungerar i alla tnk-
bara situationer. Om de uttryck som ska testas r av ngon av heltalstyperna
blir det sllan problem, men med float eller double gller det att se upp. 
Det r mycket olmpligt att hr anvnda villkor med test fr likhet eller 
icke-likhet. Flyttal har ju som bekant egenheten att inte vara exaka i data-
vrlden, och det fr katastrofala fljder eftersom ett likhetstest verkligen
krver exakt likhet nda ner till sista decimalen. Fljande kodfragment ger
nstan alltid upphov till en ondlig loop:

 	for (x = 0.0; x != 9.9; x += 0.1)

Den hemska sanningen r att x efter 100 varv i slingan kommer att f ett vr-
de som ligger mycket nra 9.9, men exakt rtt blir det knappast. Ett betyd-
ligt skrare test vore att anvnda en relationsoperator istllet:

 	for (x = 0.0; x < 9.85; x += 0.1)
