Hur man arbetar med variabler, datatyper och aritmetiska uttryck i programmeringsspråket C

C har ett stort antal olika matematiska operatorer som du kan använda för att manipulera dina data. I det här kapitlet från Programming in C, 4th Edition tar Stephen G. Kochan upp datatyperna int, float, double, char och _Bool, modifiering av datatyper med short, long och long long, reglerna för att namnge variabler, grundläggande matematiska operatorer och aritmetiska uttryck samt typcasting.

Den verkliga kraften i de program du skapar är deras hantering av data. För att verkligen kunna dra nytta av den här kraften måste du bättre förstå de olika datatyper som du kan använda, samt hur du skapar och namnger variabler. C har ett rikt utbud av matematiska operatörer som du kan använda för att manipulera dina data. I det här kapitlet kommer du att behandla följande:

  • Datatyperna int, float, double, char och _Bool
  • Modifiera datatyper med short, long, och long long
  • Reglerna för namngivning av variabler
  • Grundläggande matematiska operatorer och aritmetiska uttryck
  • Typskapning

Förstå datatyper och konstanter

Du har redan bekantat dig med C:s grundläggande datatyp int. Som du minns kan en variabel som deklarerats vara av typen int endast användas för att innehålla helhetsvärden – det vill säga värden som inte innehåller decimaler.

Programmeringsspråket C tillhandahåller fyra andra grundläggande datatyper: float, double, char och _Bool. En variabel som deklarerats vara av typen float kan användas för att lagra flyttalstal (värden som innehåller decimaler). Typ double är samma som typ float, men med ungefär dubbelt så hög precision. Datatypen char kan användas för att lagra ett enskilt tecken, t.ex. bokstaven ”a”, siffertecknet ”6” eller ett semikolon (”;”) (mer om detta senare). Slutligen kan datatypen _Bool användas för att lagra endast värdena 0 eller 1. Variabler av den här typen används för att ange en on/off-, ja/nej- eller true/false-situation. Dessa ett-eller-annat-val kallas också binära val.

I C kallas varje tal, enskilt tecken eller teckensträng för en konstant. T.ex. representerar talet 58 ett konstant heltalsvärde. Teckensträngen ”Programming in C is fun.\n” är ett exempel på en konstant teckensträng. Uttryck som helt och hållet består av konstanta värden kallas konstanta uttryck. Så uttrycket

128 + 7 - 17

är ett konstant uttryck eftersom varje term i uttrycket är ett konstant värde. Men om i deklarerades som en heltalsvariabel skulle uttrycket

128 + 7 – i

inte representera ett konstant uttryck eftersom dess värde skulle ändras baserat på värdet på i. Om i är 10 är uttrycket lika med 125, men om i är 200 är uttrycket lika med -65.

Den heltaliga typen int

I C består en heltalskonstant av en sekvens av en eller flera siffror. Ett minustecken som föregår sekvensen anger att värdet är negativt. Värdena 158, -10 och 0 är alla giltiga exempel på heltalskonstanter. Inga inbäddade mellanslag är tillåtna mellan siffrorna, och värden större än 999 kan inte uttryckas med kommatecken. (Värdet 12 000 är alltså inte en giltig heltalskonstant och måste skrivas som 12 000.)

Två speciella format i C gör det möjligt att uttrycka heltalskonstanter i en annan bas än decimal (bas 10). Om den första siffran i helhetsvärdet är en 0, anses helheten vara uttryckt i oktal-notation – det vill säga i bas 8. I det fallet måste de återstående siffrorna i värdet vara giltiga siffror i bas 8 och måste därför vara 0-7. För att uttrycka värdet 50 i bas 8 i C, som motsvarar värdet 40 i decimal, används alltså notationen 050. På samma sätt representerar oktalkonstanten 0177 decimalvärdet 127 (1 × 64 + 7 × 8 + 7). Ett heltalsvärde kan visas på terminalen i oktalnotering genom att använda formattecknen %o i formatsträngen i ett printf()-kommando. I ett sådant fall visas värdet i oktalform utan inledande nolla. Formattecknet %#o gör att en inledande nolla visas före ett oktalvärde.

Om en heltalskonstant föregås av en nolla och bokstaven x (antingen liten eller stor bokstav) anses värdet vara uttryckt i hexadecimal (bas 16) notation. Omedelbart efter bokstaven x finns siffrorna i det hexadecimala värdet, som kan bestå av siffrorna 0-9 och bokstäverna a-f (eller A-F). Bokstäverna representerar värdena 10-15 respektive. För att tilldela det hexadecimala värdet FFEF0D till en heltalsvariabel som heter rgbColor, kan man alltså använda följande instruktion

