Sådan arbejder du med variabler, datatyper og aritmetiske udtryk i programmeringssproget C

C har et stort udvalg af matematiske operatorer, som du kan bruge til at manipulere dine data. I dette kapitel fra Programmering i C, 4. udgave, dækker Stephen G. Kochan datatyperne int, float, double, char og _Bool, ændring af datatyper med short, long og long long long, reglerne for navngivning af variabler, grundlæggende matematiske operatorer og aritmetiske udtryk samt typecasting.

Den sande styrke i de programmer, du opretter, er deres manipulation af data. For virkelig at kunne udnytte denne kraft er du nødt til bedre at forstå de forskellige datatyper, du kan bruge, samt hvordan du opretter og navngiver variabler. C har et rigt udvalg af matematiske operatorer, som du kan bruge til at manipulere dine data. I dette kapitel vil du dække:

  • Datatyperne int, float, double, char og _Bool
  • Modificering af datatyper med short, long, og long long
  • Reglerne for navngivning af variabler
  • Grundlæggende matematiske operatorer og aritmetiske udtryk
  • Type casting

Forståelse af datatyper og konstanter

Du er allerede blevet præsenteret for C’s grundlæggende datatype int. Som du husker, kan en variabel, der er deklareret til at være af typen int, kun bruges til at indeholde integralværdier – dvs. værdier, der ikke indeholder decimaler.

Programmeringssproget C indeholder fire andre grundlæggende datatyper: float, double, char og _Bool. En variabel, der er deklareret til at være af typen float, kan bruges til at lagre floating-point-tal (værdier, der indeholder decimaler). Typen double er den samme som typen float, blot med ca. dobbelt så stor præcision som typen float. Datatypen char kan bruges til at lagre et enkelt tegn, f.eks. bogstavet “a”, ciffertegnet “6” eller et semikolon (“;”) (mere om dette senere). Endelig kan datatypen _Bool bruges til at gemme værdierne 0 eller 1. Variabler af denne type bruges til at angive en on/off-, ja/nej- eller sand/falsk-situation. Disse et-eller-andet-valg er også kendt som binære valg.

I C er ethvert tal, enkelt tegn eller tegnstreng kendt som en konstant. For eksempel repræsenterer tallet 58 en konstant heltalsværdi. Karakterstrengen “Programmering i C er sjovt.\n” er et eksempel på en konstant karakterstreng. Udtryk, der udelukkende består af konstante værdier, kaldes konstante udtryk. Så udtrykket

128 + 7 - 17

er et konstant udtryk, fordi hver af udtrykkets termer er en konstant værdi. Men hvis i blev erklæret som en heltalsvariabel, ville udtrykket

128 + 7 – i

ikke udgøre et konstant udtryk, fordi dets værdi ville ændre sig afhængigt af værdien af i. Hvis i er 10, er udtrykket lig med 125, men hvis i er 200, er udtrykket lig med -65.

Den hele taltype int

I C består en hele talkonstant af en sekvens af et eller flere cifre. Et minustegn foran sekvensen angiver, at værdien er negativ. Værdierne 158, -10 og 0 er alle gyldige eksempler på hele talkonstanter. Der er ikke tilladt indlejrede mellemrum mellem cifrene, og værdier større end 999 kan ikke udtrykkes ved hjælp af kommaer. (Værdien 12.000 er således ikke en gyldig heltalskonstant og skal skrives som 12000.)

To særlige formater i C gør det muligt at udtrykke heltalskonstanter i en anden base end decimal (base 10). Hvis det første ciffer i den hele talværdi er et 0, anses det hele tal for at være udtrykt i oktal notation – dvs. i base 8. I så fald skal de resterende cifre i værdien være gyldige base 8-cifre og skal derfor være 0-7. Så for at udtrykke værdien 50 i base 8 i C, som svarer til værdien 40 i decimaltal, anvendes notationen 050. På samme måde repræsenterer oktalkonstanten 0177 den decimale værdi 127 (1 × 64 + 7 × 8 + 7). En heltalsværdi kan vises på terminalen i oktal notation ved at bruge formattegnene %o i formatstrengen i en printf()-anvisning. I så fald vises værdien i oktalform uden et foranstillet nul. Formattegnet %#o bevirker, at der vises et foranstillet nul foran en oktalværdi.

