FAQ C-programmering

Fra mn/ifi/INF1060
Revisjon per 1. sep. 2010 kl. 22:54 av Bendiko@uio.no (diskusjon | bidrag) (Vanlige spørsmål)

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'.


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)

Filemeldinger 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.


Filemeldinger ved kompilering

Hva betyr "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.

Hva betyr "implicit function declaration"?

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

Hva betyr "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;

Hva betyr "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 header-filene 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 filemelding 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;
}