rgbColor = 0xFFEF0D;

. Formattecknen %x visar ett värde i hexadecimalt format utan det inledande 0x och med små bokstäver a-f för hexadecimala siffror. Om du vill visa värdet med det inledande 0x använder du formattecknen %#x, som i följande:

printf ("Color is %#x\n", rgbColor);

Ett stort x, som i %X eller %#X, kan användas för att visa det inledande x och de hexadecimala siffrorna som följer med hjälp av stora bokstäver.

Lagringsstorlekar och -intervall

Varje värde, oavsett om det är ett tecken, ett heltal eller ett flyttal, har ett värdeintervall associerat med det. Detta intervall har att göra med hur mycket lagringsutrymme som tilldelas för att lagra en viss typ av data. I allmänhet är denna mängd inte definierad i språket. Det beror vanligtvis på vilken dator du använder och kallas därför implementations- eller maskinberoende. Ett heltal kan till exempel ta upp 32 bitar på din dator, eller så kanske det lagras på 64 bitar. Du bör aldrig skriva program som gör några antaganden om storleken på dina datatyper. Du är dock garanterad att en minsta mängd lagringsutrymme kommer att avsättas för varje grundläggande datatyp. Till exempel är det garanterat att ett heltalsvärde kommer att lagras på minst 32 bitar lagringsutrymme, vilket är storleken på ett ”ord” på många datorer.

Den flytande taltypen float

En variabel som deklarerats vara av typen float kan användas för att lagra värden som innehåller decimaler. En konstant med flytande tal kännetecknas av att det finns en decimalpunkt. Du kan utelämna siffror före decimalpunkten eller siffror efter decimalpunkten, men du kan naturligtvis inte utelämna båda. Värdena 3., 125,8 och -.0001 är alla giltiga exempel på flyttalskonstanter. För att visa ett flyttalvärde på terminalen används printf-omvandlingstecknen %f.

Flytalkonstanter kan också uttryckas i vetenskaplig notation. Värdet 1.7e4 är ett flyttalvärde uttryckt i denna notation och representerar värdet 1,7 × 104. Värdet före bokstaven e kallas mantissa, medan värdet som följer efter kallas exponent. Exponenten, som kan föregås av ett valfritt plus- eller minustecken, representerar den tiopotens som mantissan ska multipliceras med. I konstanten 2,25e-3 är alltså 2,25 värdet på mantissan och -3 värdet på exponenten. Denna konstant representerar värdet 2,25 × 10-3, eller 0,00225. För övrigt kan bokstaven e, som skiljer mantisan från exponenten, skrivas med både små och stora bokstäver.

För att visa ett värde i vetenskaplig notation ska formattecknen %e anges i formatsträngen printf(). Formattecknen %g för printf() kan användas för att låta printf() avgöra om värdet för flyttal ska visas i normal flyttalsnotering eller i vetenskaplig notation. Detta beslut baseras på exponentens värde: Om det är mindre än -4 eller större än 5 används formatet %e (vetenskaplig notation), annars används formatet %f.

Använd formatkaraktärerna %g för visning av flyttalstal – det ger det mest estetiskt tilltalande resultatet.

En hexadecimal flyttalskonstant består av en inledande 0x eller 0X, följt av en eller flera decimal- eller hexadecimalsiffror, följt av ett p eller P, följt av en valfri signerad binär exponent. Till exempel representerar 0x0.3p10 värdet 3/16 × 210 = 0,5.

Den utökade precisionstypen double

Typen double liknar i hög grad typen float, men den används när räckvidden som tillhandahålls av en floatvariabel inte är tillräcklig. Variabler som deklarerats vara av typen double kan lagra ungefär dubbelt så många signifikanta siffror som en variabel av typen float. De flesta datorer representerar dubbelvärden med 64 bitar.

Om inte annat sägs, tas alla konstanter med flyttal som dubbelvärden av C-kompilatorn. För att uttryckligen uttrycka en floatkonstant lägger du till antingen ett f eller F i slutet av talet, enligt följande:

12.5f

För att visa ett dubbelvärde kan formatkaraktärerna %f, %e eller %g, som är samma formatkaraktärer som används för att visa ett floatvärde, användas.

Den enskilda teckentypen char

En char-variabel kan användas för att lagra ett enskilt tecken.1 En teckenkonstant bildas genom att tecknet innesluts i ett par enkla citationstecken. Så ”a”, ”;” och ”0” är alla giltiga exempel på teckenkonstanter. Den första konstanten representerar bokstaven a, den andra är ett semikolon och den tredje är tecknet noll – vilket inte är samma sak som siffran noll. Förväxla inte en teckenkonstant, som är ett enskilt tecken inom enkla citattecken, med en teckensträng, som är ett valfritt antal tecken inom dubbla citattecken.