Hvis en heltals-konstant indledes med et nul og bogstavet x (enten med små eller store bogstaver), anses værdien for at være udtrykt i hexadecimal (base 16) notation. Umiddelbart efter bogstavet x er cifrene i den hexadecimale værdi, som kan være sammensat af cifrene 0-9 og bogstaverne a-f (eller A-F). Bogstaverne repræsenterer henholdsvis værdierne 10-15. Så for at tildele den hexadecimale værdi FFEF0D til en heltalsvariabel kaldet rgbColor, kan man bruge udsagnet

rgbColor = 0xFFEF0D;

. Formattegnene %x viser en værdi i hexadecimalt format uden det forreste 0x, og ved at bruge små bogstaver a-f for hexadecimale cifre. Hvis du vil vise værdien med det foranstillede 0x, bruger du formattegnene %#x, som i følgende:

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

Et stort x, som i %X eller %#X, kan bruges til at vise det foranstillede x og de efterfølgende hexadecimale cifre ved hjælp af store bogstaver.

Lagringsstørrelser og -områder

Alle værdier, uanset om det er tegn, heltal eller flydende tal, har et værdiområde, der er knyttet til dem. Dette interval har at gøre med den mængde lagerplads, der er tildelt til at lagre en bestemt type data. Generelt er denne mængde ikke defineret i sproget. Det afhænger typisk af den computer, du anvender, og kaldes derfor implementerings- eller maskinafhængigt. Et heltal kan f.eks. fylde 32 bit på din computer, eller måske kan det gemmes i 64 bit. Du bør aldrig skrive programmer, der gør nogen formodninger om størrelsen af dine datatyper. Du er dog garanteret, at der vil blive afsat et minimum af lagerplads til hver grundlæggende datatype. F.eks. er det garanteret, at en heltalsværdi vil blive lagret på mindst 32 bit lagerplads, hvilket er størrelsen af et “ord” på mange computere.

Den flydende taltype float

En variabel, der er erklæret af typen float, kan bruges til lagring af værdier, der indeholder decimaler. En konstant med flydende tal er kendetegnet ved tilstedeværelsen af et decimalkomma. Du kan udelade cifre før decimalkommaet eller cifre efter decimalkommaet, men du kan naturligvis ikke udelade begge dele. Værdierne 3., 125,8 og -.0001 er alle gyldige eksempler på floating-point-konstanter. For at vise en floating-point-værdi på terminalen bruges printf-konverteringstegnene %f.

Floating-point-konstanter kan også udtrykkes i videnskabelig notation. Værdien 1.7e4 er en floatingpoint-værdi udtrykt i denne notation og repræsenterer værdien 1.7 × 104. Værdien før bogstavet e er kendt som mantisen, mens den værdi, der følger efter, kaldes eksponenten. Denne eksponent, som kan indledes med et valgfrit plus- eller minustegn, repræsenterer den potens af 10, som mantisen skal multipliceres med. I konstanten 2,25e-3 er 2,25 altså værdien af mantisen, og -3 er værdien af eksponenten. Denne konstant repræsenterer værdien 2,25 × 10-3, dvs. 0,00225. I øvrigt kan bogstavet e, som adskiller mantisse fra eksponent, skrives med enten små eller store bogstaver.

For at vise en værdi i videnskabelig notation skal formattegnene %e angives i printf()-formatstrengen. Printf()-formattegnene %g kan bruges til at lade printf() afgøre, om værdien med flydende komma skal vises i normal flydende komma-notation eller i videnskabelig notation. Denne beslutning er baseret på værdien af eksponenten: Hvis den er mindre end -4 eller større end 5, anvendes %e-formatet (videnskabelig notation); ellers anvendes %f-formatet.

