FAQ C-programmering

Fra mn/ifi/INF1060
Revisjon per 11. okt. 2010 kl. 11:25 av Bendiko@uio.no (diskusjon | bidrag)

(diff) ← Eldre revisjon | Nåværende revisjon (diff) | Nyere revisjon → (diff)
Hopp til: navigasjon, søk

Hvor finner jeg et API for C slik Java har?

Du finner ikke helt det samme for C. Under dokumentasjon på orakelsiden er det en link til en side som lister opp mye nyttig info om C. Ellers er det beste tipset å søke på nettet, bruke man-sidene eller slå opp i en bok om C. Gode sider på nettet er wikipedia og linuxmanpages.com. Det går fint å søke på wikipedia, men det kan være greit å starte med artikkelen C_standard_library.

man-sider

For å finne man-siden til funksjonen fopen som åpner en fil for lesing eller skriving, kjør følgende kommando i et unix-shell: man fopen

Hvis det finnes flere funksjoner med samme navn vil det også finnes flere ulike man-side. Dette gjelder f.eks. for funksjonene printf, write og exit. Alle disse er både C-funksjoner og programmer som kan kjøres i shellet.

'man printf', 'man write' og 'man exit' gir deg altså ikke informasjon om C-funksjonene du er ute etter, du må manuelt velge en annet man-side slik: 'man 3 printf', 'man 3 write' og 'man 3 exit'.


C Library

Hvis du vil ha en side med god oversikt over standardbibliotekene i C så kan vi anbefale denne siden: http://www.cplusplus.com/reference/clibrary/ Merk at dette er en side for C++ men det inneholder også en god oversikt over standardbibliotekene som er i C.

I menyen på venstre side så finner du de viktigste bibliotekene i C. F.eks så kan vi se at det er et bibliotek som heter stdio.h. Her kan du finne funksjonene som har med input/output å gjøre. Hvis du trykker på en funksjon så finnes det gode eksempler på hvordan de skal brukes.

VIKTIG: Merk at c++ versjonen av stdio.h heter cstdio.h, men siden vi programmerer i C så skal vi bruke C-versjonen som heter stdio.h og husk dette når du skal inkludere header i toppen av ditt c-program.

Vanlige spørsmål

Hvordan finner jeg lengden på en string?

Lengden på en string finner du med metoden strlen. En enkel og dum implementasjon av denne ser slik ut:

/*
 * Looks for the first byte in the string containing 0 (zero). 
 * The number of bytes preceding the zero is the length of the string.
*/
 int strlen2(char *str) {
    int len = 0;
   
    while(*str != '\0') {
        len++;
        str++;
    }
    return len;
}

Hvorfor viser ikke sizeof riktig størrelse på minneområdet?

char *mem = malloc(sizeof(struct Data))
printf("Size:%d\n", sizeof(mem));

Man skulle kanskje tro at det som skrives ut ville være størrelsen på struct Data, men det er det ikke. sizeof er ingen magisk funksjon som finner størrelsen på det allokerte minneområdet. Når du sender med en peker til sizeof, vil den fortelle deg hvor mange byte denne pekeren bruker, nemlig 8 byte (64bit) eller 4 byte (32bit). Størrelsen på minneområdet må du holde styr på selv.

Hvordan sammenligner jeg strukter?

Du må sammenligne hvert element i struktene, hver for seg.

Jeg vil konvertere en int til en string med metoden itoa, men funksjonen finnes ikke!

Hvis man søker på nettet etter en funksjon som skal konvertere en int til en string nevnes ofte metoden itoa, men denne metoden er ikke ANSI C. En halv-god erstatning til itoa er sprintf, (se man sprintf)

Feilmeldinger under kjøring av programmer

Hva er segmentation fault?

Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med Wikipedia

Les om hvordan du debugger dette på siden om debugging.

Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 ***

Det står forklart hva som er problemet. free kalles to ganger på samme peker, dvs. at du prøver å frigjøre et minneområdet som allerede er frigjort.


Feilmeldinger ved kompilering

"error: dereferencing pointer to incomplete type"

Det betyr som regel at du prøver og bruke en struct, men har glemt og definere den. Husk alltid å inkludere (include) de korrekte headerfilene.

"implicit function declaration"

Det betyr vanligvis at du har glemt å inkludere en header-fil øverst i programmet (#include). Bruk man-sidene for å finne hvilke headerfiler hver funksjon krever.

"assignment type mismatch" og "incompatible types in assignment"

Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:

double d = 1.0;
int *i;
i = d;

"initialization makes pointer from integer without a cast"

Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).

<math.h>

Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?

Du må fortelle kompilatoren at du skal bruke mattebilblioteket (libm). I gcc ser dette slik ut: "gcc -lm prog.c". Årsaken til at du ikke trenger å bruke dette for de vanlige headerfilene slik som stdio.h er at de ligger i libglibc som alltid linkes med programmene dine. C-programmering

Feilhåndtering i C-programmer

Måten man håndterer feil i C er ikke like konsekvent som i f.eks. Java. Normalt vil returverdien til en metode angi om det skjedde noe feil, f.eks. vil malloc returnere NULL hvis den ikke fikk allokert et minneområdet. Hva som betyr at en feil har oppstått er dokumentert i man-siden for funksjonen.

errno

En del C-funksjoner har en litt mer avansert måte å håndtere feil. I tillegg til å returnere en verdi, kan de bruke errno for å angi hva slags feil som oppsto. Variabelen errno er tilgjengelig med #include <errno.h>. Hvis en feil oppstår man kan bruke denne variabelen til å hente ut en feilmelding som forklarer feilen.

Mange metoder i C-biblioteker bruker errno, noen eksempler er fopen, fclose, read, write.

  • perror printer feilmeldingen til feilen som oppsto sist. Den tar en string som argument som printes før feilmeldingen. Hvis argumentet er NULL vil kun feilmeldingen printes.
  • strerror tar errno-variabel som input og returnerer en string med feilmeldingen.

Et eksempel på bruk av errno

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main(void) {
   
    char *fname1 = "ikkeeksisterendefil.txt";
    FILE *fp = fopen(fname1, "r");
   
    if (fp == NULL) {
        // perror sjekker errno, og skriver ut feilmelding til standard error.
        perror("ERROR");
    }
    else {
        printf("%s was opened successfully\n", fname1);
    }  

    char *fname2 = "/etc/shadow";
    fp = fopen(fname2, "r");
   
    if (fp == NULL) {
        // strerror returnere en char-peker som skrives ut med printf.
        printf("ERROR opening %s. %s\n", fname2, strerror(errno));
    }
    else {
        printf("%s was opened successfully\n", fname2);
    }
   
    return 0;
}