Teckenkonstanten ”\n”-tecknet för nya rader – är en giltig teckenkonstant, även om den tycks strida mot den tidigare citerade regeln. Detta beror på att backslash-tecknet är ett specialtecken i C-systemet och faktiskt inte räknas som ett tecken. Med andra ord behandlar C-kompilatorn tecknet ”\n” som ett enda tecken, trots att det egentligen består av två tecken. Det finns andra specialtecken som inleds med backslash-tecknet. Se bilaga A, ”C Language Summary”, för en fullständig lista.

Formattecknen %c kan användas i ett printf()-anrop för att visa värdet av en char-variabel på terminalen.

Den booleska datatypen _Bool

En _Bool-variabel definieras i språket så att den är tillräckligt stor för att lagra endast värdena 0 och 1. Den exakta mängden minne som används är ospecificerad. _Bool-variabler används i program som behöver ange ett boolskt tillstånd. En variabel av den här typen kan till exempel användas för att ange om alla data har lästs från en fil.

Enligt konvention används 0 för att ange ett falskt värde och 1 för att ange ett sant värde. När du tilldelar ett värde till en _Bool-variabel lagras värdet 0 som 0 i variabeln, medan alla värden som inte är noll lagras som 1.

För att göra det lättare att arbeta med _Bool-variabler i ditt program definieras värdena bool, true och false i standardheaderfilen <stdbool.h>. Ett exempel på detta visas i program 5.10A i kapitel 5, ”Att fatta beslut”.”

I program 3.1 används de grundläggande datatyperna i C.

Program 3.1 Användning av de grundläggande datatyperna

Program 3.1 Utmatning

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

Det första påståendet i program 3.1 deklarerar variabeln integerVar som en heltalsvariabel och tilldelar den också ett initialt värde på 100, som om följande två påståenden hade använts i stället:

int integerVar;integerVar = 100;

I den andra raden av programmets utdata, lägg märke till att värdet 331,79, som tilldelas floatingVar, faktiskt visas som 331,790009. Faktum är att det faktiska värdet som visas beror på vilket datorsystem du använder. Orsaken till denna felaktighet är det särskilda sätt på vilket siffror representeras internt i datorn. Du har förmodligen stött på samma typ av felaktighet när du hanterar siffror på din fickräknare. Om du dividerar 1 med 3 på din miniräknare får du resultatet .3333333333, med kanske några extra 3:or på slutet. Raden av 3:or är miniräknarens approximation av en tredjedel. Teoretiskt sett borde det finnas ett oändligt antal treor. Men miniräknaren kan bara rymma så många siffror, därav maskinens inneboende felaktighet. Samma typ av felaktighet gäller här: Vissa värden med flytande punkter kan inte representeras exakt i datorns minne.

När du visar värdena för float- eller dubbelvariabler kan du välja mellan tre olika format. Tecknen %f används för att visa värden på ett standardiserat sätt. Om inget annat anges visar printf() alltid ett float- eller dubbelvärde med sex avrundade decimaler. Du ser senare i det här kapitlet hur du väljer hur många decimaler som ska visas.

Tecknen %e används för att visa värdet av en float- eller dubbelvariabel i vetenskaplig notation. Återigen visas sex decimaler automatiskt av systemet.

Med tecknen %g väljer printf() mellan %f och %e och tar också automatiskt bort eventuella efterföljande nollor från visningen. Om inga siffror följer efter decimaltecknet visas inte heller det.

I det näst sista printf()-instruktionen används tecknen %c för att visa det enskilda tecknet ”W” som du tilldelade charVar när variabeln deklarerades. Kom ihåg att medan en teckensträng (t.ex. det första argumentet till printf()) omsluts av ett par dubbla citattecken, måste en teckenkonstant alltid omslutas av ett par enkla citattecken.

Det sista printf() visar att en _Bool-variabel kan få sitt värde visat med hjälp av heltalsformattecknen %i.

Typspecifikationer: long, long long long, short, unsigned och signed

Om specifikationen long placeras direkt före int-deklarationen har den deklarerade heltalsvariabeln ett utökat intervall på vissa datorsystem. Ett exempel på en lång int-deklaration kan vara

long int factorial;

Detta deklarerar variabeln factorial som en lång heltalsvariabel. Liksom för floats och doubles beror den särskilda noggrannheten hos en lång helhetsvariabel på just ditt datorsystem. På många system har en int och en long int samma räckvidd och båda kan användas för att lagra heltalsvärden som är upp till 32 bitar breda (231 – 1, eller 2 147 483 647).