Brug %g-formattegnene til visning af flydende punkttal – det giver det mest æstetisk tiltalende output.

En hexadecimal flydende konstant består af en foranstillet 0x eller 0X, efterfulgt af et eller flere decimale eller hexadecimale cifre, efterfulgt af et p eller P, efterfulgt af en valgfrit signeret binær eksponent. F.eks. repræsenterer 0x0.3p10 værdien 3/16 × 210 = 0,5.

Den udvidede præcisionstype double

Double-typen ligner meget float-typen, men den anvendes, når det område, som en float-variabel giver, ikke er tilstrækkeligt. Variabler, der er deklareret til at være af typen double, kan lagre ca. dobbelt så mange signifikante cifre som en variabel af typen float. De fleste computere repræsenterer dobbeltværdier ved hjælp af 64 bit.

Medmindre andet er oplyst, betragtes alle floating-point-konstanter som dobbeltværdier af C-compileren. For at udtrykke en float-konstant eksplicit skal du tilføje enten et f eller F til slutningen af tallet som følger:

12.5f

For at vise en dobbeltværdi kan formattegnene %f, %e eller %g, som er de samme formattegn, der bruges til at vise en float-værdi, bruges.

Den enkelte tegntype char

En char-variabel kan bruges til at gemme et enkelt tegn. 1 En tegnkonstant dannes ved at omslutte tegnet inden for et par enkelte anførselstegn. Så ‘a’, ‘;’ og ‘0’ er alle gyldige eksempler på tegnkonstanter. Den første konstant repræsenterer bogstavet a, den anden er et semikolon, og den tredje er tegnet nul – som ikke er det samme som tallet nul. Du må ikke forveksle en tegnkonstant, som er et enkelt tegn omsluttet af enkelte anførselstegn, med en tegnstreng, som er et vilkårligt antal tegn omsluttet af dobbelte anførselstegn.

Tegnkonstanten ‘\n’-tegnet ‘newline’ – er en gyldig tegnkonstant, selv om den synes at være i modstrid med den tidligere citerede regel. Det skyldes, at backslash-tegnet er et specialtegn i C-systemet og faktisk ikke tæller som et tegn. Med andre ord behandler C-compileren tegnet “\n” som et enkelt tegn, selv om det faktisk er dannet af to tegn. Der er andre specialtegn, der indledes med backslash-tegnet. Se bilag A, “Oversigt over C-sproget”, for at få en komplet liste.

Formattegnene %c kan bruges i et printf()-kald for at vise værdien af en char-variabel på terminalen.

Den boolske datatype _Bool

En _Bool-variabel er i sproget defineret til at være stor nok til kun at lagre værdierne 0 og 1. Den præcise mængde hukommelse, der bruges, er ikke specificeret. _Bool-variabler anvendes i programmer, der skal angive en boolsk tilstand. En variabel af denne type kan f.eks. bruges til at angive, om alle data er blevet læst fra en fil.

Som konvention bruges 0 til at angive en falsk værdi, og 1 angiver en sand værdi. Når du tildeler en værdi til en _Bool-variabel, gemmes en værdi på 0 som 0 inde i variablen, mens enhver værdi, der ikke er nul, gemmes som 1.

For at gøre det lettere at arbejde med _Bool-variabler i dit program, definerer standardheaderfilen <stdbool.h> værdierne bool, true og false. Et eksempel på dette er vist i program 5.10A i kapitel 5, “At træffe beslutninger”.”

I program 3.1 anvendes de grundlæggende datatyper i C.

Program 3.1 Brug af de grundlæggende datatyper

Program 3.1 Output

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

Den første anvisning i program 3.1 erklærer variablen integerVar for at være en heltalsvariabel og tildeler den også en begyndelsesværdi på 100, som om de følgende to udsagn var blevet brugt i stedet:

