Navigationskarta Insitutitionen för Datavetenskap Umeå Universitet

Grunderna i C

While och do...while

While-slingan är en av de enklaste slingkonstruktionerna. Först testas villkoret. Om villkoret är sant körs slingan, och sedan börjar det hela om från början.

i = 0;
while (i < 10) {
  printf("%d\n", i);
  i++;
}

Det är vanligt att man använder sig av tilldelningar i själva villkoret. Då måste man vara noga med att sätta parenteserna rätt, eftersom == och != har högre prioritet än =.

while ((ch = getchar()) != EOF) 
  putchar(ch);

Om villkoret är falskt från början kommer slingan aldrig att köras. Ibland vill man att slingan alltid ska köras minst en gång, och då kan man lägga villkoret i slutet av slingan. Följande slinga skriver ut de tecken användaren matar in ända tills användaren trycker på Q (tecknet Q skrivs också ut):

do {
  ch = getchar();
  putchar(ch);
} while (ch != 'Q');

For-slingan

For-slingan i C är mycket flexibel. Först anges en initiering, sedan ett stoppvillkor och slutligen en "uppräkningssats" som ska köras för varje genomlöpning av slingan:

for (i = 0; i < 10; i++)
  printf("%d\n", i);

Observera att uppräkningssatsen (i++) körs efter det att slingan körts första varvet, och att stoppvillkoret alltid testas innan slingan körs. Det är alltså fullt möjligt att slingan aldrig kommer att köras:

for (i = 1000; i < 10; i++)
  printf("%d\n", i);

Oftast används en heltalsvariabel för att styra slingan, men det går också att använda andra typer av satser, exempelvis funktionsanrop. Nedanstående slinga läser in tecken från tangentbordet och skriver ut dem på skärmen ända tills det kommer ett ogiltigt tecken. Funktionen IsValid() avgör vilka tecken som är giltiga.

for (ch = getchar(); IsValid(ch); ch = getchar())
  putchar(ch);

Man kan alltid skriva om en while-slinga som en for-slinga och vice versa. Vilken man väljer beror på vad som blir smidigast i den aktuella situationen. Just i detta fall hade det varit smidigare att använda en while-slinga:

while (IsValid(ch = getchar()))
  putchar(ch);  

If-satsen

If-satsen är i princip ganska enkel:

if (x >= 0.0)
  roten = sqrt(x);
else
  roten = sqrt(-x);

Alla värden som inte är 0 betraktas som sanna. Ett villkor behöver alltså inte innehålla en logisk operator (>=, == osv) utan kan bestå av ett numeriskt värde:

if (Tot)
  Procent = Andel / Tot;

Det går också att utnyttja att NULL == 0, även om det kan göra koden svårläst. Följande två if-satser gör precis samma sak:

if (gets(s) != NULL) ...
if (gets(s)) ...

{Måsvingar}

If, for och de andra konstruktionerna ovan styr bara en enda sats:

for (i = 0; i < 10; i++)
  ReadNew(x);           /* Körs tio gånger */
x = 0;                   /* Körs en gång */

if (x > 30)
  y = 0;                 /* Körs bara om x > 30 */
printf("%d\n", x);      /* Körs alltid */

Om man vill koppla flera satser till exempelvis en if-sats måste man skapa en sammansatt sats med hjälp av måsvingar. Följande kod kommer bara att skriva ut x om x är större än 30:

if (x > 30) {
  y = 0;                 /* Körs bara om x > 30 */
  printf("%d\n", x);    /* Dito */
}

Observera att indenteringen inte påverkar hur koden körs! Indenteringen är till för att programmet ska bli lätt att läsa för människor; kompilatorn ignorerar den fullständigt. Nedanstående indentering ger en felaktig bild av vad som händer:

if (x > 30)
  y = 0;                 /* Körs bara om x > 30 */
  printf("%d\n", x);    /* OBS! Körs alltid */

Funktionsprototyper

Alla funktioner har en returtyp (typen på det värde funktionen returnerar). Alla argument har också en typ. Dessa typer måste naturligtvis deklareras. Ibland räcker det att deklarera typerna samtidigt som man definierar funktionen, men om första anropet till funktionen kommer före funktionsdefinitionen måste typerna deklareras separat. Den extra deklarationen kallas en funktionsprototyp, och ser ut precis som funktionshuvudet bortsett från att den avslutas med ; istället för med {. I följande exempel behövs ingen prototyp:

float plus_tre(float x) {
 return(x + 3.0);
}

int main(int argc, char **argv) {
  ...
  z = plus_tre(z);
  ...
}

Som du ser definieras plus_tre() före första anropet. Om plus_tre() däremot hade legat efter main() hade det varit nödvändigt med en prototyp:

float plus_tre(float x);

int main(int argc, char **argv) {
  ...
  z = plus_tre(z);
  ...
}

float plus_tre(float x) {
  return(x + 3.0);
}

Om prototypen inte hade funnits hade kompilatorn inte känt till typen hos plus_tre() när det första anropet skedde.

Readdir, version 1

/* En enkel ls som visar innehållet i aktuell katalog. */
/* Version 1: Ingen felkontroll.  */

#include <dirent.h>
#include <stdio.h>

int main(void) {
  DIR *dp;
  struct dirent *dep;
  dp = opendir(".");
  while ((dep = readdir(dp)) != NULL) 
    printf("%s\n", dep->d_name);
closedir(dp);
return(0); }

Readdir, version 2

/* En enkel ls som visar innehållet i aktuell katalog. */
/* Version 2: Med felkontroll.  */

#include <dirent.h>
#include <stdio.h>

int main(void) {
  DIR *dp;
  struct dirent *dep;

if ((dp = opendir(".")) == NULL) {
    perror("opendir() failed");
    return(1);
  } else {
    while ((dep = readdir(dp)) != NULL)
      printf("%s\n", dep->d_name);
    closedir(dp);
  }
  return(0);
}

[an error occurred while processing this directive]