FAQ C-programmering

Fra mn/ifi/INF1060
Revisjon per 17. jun. 2010 kl. 22:11 av Bendiko@uio.no (diskusjon | bidrag) (Ny side: == 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. E…)

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

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; ).

  • 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

  • Utskrift til skjerm

For å skrive til skjermen brukes metoden printf. Denne metoden brukes litt anderledes enn System.out.println i Java. Den tar et variabelt antall argumenter, hvor først argument alltid er en string.

printf("Dette skrives ut på skjermen\n");

Denne stringen kalles format-stringen, og kan inneholde ulike tegn som angir hva slags argumenter som kommer senere:

int tall = 10;
printf("Dette er et tall:%d\n", tall);

Her brukes %d for å angi at det kommer et argument etter format-stringen som i eksempelet overfor er et heltall.

Det er ingen grense for hvor mange argumenter som kan angis.

char *text = "Eksempel på et desimaltall:";
float desimaltall = 3.14;
int heltall = 10;
printf("%s %f og et heltall i hex-format:%x\n", text, desimaltall, heltall);	

Merk at man må angi linjeskift selv med '\n'.

Det er fullt mulig å kalle printf uten format-string slik:

char *text = "Dette er en tekst";
printf(text);

...den vil da tolke stringen som sendes inn som format-stringen, og hvis denne stringen tilfeldigvis inneholder format-tegn vil den anta at det finnes flere argumenter. Å kalle printf uten format-string kan utgjøre en sikkerhetsrisiko og er strengt forbudt!

Gjør alltid slik:

char *text = "Dette er en tekst\n";
printf("%s" ,text);

Mer informasjon finnes på man-siden til printf.

  • 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)

  • 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;

}


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:

  1. include <stdio.h>
  2. include <stdlib.h>
  3. include <string.h>
  4. 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;

}