int integerVar;integerVar = 100;

I den anden linje af programmets output bemærker du, at værdien 331,79, som er tildelt floatingVar, faktisk vises som 331,790009. Faktisk afhænger den faktiske værdi, der vises, af det pågældende computersystem, som du bruger. Årsagen til denne unøjagtighed er den særlige måde, hvorpå tal repræsenteres internt i computeren. Du er sikkert stødt på den samme type unøjagtighed, når du arbejder med tal på din lommeregner. Hvis du dividerer 1 med 3 på din lommeregner, får du resultatet .333333333333, med måske nogle ekstra 3’ere påklistret til sidst. Rækken af 3’er er lommeregnerens tilnærmelse til en tredjedel. Teoretisk set skulle der være et uendeligt antal 3’ere. Men lommeregneren kan kun rumme så mange cifre, og derfor er maskinen iboende unøjagtig. Den samme type unøjagtighed gælder her: Visse floatingpoint-værdier kan ikke repræsenteres nøjagtigt inde i computerens hukommelse.

Når du viser værdierne for float- eller double-variabler, har du valget mellem tre forskellige formater. Tegnene %f bruges til at vise værdierne på en standardmåde. Medmindre andet er angivet, viser printf() altid en float- eller double-værdi med seks decimaler afrundet. Du ser senere i dette kapitel, hvordan du vælger det antal decimaler, der skal vises.

Tegnene %e bruges til at vise værdien af en float- eller doublevariabel i videnskabelig notation. Igen vises seks decimaler automatisk af systemet.

Med %g-tegnene vælger printf() mellem %f og %e og fjerner også automatisk eventuelle efterliggende nuller fra visningen. Hvis der ikke følger nogen cifre efter decimalkommaet, vises det heller ikke.

I den næstsidste printf()-anvisning bruges %c-tegnene til at vise det enkelte tegn “W”, som du tildelte charVar, da variablen blev erklæret. Husk, at mens en tegnstreng (som f.eks. det første argument til printf()) er omsluttet af et par dobbelte anførselstegn, skal en tegnkonstant altid være omsluttet af et par enkelte anførselstegn.

Den sidste printf() viser, at en _Bool-variabel kan få sin værdi vist ved hjælp af de hele talformattegn %i.

Typespecifikatorer: long, long long long, short, unsigned og signed

Hvis specifikationsspecifikatoren long er placeret direkte før int-deklarationen, har den deklarerede integer-variabel et udvidet interval på nogle computersystemer. Et eksempel på en long int-deklaration kan være

long int factorial;

Dette erklærer variablen faktorial for at være en long integer-variabel. Som det er tilfældet med floats og doubles, afhænger den særlige nøjagtighed af en lang variabel af dit særlige computersystem. På mange systemer har en int og en long int samme rækkevidde, og begge kan bruges til at lagre heltalsværdier med en bredde på op til 32 bit (231 – 1, eller 2.147.483.647).

En konstantværdi af typen long int dannes ved eventuelt at tilføje bogstavet L (store eller små bogstaver) i slutningen af en heltalskonstant. Der må ikke være mellemrum mellem tallet og L’et. Deklarationen

long int numberOfPoints = 131071100L;

deklarerer altså variablen numberOfPoints til at være af typen long int med en begyndelsesværdi på 131.071.100.

For at vise værdien af en long int ved hjælp af printf() anvendes bogstavet l som en modificator før de hele talformattegn i, o og x. Det betyder, at formattegnene %li kan bruges til at vise værdien af et long int i decimalformat, tegnene %lo kan vise værdien i oktalformat, og tegnene %lx kan vise værdien i hexadecimalformat.

Der findes også en datatype for long long integer, så

long long int maxAllowedStorage;

deklarerer den angivne variabel som værende af den angivne udvidede nøjagtighed, som garanteret er mindst 64 bit bred. I stedet for et enkelt bogstav l bruges to l’er i printf-strengen for at vise lange lange lange hele tal, som i “%lli”.

