Strängar En sträng i C är helt enkelt en array av char: char namn[20]; För att få strängar att bete sig som om de vore av dynamisk längd markeras strängens slut med null-tecknet \0 : J o z e f S w i a t y c k i \0 Biblioteksfunktioner för stränghantering, i/o-operationer mm behandlar strängar fram till första påträffade null-tecknet. Exempel: vill man i ovanstående exempel ta bort efternamnet och endast behålla förnamnet räcker det med att göra namn[5]= \0 ; Det friställer givetvis inte utrymmet, men stränghanterings- och i/o-funktioner kommer att endast behandla tecknen fram till \0. Bild 34 Strängar (forts.) En strängkonstant skrivs inom dubbla citationstecken: Jozef Kompilatorn lägger till ett null-tecken vid lagring av konstanten, skall man deklarera ett utrymme för den måste det alltså finnas plats för ett extra tecken. Eftersom det inte finns operationer för hela arrayer måste strängar kopieras, jämföras osv. tecken för tecken. Det finns dock färdiga biblioteksfunktioner för detta, främst i string.h En char-array kan dock som vanligt initieras vid definitionen - kompilatorn kopierar in strängen då: char namn[6]= Jozef ; Obs! igen att detta endast är tillåtet vid initiering, inte i tilldelningssatser. Obs! vidare att utrymmet måste rymma det avslutande null-tecknet. Vid initiering kan antalsangivelsen utelämnas (som vanligt): char namn[]= Jozef Swiatycki ; Bild 35 1
string-biblioteket Innehåller rutiner för kopiering, jämförelse av och sökning i strängar (str-funktioner) samt ospecificerade minnesareor (mem-funktioner). Tillgänglig genom #include <string.h> Viktigaste: char *strcpy(char *dest, const char *source); Kopierar från source till dest (tom första påträffade null-tecknet). Returnerar dest. char *strncpy(char *d, const char *s, int n); Kopierar som mest n tecken från s till d (tom första påträffade null-tecknet). Returnerar dest. Även för många andra str-funktioner finns n -varianter. char *strcat(char *dest, const char *source); Kopierar source till slutet på dest, returnerar dest. int strcmp(const char *s1, const char *s2); Jämför s1 och s2, returnerar positivt om s1 > s2, 0 om s1 == s2, negativt om s1 < s2. int strlen(const char *str); Returnerar strängens längd fram till (exklusive) första null-tecknet. Bild 36 string-biblioteket, forts. char *strchr(const char *s, int c); Returnerar den först påträffade förekomsten av tecknet c i strängen s (eller NULL) char *strstr(const char *s1, const char *s2); Returnerar den först påträffade förekomsten av strängen s2 i strängen s1 (eller NULL) char *strtok(char *s, const char *delimiters); Används för att få pekare till delsträngar i s, avgränsade av tecknen i delimiters. Vid första anropet returneras pekare till det först påträffade tecknet som inte ingår i delimiters och nästa påträffade delimiter-tecknet skrivs över med \0. Vid efterföljande anrop ska s vara NULL och strtok ger pekare till nästa delsträng (har tydligen en statisk pekare till strängen internt). Returnerar NULL när inget icke-delimiter-tecken påträffats. Obs! förändrar s! Får inte användas på strängkonstanter! Exempel: char line[] = Vilken, konstig; funktion! ; char *word = strtok(line,,;! ); while (word!= NULL){ printf( %s\n, word); word = strtok(null,,;! ); } Bild 37 2
ctype-biblioteket I standardbiblioteket ctype (tillgänglig genom #include <ctype.h>) finns det ett antal funktioner för test av enskilda tecken. Dessa funktioner tar in ett tecken som argument (argumentet är en int för att även kunna ta emot EOF) och returnerar 1 om tecknet uppfyller testet, 0 annars. Exempel på funktionerna: int isalpha(int c); -är c en bokstav int isdigit(int c); -är c ett siffertecken int islower(int c); -är c en gemen bokstav Det finns även två funktioner för omvandling mellan gemena och versaler: int tolower(int c); - returnerar motsvarande gemen int toupper(int c); - returnerar motsvarande versal Testerna och omvandlingarna gäller per default endast engelska bokstäver, men kan fås att fungera för svenska bokstäver genom att man sätter svensk locale : #include <locale.h>... int main(void){ setlocale(lc_ctype, sv_se ); Bild 38 Introduktion till stdio Bibliotek innehållande symboliska konstantnamn, typer och rutiner för input och output. Man får tillgång till dessa genom #include <stdio.h> I Unix betraktas alla filer som strömmar av bytes, ingen skillnad görs mellan textfiler och binärfiler. All tolkning av data är C-programmats ansvar. På andra system kan det dock finnas skillnader mellan textfiler och binärfiler (främst hantering av radslut på textfiler). stdio definierar typen FILE för filobjekt. Rutiner för filhantering tar emot pekare till sådana objekt som argument, vissa returnerar sådana pekare. En egen filvariabel skall alltså deklareras som FILE *: FILE *minfil; Bild 39 3
Standardfiler Vid programstarten finns tre filer öppnade: stdin - öppnad för input och kopplad normalt till tangentbordet stdout - öppnad för output och kopplad normalt till skärmen stderr - även den öppnad för output och kopplad till skärmen stdin stdout programmet stderr Anledningen till att det finns två standard-outputfiler kopplade normalt till skärmen är att stdin och stdout kan vara omdirigerade till skivminnesfiler eller kopplade till andra processers stdout resp. stdin genom pipes. Även i sådana situationer vill man dock att felmeddelanden skall skrivas ut på skärmen - därför finns stderr. Felmeddelanden bör alltså alltid skrivas på stderr. Bild 40 Repetition - omdirigering och pipes Omdirigering görs från kommandoraden där programmet startas. Omdirigering av stdin görs med < filnamn, t.ex.: prog < minfil prog kommer nu att läsa stdin från filen minfil istf. tangentbordet. Omdirigering av stdout görs med > filnamn, t.ex.: prog > minfil prog kommer nu att skriva stdout på filen minfil istf. skärmen. Även stderr kan omdirigeras till en fil, med 2> filnamn, t.ex.: prog 2> minfil En pipe innebär att ett programs stdout kopplas till ett annat programs stdin, detta görs från kommandoraden med tecknet, t.ex.: prog1 prog2 Allt detta sker från kommandoraden, transparent för C-programmet. Bild 41 4
Formatterad i/o mot stdin och stdout int printf(const char *format,...); Konverterar sina argument enligt formatsträngen och skriver ut dem på stdout. Returnerar antalet utskrivna tecken eller EOF om fel har inträffat. Exempel: printf( Priset är %d kronor och %d öre\n, k, p); int scanf(const char *format,...); Läser tecken från stdin, matchar dem mot formatsträngen, konverterar enligt formatsträngen och lägger i de variabler vilkas adresser anges efter formatsträngen. Returnerar antalet gjorda konverteringar. Avbryter vid första felet. Exempel: int tim, min; printf( Vad är klockan? ); scanf( %d:%d, &tim, &min); Bild 42 Viktigaste symboler i formatsträngen: Konverteringsangivelser %d - argumentet är en int, textrepresentationen decimal %c - argumentet är en char %s - argumentet är en sträng, dvs. char * (utrymme måste finnas) %f - argumentet är en double Mellan % och konverteringssymbolen kan man ange fältbredden, antalet decimaler, vänsterjustering o.s.v. med notationer som ändrar betydelse beroende på konverteringstypen och om det är fråga om utskrift eller inläsning. scanf slutar vid påträffat radslut och lämnar radslutet kvar i bufferten. Man bör därför tömma bufferten efter ett scanf-anrop: scanf( %d, &tal); while (getchar()!= \n ) ; Bild 43 5
Egna filer Deklaration: FILE *minfil; Öppnande: FILE *fopen(const char *name, const char *mode); Försöker öppna filen med det namnet name för operationer enligt mode. Returnerar pekare till stdios FILE (vad det nu är) eller NULL vid misslyckande. mode kan vara: r - input w - output r+ - input och output på en existerande fil w+ - input och output på en ny fil a - tillägg i slutet på en existerande fil samt några varianter på dessa. Stängning: int fclose(file *file); Stänger filen. Returnerar 0 vid lyckad operation, EOF vid misslyckad. Bild 44 Formatterad i/o mot filer och strängar I/O mot filer motsvarande printf och scanf: int fprintf(file *file, const char *format,...); int fscanf(file *file, const char *format,...); Motsvarande konverteringar mot strängar: int sprintf(char *buffer, const char *format,...); int sscanf(char *buffer, const char *format,...); Bild 45 6
Bytevis (teckenvis) I/O int getc(file *file); int fgetc(file *file); Läser in en byte från filen file och returnerar den som en int. Om det inte fanns någon mer byte att läsa returneras EOF, därför är returtypen int. int getchar(void); Som ovan fast från stdin. int ungetc(int c, FILE *file); Stoppar tillbaka tecknet c på filen file (som skall vara öppen för input). Egentligen läggs tecknet i bufferten. Garanteras fungera endast en gång per inläsning. Returnerar c eller EOF vid misslyckande. int putc(int c, FILE *file); int fputc(int c, FILE *file); Skriver ut tecknet c på filen file, returnerar det utskrivna tecknet. int putchar(int c); Som ovan fast till stdout. Bild 46 Radvis i/o (strängar) char *gets(char *buff); Läser in tecken från stdin in i utrymmet som pekas ut av buff, slutar vid radslut eller filslut. Radslutstecknet läses men stoppas inte in i buff, däremot stoppas in ett null-tecken efter sista inlästa tecknet. Returnerar buff. Obs! Ingen kontroll att utrymmet räcker, bör därför inte användas. char *fgets(char *buff, int max, FILE *file); Läser in tecken från filen file in i utrymmet som pekas ut av buff, slutar vid radslut eller filslut. Läser dock högst max-1 tecken. Om radslut påträffas bland de max-1 tecknen så stoppas den in i buff. Ett null-tecken stoppas in efter sista inlästa tecknet. Returnerar buff eller NULL om det inte fanns mer att läsa. int fputs(const char *str, FILE *file); Skriver ut strängen str på filen file. Returnerar EOF vid fel. int puts(const char *str); Som ovan fast mot stdout. Bild 47 7