Ett konstantvärde av typen long int bildas genom att man valfritt lägger till bokstaven L (stor eller liten bokstav) i slutet av en heltalskonstant. Inga mellanslag är tillåtna mellan talet och L. I deklarationen

long int numberOfPoints = 131071100L;

deklareras variabeln numberOfPoints till att vara av typen long int med ett initialt värde på 131 071 100.

För att visa värdet av ett long int med hjälp av printf() används bokstaven l som en modifierare före heltalsformattecknen i, o och x. Detta innebär att formattecknen %li kan användas för att visa värdet av ett long int i decimalformat, tecknen %lo kan visa värdet i oktalformat och tecknen %lx kan visa värdet i hexadecimalformat.

Det finns också en datatyp för långa, långa heltal, så

long long int maxAllowedStorage;

deklarerar att den angivna variabeln ska ha den angivna utökade noggrannheten, som garanterat är minst 64 bits bred. I stället för en enda bokstav l används två ls i printf-strängen för att visa långa långa långa heltal, som i ”%lli”.

Den långa specifikationen är också tillåten framför en dubbeldeklaration, enligt följande:

long double US_deficit_2004;

En lång dubbelkonstant skrivs som en flytande konstant med bokstaven l eller L omedelbart efter, till exempel

1.234e+7L

För att visa en lång dubbel används L-modifiern. Så %Lf visar ett långt dubbelvärde i flyttalsnotering, %Le visar samma värde i vetenskaplig notation och %Lg talar om för printf() att välja mellan %Lf och %Le.

Specifikatorn short, när den placeras framför int-deklarationen, talar om för C-kompilatorn att den särskilda variabeln som deklareras används för att lagra ganska små heltalsvärden. Motivet för att använda korta variabler är främst att spara minnesutrymme, vilket kan vara ett problem i situationer där programmet behöver mycket minne och det tillgängliga minnet är begränsat.

På vissa maskiner tar ett kort int upp hälften så mycket lagringsutrymme som en vanlig int-variabel gör. I vilket fall som helst är du garanterad att det utrymme som tilldelas en short int inte kommer att vara mindre än 16 bitar.

Det finns inget sätt att explicit skriva en konstant av typen short int i C. För att visa en short int-variabel placerar du bokstaven h framför något av de normala tecknen för omvandling av heltal: %hi, %ho eller %hx. Alternativt kan du också använda något av tecknen för heltalsomvandling för att visa korta int-variabler, på grund av det sätt på vilket de kan omvandlas till heltal när de skickas som argument till rutinen printf().

Den sista specificeringen som kan placeras framför en int-variabel används när en heltalsvariabel kommer att användas för att lagra endast positiva tal. Deklarationen

unsigned int counter;

deklarerar för kompilatorn att variabeln räknare används för att endast innehålla positiva värden. Genom att begränsa användningen av en heltalsvariabel till uteslutande lagring av positiva heltal utökas noggrannheten hos heltalsvariabeln.

En int-konstant utan förtecken bildas genom att placera bokstaven u (eller U) efter konstanten, enligt följande:

0x00ffU

Du kan kombinera bokstäverna u (eller U) och l (eller L) när du skriver en heltalskonstant, så

20000UL

det säger till kompilatorn att behandla konstanten 20000 som en unsigned long.

En heltalskonstant som inte följs av någon av bokstäverna u, U, l eller L och som är för stor för att rymmas i ett int av normal storlek behandlas av kompilatorn som ett unsigned int. Om den är för liten för att rymmas i ett unsigned int behandlar kompilatorn den som ett long int. Om det fortfarande inte får plats i ett long int gör kompilatorn det till ett unsigned long int. Om den inte får plats där behandlar kompilatorn den som en long long int om den får plats och som en unsigned long long int i annat fall.

När du deklarerar variabler av typen long long long int, long int, short int eller unsigned int kan du utelämna nyckelordet int. Därför kunde den osignerade variabeln counter ha deklarerats på motsvarande sätt på följande sätt:

unsigned counter;

Du kan också deklarera char-variabler som osignerade.

Den signerade kvalifikationen kan användas för att uttryckligen tala om för kompilatorn att en viss variabel är en signerad kvantitet. Den används främst framför char-deklarationen, och ytterligare diskussioner skjuts upp till kapitel 13, ”Mer om datatyper.”

Oroa dig inte om diskussionerna om dessa specificerare verkar lite esoteriska för dig vid det här laget. I senare avsnitt i den här boken illustreras många av dessa olika typer med verkliga programexempel. Kapitel 13 går mer i detalj in på datatyper och konverteringar.

Tabell 3.1 sammanfattar de grundläggande datatyperna och kvalificeringarna.

Tabell 3.1 Grundläggande datatyper