Föreläsning 7 Strängar I C använder vi strängar för att lagra text. Strängar kommer in ganska sent i kursen, det är jag inte så glad över, men det finns också fördelar, vi har grundat oss rejält nu i funktioner, pekare och arrayer. Många av de sakerna kommer då att kunna illustreras ganska bra med strängar. 13.1 Strängliteraler En literal betyder de tecken som man ska skriva i källkoden för att representera någonting. Det som vi ska skriva i C-källkod för att representera en sträng är en följd av tecken omsluten av två citationstecken, så här: Detta är en en sträng i C Vi har redan stött på strängar i printf() och scanf()-funktionerna, vi har skrivit ut strängar då vi gjort saker av typen printf( Mata in storlek: ); Då har vi skrivit ut en sträng och den sträng som skrevs ut var Mata in storlek:. Normalt sett följs väl denna utskrift av någon sorts inmatning, kanske med scanf() där användaren får mata in någonting som ska handla om någon storlek. Escapesekvenser i strängar Om citationstecken, alltså, används för att ange ett strängavslut i en strängliteral, hur skriver man då om man faktiskt vill ha ett citationstecken som del av strängen? Svaret är att man använder en så kallad escapesekvens, vi skriver först ett backslash, följt av citationstecken. Strängliteralen Kalle \ Olle är då en strängliteral som reprenterar texten Kalle Olle. Likadant med nyradstecken, för nyrad skriver vi \n, som vi säkert sett i många anrop till printf(). Vi gör på samma sätt med backslash själv, vi skriver \\ för att teckna den sträng som representerar texten som endast består av ett backslash: \. Det finns fler escapesekvenser, men dessa är viktigast. 13.2 Lagring i minnet och variabler Strängar lagras som en array av tecken, men det viktiga tillägget att strängen, i minnet avslutas med en tecknet som har nummer 0. Detta tecken kallas nul. Den har asciikod 0 och kan skrivas '\0'. (Det är inte samma sak som makrot NULL som är en pekare, alltså en minnesadress minns att vi inte kan blanda adressangivelser och tal, även om adresser faktiskt anges av heltal. Både nul och NULL har värdet dt numeriska värdet 0 men de betyder olika saler.) Så här ser den interna representationen ut av strängen ABC : Uttryckt med asciikoder: [65 66 67 0] eller om vi uttrycker det med tecken: ['A' 'B' 'C' '\0'] Det krävs alltså fyra minnespositioner, fyra bytes. ('A' är en teckenliteral) Alla strängar måste alltid, utan något enda undantag, innehålla en extra minnesposition som innehåller nul-tecknet. Detta markerar strängens slut. En tom sträng representeras som en array av tecken där den första positionen innehåller nollan. Om inte nul-tecknet finns där ska vi inte anse det som en sträng, då är det endast en array av tecken (char) som också kan vara användbar. johnnyp@kth.se Sidan 1 av 11
Initiering av strängvariabler HI1024 Programmering, grundkurs, 8.0 hp, KTH STH, hösten 2012 Vi kan deklarera och intiera en strängvariabel direkt genom att skriva char date[8] = June 14 ; det här innebär att teckenarrayen date skapas, initieringen innebär att en sträng läggs in i den och sedan kan vi arbeta med strängen som vi vill. Den interna representationen blir så här: ['J' 'u' 'n' 'e' ' ' '1' '4' '\0'] Observera att längden på denna sträng är 7 och den kräver 8 lagringsplatser. Vi har återigen använt teckenliteraler ('J', 'u', etc.) för att bli extra tydliga i vad som lagras i varje position. Boken gör inte det och då är det svårt att se att det står ett mellanslag, ' ', i position 4 i den array som lagrar denna sträng. Vi ser här igen sista positionen som innehåller nul-tecknet. Återigen, det MÅSTE vara där, annars fungerar ingenting annat, alla saker i C som hanterar strängar förutsätter att nul-tecknet definerar slutet på strängen. Vi kan ha mer plats i en teckenarray så att vi kan lagra strängar av varierande storlekar, det viktiga är bara att komma ihåg att det ska finnas ett extra tecken med som innehåller nul-tecknet. Vi skulle, i samma teckenarray som ovan kunna lagra strängen Hej som då skulle se ut så här: ['H' 'e' 'j' '\0'????]. Det spelar ingen roll vad platserna efter nultecknet innehåller, allt i C som hanterar strängar, bryr sig inte om vad som kommer efter nultecknet. Teckenarrayer och pekare till tecken Arrayer är pekare har vi ju hört. Nja, då det gäller parametrar till funktioner är de samma sak. Men inte annars, vi kan skriva char *date = June 14 ; och då pekar teckenpekaren på en sträng och därmed är den en teckenarray. Denna version kan då användas istället för versionen char date[] = June 14 ;. Men vi måste vara försiktiga, date är en array i ena fallet och en pekare i andra fallet, det är inte samma sak såvida vi inte arbetar med parametrar till funktioner. Det betyder att pekarversionen (char *date) inte är skyddad mot förändring av sitt värde som arrayversionen (char date[]) är. Jag rekommenderar inte pekarvarianten, deklarera hellre strängar i arrayer istället för säkerhets skull. 13.3 In- och utmatning av strängar Vi vet ofta inte på förhand hur många tecken en sträng är, om vi ber användaren mata in ett namn så kan användaren skriva hur många tecken som helst. När vi har med inmatning av strängar att göra så kan detta bli problematiskt. Utmatning av strängar är lättare, då är längden på strängen given på förhand. Vi börjar med att studera utmatning av strängar. Utmatning av strängar med puts() och printf() Vi har ofta redan använt funktionen printf() så vi behöver egentligen inte nämna så mycket mer om den, vi har sett den. Vi ska bara beröra omvandlingsspecifikationen för strängar, %s. Vi skriver alltså i formatsträngen %s om vi vill mata ut en sträng som vi anger i parameterlistan till printf(), vi ser på ett vansinnigt enkelt exempel: printf( Hej %s!\n, str ); Om str innehåller strängen Kalle blir resultatet av denna sats utskriften Hej Kalle!, följt av ny rad. Funktionen puts() är ännu enklare, vi skriver bara puts(str) så skrivs strängen str ut. johnnyp@kth.se Sidan 2 av 11
Inmatning av strängar med scanf och gets Funktionen gets() är inte bra. Inte scanf() heller. Men vad ska vi använda då? Ni kan använda båda, men vi ska vara medvetna om att de inte har någon inbyggd säkerhetskontroll beträffande huruvida användaren matar in någonting som inte ryms i den variabel som vi vill lagra strängen i. Detta kan vara allvarligt i proffslivet, men här i skolan gör vi det enkelt för oss och använder båda funktionerna utan att fundera så mycket på det. Med scanf() använder vi omvandlingsspecifikationen %s i formatsträngen då vi vill läsa in en sträng. Om vi vill läsa in en sträng i teckenarrayen str med deklarerationen char str[20]; så skriver vi så här med scanf(): scanf( %s, str); Observera att vi inte har en adressoperator på str i anropet till scanf(). Alltså inte scanf( %s, &str);. Varför det? Jo, str är namnet på en teckenarray och namnet på en array är redan en pekare, str är alltså redan en adress. När vi matar in heltal måste vi definitivt ha adressoperatorn på, (scanf( %d, &heltal);), men, då det alltså gäller strängar ska vi inte ha det. Det finns ett litet bekymmer med %s i scanf() och det gäller det som kallas för white space. Omvandlingen %s betyder läs en sammanhängande följd av tecken, vi kan alltså inte ha mellanslag i denna följd av tecken, eller tabulatorsteg eller mellanslag. Just mellanslag, tabulatorsteg och return kallas med ett gemensamt ord för white space och vi kan alltså inte ha något white space inom %s. Det enda detta brukar betyda rent praktiskt är att vi inte kan läsa in strängar med mellanslag i. Vi brukar inte vara intresserade av att lägga in tabulatorsteg i strängar i matar in i program och return, alltså nyradstecken, använder vi ändå för att avsluta inmatningen av en sträng så det enda som detta utesluter är mellanslag. Vi kan alltså inte mata in en sträng med innehållet Tor Leif i en sträng med scanf( %s, fornamn);, vilket faktiskt kan vara problematiskt om vi nu vill kunna mata in dubbelnamn i en variabel som heter fornamn, alltså förnamn, med borttagna prickar från ö:et. Lösningen till problemet med mellanslag kan vara att använda funktionen gets() istället. Den funktionen läser in en hel rad i den sträng som den opererar på. Om vi återigen har deklarationen char str[20]; och skriver gets(str); så läses en hel rad in, alltså str fylls med det innehåll som användaren skriver fram till och med han/hon trycker return. Det betyder att gets() ofta är ett bättre val än scanf(). Men både gets() och scanf() har ett allvarligt problem och det är att de inte kollar hur många tecken som användaren matar in. Vi ska bortse från det i den här kursen, men senare, om ni skriver proffsprogram i C behöver ni undvika dessa funktioner. Då behöver ni använda fgets() som har en inbyggd spärr. Det finns dessutom en del bekymmer med inmatningsbufferten då man blandar inmatning av strängar och primitiva datatyper som int och float etc. Vi studerar detta särskilt i en övning som behandlar just detta. johnnyp@kth.se Sidan 3 av 11
13.4 Tillgång till enskilda tecken i en sträng Boken har ett lysande exempel på en funktion som heter count_spaces(), vi ska titta på den tillsammans med ett testprogram som vi skriver här. (Vi utelämnar #include-direktivet.) int count_spaces(const char s[]) int count = 0, i; for(i=0; s[i]!='\0'; i++) if(s[i]==' ') count++; return count; main() char str[] = "Denna sträng har 4 mellanslag."; printf("antal mellanslag: %d.\n", count_spaces(str)); En testkörning ser ut så här: Antal mellanslag: 4. Som vi ser arbetar loopen genom att söka efter nul-tecknet som avslutar strängen, då loopen hittar nul-tecknet har loopen kommit till slutet av strängen och avbryter då körningen. I varje varv kontrolleras vad innehållet i s[i] är, eftersom en sträng måste vara en array av tecken kan vi tillgå varje enskilt tecken genom att använda index, här har vi valt att indexera strängen/teckenarrayen med heltalsvariabeln i. Om vi hittar ett mellanslag så ökas count med 1 och då är loopen är klar, dvs, när vi gått igenom hela strängen, returneras count som resultat som då bli antalet mellanslag i strängen som vi arbetar med. I testkörningen ser vi en sträng med 4 mellanslag och just 4 skrivs ut som resultat. Vi måste skicka en sträng till denna funktion. Det betyder att det måste finnas ett nul-tecken som avslutar följden av tecken i arrayen. Detta är ett mycket viktigt exempel på hur funktioner ställer krav på de som anropar dem. Utan nul-tecknet bryts inte for-loopen då den ska och count får kanske ett vansinnigt värde. Det är också mycket troligt att programmet som anropar funktionen kraschar, vi gör if(s[i]==' ') count++; jättemånga gånger, på helt vansinniga ställen, det betyder att programmet troligen läser utanför sin minnesarea (när i blir jättestort) och då avbryts programmet av operativsystemet. Som sagt det här är ett intressant exempel på att en funktion som kräver en sträng som parameter verkligen måste få en sträng också, nul-tecknet måste finnas någonstans i strängen. Detta leder in på nästa område, vi ska studera en mängd funktioner som är specialskrivna för just strängar. De har alla den här egenskapen att de absolut kräver välformade strängar som indata. johnnyp@kth.se Sidan 4 av 11
13.5 Strängbiblioteket, string. HI1024 Programmering, grundkurs, 8.0 hp, KTH STH, hösten 2012 Vi kan inte direkt tilldela en sträng ett värde, det går inte att skriva str = bla bla bla ; om str är deklarerad som teckenarray. Det går att initiera en sträng, om vi i deklarationen skriver char str[20] = bla bla bla ; så kommer str att ha det innehåll vi förskriver, men det går bara att göra så här i en deklaration. I löpande kod måste vi göra någon form av loop som går igenom str tecken för tecken och lägger in rätt tecken på rätt plats. På samma sätt kan vi inte jämföra innehållet i två olika strängar direkt, om str1 och str2 är två olika teckenarrayer så kan vi inte skriva if(str1==str2) och hoppas på att innehållet i strängarna jämförs. Varför? Jo, str1 och str2 är ju två pekare till två olika minnesutrymmen (två olika teckenarrayer) och de adresserna är ju normalt alltid olika så värdet på str1 är normalt alltid skilt från värdet på str2. Av samma anledning är det inte heller meningsfullt att göra en tilldelning, str1=str2;, eftersom det bara innbär att de båda pekarna nu pekar på samma utrymme. Om man vill att en ordentlig kopiering av innehållet ska ske behöver vi återigen ha något slags loopkonstruktion som går igenom tecken för tecken och ser till att rätt tecken kommer in på rätt plats. Vi måste också styra så att nultecknet avslutar den resulterande strängen. Lyckligtvis finns allt detta gjort redan, vi har ett bibliotek som heter string och som innehåller många mycket användbara stränghanteringsfunktioner. Här löses tilldelning, jämförelse med mera. För att få tillgång till strängbiblioteket behöver vi skriva #include <string.h> i början av vårt program. De funktioner vi ska studera här är strcpy() string copy, strlen() string length, strcat() string concatenate och strcmp() string comparison. Vi kan studera hur de alla anropas genom manualkommandot i UNIX. Vi kan skriva man strcpy till exempel, och få en precis beskrivning av hur man anropar den funktionen. Vi får då följande text: NAME strcpy, strncpy - copy a string SYNOPSIS #include <string.h> char *strcpy(char *dest, const char *src); char *strncpy(char *dest, const char *src, size_t n); DESCRIPTION The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Det finns mer text än så i manualsidan, men den här första texten är tillräcklig för att förklara hur strcpy() fungerar översiktligt. Det mest informativa är just funktionsprototypen, som alltså visar hur man ska anropa funktionen: strcpy(char *dest, const char *src). Vi har tydligen två argument, dest och src. Båda är pekare till char, dvs de kan vara arrayer av tecken som då innehåller strängar. Funktionen kräver att det är strängar som skickas och kärnan i funktionssättet beskrivs av meningen:...copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. Exempel på anrop kan då vara dessa: strcpy(namn, Johnny ); (kopierar in Johnny i strängen namn), strcpy(namn2,namn); (kopierar in det som finns i namn till namn2.) johnnyp@kth.se Sidan 5 av 11
Vi studerar nu de tre andra strängfunktionerna, strlen(), strcat() och strcmp(). Funktionen strlen() - string length Vi studerar manualtexten för strlen(): NAME strlen - calculate the length of a string SYNOPSIS #include <string.h> size_t strlen(const char *s); DESCRIPTION The strlen() function calculates the length of the string s, not including the terminating '\0' character. RETURN VALUE The strlen() function returns the number of characters in s. Vi ser då att den funktionen är ganska lätthanterlig, ett kort exempel demonstrerar: main() char str[20] = En text ; int length; length = strlen (str); printf( Length: %d.\n, length); Detta program har körningen Length 7. Längden av strängen En text är alltså 7. Hur många tecken innehåller str? Jo, alltid 20. Vilken är minsta storleken på teckenarrayen som kan lagra strängen En text? Jo, det blir 8, eftersom vi alltid måste ha en plats för nul-tecknet. Funktionen strcat() - string concatenation Det engelska ordet concatenation betyder konkatenering som är ett finare ord för sammanslagning. Denna funktion slår alltså samman två strängar. Vi studerar åter en manualsida: NAME strcat, strncat - concatenate two strings SYNOPSIS #include <string.h> char *strcat(char *dest, const char *src); DESCRIPTION The strcat() function appends the src string to the dest string, overwriting the null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. Texten är något nedkortad, det finns mer upplysningar i manualsidan, men det här är det viktigaste. johnnyp@kth.se Sidan 6 av 11
Vi ser på ett testprogram: (Vi skriver ut inkluderingsdirektiv just här.) #include <stdio.h> #include <string.h> main() char str1[20], str2[20]; strcpy(str1, "abc"); //Nu innehåller str1 "abc" strcat(str1, "def"); //Nu innehåller str1 "abcdef" strcpy(str1, "abc"); //Nu innehåller str1 "abc" strcpy(str2, "def"); //Nu innehåller str2 "def" strcat(str1, str2); //Nu innehåller str1 "abcdef" Kommentarerna i programmet ger en förklaring av hur strcpy() och strcat() fungerar. Båda funktionerna strcpy() och strcat() kräver att vi skickar in strängar till dem. För strcpy():s del är det dock inte helt nödvändigt att första parametern är en sträng eftersom den ändå skrivs över. Vi skulle kunna fundera över en egen strcat(), hur skulle den fungera? #include <stdio.h> void egen_strcat (char * dest, const char * src) int dest_end=0, i; while(dest[dest_end]!= '\0')dest_end++; // Hitta slutet på dest. for(i=0; src[i]!='\0'; i++) dest[dest_end+i] = src[i]; // Kopiera från src till dest. dest[dest_end+i]='\0'; // Lägg till strängavslut i dest. main() char str1[20] = "abc"; char str2[20] = "def"; egen_strcat(str1, str2); printf("str1: %s.\n", str1); En testkörning: str1: abcdef Lägg märke till att vi inte behöver inkludera string.h nu. Lägg också märke till hur starkt funktionen beror på att vi verkligen har nul-tecken som avslutar de ingående strängarna. Fråga: Skulle while(dest[dest_end++]!= '\0'); vara korrekt? johnnyp@kth.se Sidan 7 av 11
Funktionen strcmp() - string comparison Som tidigare nämnt kan vi alltså inte jämföra strängar genom att direkt jämföra namnen på de respektive teckenarrayerna som de båda strängarna är lagrade i. För att jämföra två strängar bildar vi ett jämförelsetal som returneras av funktionen strcmp(). Manualsidan ger oss detaljerna: NAME strcmp - compare two strings SYNOPSIS #include <string.h> int strcmp(const char *s1, const char *s2); DESCRIPTION The strcmp() function compares the two strings s1 and s2. It returns an integer less than, equal to, or greater than zero if s1 is found, respectively, to be less than, to match, or be greater than s2. RETURN VALUE The strcmp() and strncmp() functions return an integer less than, equal to, or greater than zero if s1 (or the first n bytes thereof) is found, respectively, to be less than, to match, or be greater than s2. Vi illustrerar detta med ett exempel där användaren matar in strängar och programmet jämför dem. main() char str1[20], str2[20]; do printf("str 1: "); gets(str1); if(strlen(str1)==0)break; printf("str 2: "); gets(str2); if(strlen(str2)==0)break; if(strcmp(str1,str2)<0) printf("%s < %s.\n", str1, str2); if(strcmp(str1,str2)==0) printf("%s == %s.\n", str1, str2); if(strcmp(str1,str2)>0) printf("%s > %s.\n", str1, str2); while(1); Och testkörningen: Str 1: olle Str 2: kalle olle > kalle. Str 1: Olle Str 2: kalle Olle < kalle. Str 1: Olle Str 2: olle Olle < olle. Str 1: olle Str 2: olle olle == olle. Str 1: Vi ser att bokstavsordningen är baserad på asciitabellen, så olle > kalle men också Olle < kalle. Det beror ju på att stora bokstäver kommer innan de små i asciitabellen. johnnyp@kth.se Sidan 8 av 11
13.6 String Idioms, studera själva. 13.7 Arrayer av strängar HI1024 Programmering, grundkurs, 8.0 hp, KTH STH, hösten 2012 Vi tittar på ett enkelt exempel där vi studerar en array av strängar: #define ANTAL 5 int main(void) char namnlista[antal][10]; int i; for(i=0;i<=antal-1;i++) printf("mata in namn %d: ", i+1); gets(namnlista[i]); for(i=0;i<=antal-1;i++) printf("namn %d: %s.\n", i+1, namnlista[i]); Det enda programmet gör är att låta användaren mata in 5 strängar och sedan skriva ut dem. Så här ser provkörningen ut: (Det användaren skriver är i fet stil.) Mata in namn 1: johnny Mata in namn 2: nina Mata in namn 3: kalle Mata in namn 4: olle Mata in namn 5: lisa Namn 1: johnny. Namn 2: nina. Namn 3: kalle. Namn 4: olle. Namn 5: lisa. Om vi nu vill sortera dessa strängar i bokstavsordning så kan vi använda oss av strcmp(). Det kan också vara bra att ha en bytesfunktion som byter plats på två strängar. Vi tar en titt på en platsbytesfunktion och studerar den i detalj först. void swap (char *s1, char *s2) char tmp[20]; strcpy(tmp,s1); strcpy(s1,s2); strcpy(s2,tmp); En vanlig platsbytesfunktion som har en temporär mellanlagringsplats (tmp) och som byter plats på sina argument. Först kopieras s1 till mellanlagringsplatsen (tmp), sedan skrivs innehållet i s1 över med innehållet i s2. Till sist tar vi det gamla värdet på s1 och lägger i s2. johnnyp@kth.se Sidan 9 av 11
Ett program som då sorterar de inmatade strängarna baserat på platsbytesfunktionen visas nedan vid sidan om körningen. Programmet: (#include-direktiv är utelämnade.) Testkörning: #define ANTAL 5 void swap (char *s1, char *s2) char tmp[20]; strcpy(tmp,s1); strcpy(s1,s2); strcpy(s2,tmp); int main(void) char namnlista[antal][10], tmp[10]; int i, k, m; for(i=0;i<=antal-1;i++) printf("mata in namn %d: ", i+1); gets(namnlista[i]); Mata in namn 1: sara Mata in namn 2: johnny Mata in namn 3: olle Mata in namn 4: lisa Mata in namn 5: kalle Namn 1: sara. Namn 2: johnny. Namn 3: olle. Namn 4: lisa. Namn 5: kalle. Namnlista, sorterad: Namn 1: johnny. Namn 2: kalle. Namn 3: lisa. Namn 4: olle. Namn 5: sara. printf("\n"); for(i=0;i<=antal-1;i++) printf("namn %d: %s.\n", i+1, namnlista[i]); printf("\n"); //Sortering: for(k=0;k<=antal-1;k++) for(m=k+1;m<=antal-1;m++) if(strcmp(namnlista[k],namnlista[m])>0) swap(namnlista[k],namnlista[m]); printf("namnlista, sorterad:\n"); for(i=0;i<=antal-1;i++) printf("namn %d: %s.\n", i+1, namnlista[i]); I detta exempel ser vi många intressanta saker, programmet innehåller en array av strängar, alltså en array av arrayer. Vidare har vi sortering vilket är en av de viktigaste manövrarna när man arbetar med databehandling. Sorteringen innehåller en nästlad loop som man behöver tänka en del för att förstå. Vidare har vi anrop till flera viktiga funktioner, strcmp() och en egen funktion som heter swap(). Det här är ett av kursens viktigaste exempel och jag rekommenderar att ni studerar detta exemepel mycket noggrannt. Kommandoradsargument I UNIX brukar man ge kommandon till någonting som heter kommandoskalet. Ett program kan då ofta ta emot så kallade parametrar som ändrar på programmets beteende. Kommandot ls listar alla johnnyp@kth.se Sidan 10 av 11
filer i den arbetskatalog man uppehåller sig i och om man bara skriver ls vid en kommandoprompt får man en lista på alla filer i arbetskatalogen. Men om man skriver ls -l så ändrar man kommandots beteende så att det ger en lång listning med detaljer om filernas attribut. Vi har då skickat argumentet -l till ls som alltså påverkar kommandot på detta sätt och får det att ge en mer utförlig respons. Då ett program är skrivet i C och startat från en kommandoprompt så finns det en möjlighet för C- programmet att fånga upp kommandoradsargument. De kommer då som parametrar till själva main()-funktionen i en array av strängar. Detta sköts automatiskt av operativsystemet, det man behöver göra som programmerare är att deklarera main() på ett speciellt sätt. Vi skriver då int main (int argc, char *argv[]) och sedan skriver vi vårt C-program som vanligt. Skillnaden nu är att vi kan tillgå parametrar precis som om main() vore en funktion som anropades. Vilket den är! Om vi studerar föregående exempel och arbetar med kommandoradsparametrar istället kan vi studera följande program. Testkörningen visas brevid, det kompileras till ett program som heter getnames. int main(int argc, char *argv[]) int i; for(i=1;i<argc;i++) printf("namn %d: %s.\n", i, argv[i]); $./getnames kalle olle lisa Namn 1: kalle. Namn 2: olle. Namn 3: lisa. $ Vi kan alltså ta in kommandoradsargumenten i en array som har namnet argv. Vi kommer att använda oss mycket av det här sättet att programmera under UNIX. Vi kan nu kombinera detta exempel med det förra som hade sortering och skapa ett sorteringskommando i UNIX: Programmet: void swap(char *s1, char *s2) char tmp[200]; strcpy(tmp,s1); strcpy(s1,s2); strcpy(s2,tmp); void get_args(int argc, char *argv[], char args[][10]) int i; for(i=1;i<argc;i++) strcpy(args[i],argv[i]); En provkörning:./mysort olle kalle lisa anna Namn 1: anna. Namn 2: kalle. Namn 3: lisa. Namn 4: olle. int main(int argc, char *argv[]) int i, j; char args[argc][10]; get_args(argc,argv,args); for(i=1; i<argc; i++) for(j=i+1;j<argc;j++) if(strcmp(args[i],args[j])>0) swap(args[i],args[j]); for(i=1;i<argc;i++) printf("namn %d: %s.\n", i, args[i]); Vi mellanlagrar argumenten i en array args, som vi hanterar med hjälpfunktionen get_args(). johnnyp@kth.se Sidan 11 av 11