Den lange specificator er også tilladt foran en dobbeltdeklaration, som følger:

long double US_deficit_2004;

En lang dobbeltkonstant skrives som en flydende konstant med bogstavet l eller L umiddelbart efter, som

1.234e+7L

For at vise en lang dobbeltkonstant bruges L-modifikatoren. Så %Lf viser en lang dobbeltværdi i flydende notation, %Le viser den samme værdi i videnskabelig notation, og %Lg fortæller printf(), at den skal vælge mellem %Lf og %Le.

Specifikatoren short, når den placeres foran int-deklarationen, fortæller C-compileren, at den pågældende variabel, der deklareres, bruges til at lagre ret små heltalsværdier. Motivationen for at bruge korte variabler er primært at spare hukommelsesplads, hvilket kan være et problem i situationer, hvor programmet har brug for meget hukommelse, og hvor mængden af tilgængelig hukommelse er begrænset.

På nogle maskiner fylder en kort int kun halvt så meget som en almindelig int-variabel. Under alle omstændigheder er du garanteret, at den plads, der er allokeret til en short int, ikke vil være mindre end 16 bit.

Der er ingen måde at skrive en konstant af typen short int eksplicit i C. For at vise en short int-variabel skal du sætte bogstavet h foran et af de normale tegn til konvertering af hele tal: %hi, %ho eller %hx. Alternativt kan du også bruge et af integerkonverteringstegnene til at vise korte ints, på grund af den måde, hvorpå de kan konverteres til hele tal, når de overføres som argumenter til rutinen printf().

Den sidste specificator, der kan placeres foran en int-variabel, bruges, når en integer-variabel kun skal bruges til at lagre positive tal. Deklarationen

unsigned int counter;

deklarerer over for compileren, at variabeltælleren kun bruges til at indeholde positive værdier. Ved at begrænse brugen af en integervariabel til udelukkende at lagre positive hele tal udvides nøjagtigheden af integervariablen.

En int-konstant uden fortegn dannes ved at placere bogstavet u (eller U) efter konstanten på følgende måde:

0x00ffU

Du kan kombinere bogstaverne u (eller U) og l (eller L), når du skriver en integerkonstant, så

20000UL

anviser compileren, at den skal behandle konstanten 20000 som en long uden fortegn.

En heltalskonstant, der ikke efterfølges af et af bogstaverne u, U, l eller L, og som er for stor til at passe ind i en int af normal størrelse, behandles af compileren som en int uden fortegn. Hvis den er for lille til at passe ind i et unsigned int, behandler compileren den som et long int. Hvis den stadig ikke kan passe ind i en long int, gør compileren den til en unsigned long int. Hvis den ikke kan være der, behandler compileren den som en long long int, hvis den kan være der, og ellers som en unsigned long long int.

Når du deklarerer variabler til at være af typen long long long int, long int, short int eller unsigned int, kan du udelade nøgleordet int. Derfor kunne den usignerede variabel tæller tilsvarende have været deklareret på følgende måde:

unsigned counter;

Du kan også deklarere char-variabler til at være usignerede.

Den signerede kvalifikator kan bruges til udtrykkeligt at fortælle compileren, at en bestemt variabel er en signeret størrelse. Dens anvendelse sker primært foran char-deklarationen, og yderligere drøftelser udskydes til kapitel 13, “Mere om datatyper.”

Du skal ikke bekymre dig, hvis drøftelserne af disse specifiers virker lidt esoteriske for dig på dette tidspunkt. I senere afsnit i denne bog bliver mange af disse forskellige typer illustreret med konkrete programeksempler. Kapitel 13 går mere i detaljer om datatyper og konverteringer.

Tabel 3.1 opsummerer de grundlæggende datatyper og kvalifikatorer.

Tabel 3.1 Grundlæggende datatyper