=========== C - Programmering Amiga OS 2.xx =================== Av Kjell Cederfeldt. Del 10. Söndag den 20 Dec 1992. ------------------------------- Efter ett långt uppehåll är vi nu igång! Kursen kommer att fortsätta med utgångspukt från Sas/C V6. För er som inte har Sas/C kan ändå hänga med, men titta i tidigare exempel hur kompileringarna går till. Vi kommer från och med nu att accelerera takten fram till vi når en mer Amiga specifik nivå. Men innan vi kan börja programmera Amigaunikt med allt vad detta innebär, har vi ett par bitar kvar. Structurer, listor och pekare. Detta är *MYCKET* viktigt att ha bra kläm på då man skall programera Amiga. Hela Amigan och dess funktioner bygger nämligen på detta. Vi kommer att i detta avsnitt ägna lite åt en tillbakablick samt titta på structurer, listor och pekare. Mycket av det som har tagits upp i de tidigare kursdelarna, kommer givetvis att som en naturlig del i programmerandet att tas upp i fortsättningen. Men om du har tappat en del av vad de 9 tidigare kursdelarna innehåller, är det en god ide att gå igenom det innan du fortsätter. I med det att Sas släppt sin nya kompilator, går vi igenom detaljer vad som har ändrats. Och det är faktiskt en hel del. Men till att börja med kan nämnas att kompileringskommandot sc5 motsvaras direkt av tidigare versions LC (Sc står för Sas compiler och 5 för Version 5 kompatibel). Genom att skriva 'sc5 -L' kan alla tidigare exempel kompileras om utan att behöva ändra någonting. I och med version 6 har kraven på deklarering av funktioner och datatyper ökat för att förenkla för oss att alltid ha angivit allt på rätt sätt. Till att börja med kan detta kännas lite jobbigt och rörigt. Men vi kommer att gå igenom detta också. Förändringar i Sas/C --------------------- Vi skriver in ett kort exempelprogram för att visa vad som ändrats. /********* Test.c *********/ main() { printf("Hej på er!\n"); } Vi kan kompilera detta med att skriva sc5 -L Test.c Vi känner igen oss. vi har bara bytit ut LC mot sc5. Men när vi kompilerar programmart får vi ett varingsfel: Test.c 3 Warning 100: no prototype declared for function "printf" Proggrammet fungerar dock som vanligt. Att få varningsfel i programmet är inte att föredra. Det talar om att man inte har angett (deklarerat) allt riktigt. Vad kompilatorn klagar på är alltså att den inte känner till funktionen printf. Funktionen printf finns inte beskriven i programmet utan ligger med i de funktioner som automatiskt länkas med. Kompilatorn vill dock ha denna funktionen beskriven innan. Genom att lägga till raden '#include ' i början av programmet. hämtas 'headerfilen' för standard in/ut hantering in innan programmet kompileras. I den filen finns funktionen printf beskrivet. #include /********* Test.c *********/ main() { printf("Hej på er!\n"); } Vi kompilerar och länkar med sc5 -L Test.c Varningen skall nu vara borta. Jag skall visa hur man gör en egen prototyp (funktionsdeklarering) av en egen funktion. #include /********* Test.c *********/ main() { /* Anroppar funktionen skriv() för att skriva ut texten */ skriv("Hej på er!\n"); skriv("Vi testar prototyper.\n"); } skriv(string) char *string; { printf("%s", string); } Vi kompilerar och länkar med sc5 -L Test.c Vid kompileringen fick vi två varningsfel: Test.c 7 Warning 100: no prototype declared for function "skriv" Test.c 15 Warning 85: return value mismatch for function "skriv" Expecting "int", found "void" Tydligt är att kompilatorn vill ha reda på hur funktionen skriv() ser ut. Vi måste alltså tala om detta med att göra en prototyp för detta. Vi lägger därför till raden 'void skriv(char *);' i vårt program. #include /****** prototyper ******/ void skriv(char *); /********* Test.c *********/ main() { /* Anroppar funktionen skriv() för att skriva ut texten */ skriv("Hej på er!\n"); skriv("Vi testar prototyper.\n"); } skriv(string) char *string; { printf("%s", string); } Vi kompilerar och länkar med sc5 -L Test.c Nu fick vi inte bara ett varingsfel utan också ett kompileringsfel: Test.c 18 Error 72: conflict with previous declaration See line 5 file "Test.c" Test.c 18 Warning 161: no prototype declared at definition for function "skriv" Detta beror på att vi i prototypen för vår funktion skriv() talat om att funktionen inte lämnar något returvärde (är tyst (void)), så vi skriver därför in ordet void framför vår funktion skriv(). #include /****** prototyper ******/ void skriv(char *); /********* Test.c *********/ main() { /* Anropar funktionen skriv() för att skriva ut texten */ skriv("Hej på er!\n"); skriv("Vi testar prototyper.\n"); } void skriv(string) char *string; { printf("%s", string); } Vi kompilerar och länkar med sc5 -L Test.c Nu är alla fel och varingsfel helt borta. Detta kommer att ställa till en del "problem" för oss i fortsättningen. "Allt" måste beskrivas i förhand och problemet med att veta hur man gör det eller var det finns beskrivet kommer att bli lite småjobbigt innan man lär sig det. Men lyckligtvis kommer jag att hjälpa er med det :-) Vi har i exemplet hela tiden angivet sc5. Denna version av kompilatorn gör att medsända kommandon är kompatibla med de som man angav i version V5 eller tidigare. Detta kommer vi inte att använda oss av i forsättningen utan vi kommer att använda oss av den nya standarden i Sas/C V6. Vi testar att kompilera programmet ovan på följande sätt: sc Test.c LINK SC står alltså för kompileringen och LINK för att vi automatiskt vill länka. (Vid länkningen tar Sas med starup kod och annat som behövs, detta kommer vi att gå in närmare på sedan). Men i Del 1 av kursen, sades att länkaren hette BLINK. I version 6 heter den SLINK. Den fungerar i stort sätt på samma sätt. Jag skall nu visa hur man kompilar och länkar i separata steg. Detta kan man sedan göra på olika sätt, dels genom att ange de olika objekten i 'SCoptions' eller i sin 'makefile' (kommer att beskrivas senare) Vi kompilerar först med sc: sc Test.c Vi länkar sedan med slink: slink lib:c.o test.o TO Test LIB lib:sc.lib lib:amiga.lib SMALLDATA SMALLCODE NODEBUG lib:c.o är den standard startupcode som föjler med sas då du köper den. En startuppkod är nödvänding för att programmet skall starta på rätt sätt. test.o är det objekt som skapas vi kompileringen med 'sc'. Detta är en binärfil men inte körbar eftersom den bland annat saknar startuppkoden. TO Test anger att vi vill kalla det färdiga programmet för 'Test' LIB anger att här kommer en del lib includeringar. lib:sc.lib lib:amiga.lib. I dessa lib's ligger definieringar och funktioners som kompilatorn automatisk hämtar in (och/eller vi själva hämtar in) vid kompileringen. Ett exempel på detta är just printf(). SMALLDATA och SMALLCODE talar om för länkaren att vi vill använda korta hoppanropp (om möjligt) och göra en lite kortare och effektivare kod. (Vilket brukar fungera i de flesta fall). NODEBUG betyder att vi inte vill ha med någon debugging (felsöknings) kod i vårt program. Detta är inte helt enkelt till att börja med, men det gör att man får mycker lättare att få kontroll över lite större projekt. Speciellt med projekt innehållande flera "delar" av kod. OBS! Man kan via Workbench gå in och ställa om flaggan NoLink till Link i 'SCoptions' och sedan spara detta lokalt i sitt projekt med [SAVE] eller globalt för alla projekt med [Save Default]. Sedan är det bara att klicka på Build iconen. (Det är det enklaste då man har enkla och okomliserade projekt). Men även i de mest anvancerade projekt, kan man sätta upp precis allt så som man vill att det skall ske och kompilera och länka från WB. Detta gör att Sas/C är mycket trevligt programmeringsverktyg. Peronligen föredrar jag att ställa om flaggan 'Version' till 'NoVersion' i 'SCoptions' för att slippa få med version strängen vid varje komlipering. Detta gör också att men enklare uppattar de felmeddelanden som kan bli. Pekare ------ I vårt programexempel Test.c använde vi oss av en pekare. Pekaren hette 'string'. Hur känner man igen en pekare? Oftast ser man det på att den har en stjärna framför sig. I exemplet ovan skrev vi '*string' variablen 'string' var av typen char. Och som vi kanske minns sedan tidigare är char en datatyp för ett tecken. I datatypen 'char' kan man bara lagra ett enda tecken. Men i detta fall är 'string' en pekare till första teckenet i stängen som medsändes till funktionsanropet 'skriv()' Strängen nolltermineras efter sista teckenet i funktionen. Här sköts det av C sjävt. (Se Del 8 av C-Kursen). Strängen 'string' deklareras i funktionen 'skriv()', Och tilldelas sin sträng genom funktionsanropet 'skriv()' i mainfunktionen. Det är där som minne till strängen tilldelas. Med andra ord så ligger alltså texten i strängen någonstans i minnet. Vid anropet av funktionen 'skriv()' skickas endast pekaren för var någonstans i minnet strängen finns. Vi skickar alltså inte med alla tecken in i funktionen, utan bara pekaren till första tecknet i minnet. Genom att strängen sedan innehåller ett nolltecken (nollterminering), kan 'printf()' funktionen veta hur lång strängen är. Variabeln string i funktionen 'skriv()' är alltså en pekare och innehåller adressen till strängen. Därför är datalängden på pekaren 'string' 32 bitars (samma som adresspekare). Datatypen char är lika lång som datatypen UBYTE vilket är 8 bitar. Vi gör ett exempel för att visa skillnaden mellan pekare och "vanliga" variabler. Vi kommer i exemplet nedan att använda oss av heltal (int). Dessa kallar vi 'value1' och 'value2'. Genom att skicka med dessa till funktionen 'calc()' kan vi i i funktionen 'calc()', beräkna talen och sedan skriva ut dem. I funktionen 'calc()' deklarerar vi de två medsända värdenas variabler till tal1 och tal2. Värdena som kommer till i funktionen kommer nu tilldelas i de båda heltalsvariablerna tal1 och tal2. Vi skriver och beräknar dem i 'printf()' funktionen. Vi tilldelar sedan tal1 summan av tal1 och tal2. Efter funktionsanropet 'calc()' i huvudfunktionen skriver vi sedan ut värdet i 'value1'. Titta på prototypen för funktionen 'calc()'. #include /****** prototyper ******/ void calc(int, int); /********* Pektest.c *********/ main() { int value1, value2; /* Anropar funktionen calc() för att beräkna och skriva ut talen */ value1 = 5; value2 = 10; calc(value1, value2); printf("Value1 är %d.\n", value1); } void calc(tal1, tal2) int tal1, tal2; { printf("%d + %d är %d\n", tal1, tal2, tal1 + tal2); tal1 = tal2 + tal1; } Vi testar att kompilera programmer ovan på följande sätt: sc PekTest.c LINK När vi kör programmet blir det följande utskrift! PekTest 5 + 10 är 15 Value1 är 5 Detta borde vara klart för de flesta. Anledningen till att Value1 är 5 efter funktionsanropet är att tal1 och tal2 i funktionen är lokala för just den funktionen och value1 och value2 är lokala i funktionen 'main()'. Detta gör att värdena förs med till funktionen 'calc()', men inte tillbaka igen. För att lösa detta krävs lite modifiering av programmet. Vi kommer att ändra heltalsvariablerna tal1 och tal2 till pekare. (Notera förändringen i prototypen för 'Calc()'). Eftersom funktionen kommer att kräva pekare till de båda talen, får vi sända adressen till value1 och value2 i mainfunktionen då dessa inte är av pekartyp. #include /****** prototyper ******/ void calc(int *, int *); /********* Pektest.c *********/ main() { int value1, value2; /* Anropar funktionen calc() för att beräkna och skriva ut talen */ value1 = 5; value2 = 10; calc(&value1, &value2); printf("Value1 är %d.\n", value1); } void calc(tal1, tal2) int *tal1, *tal2; { printf("%d + %d är %d\n", *tal1, *tal2, *tal1 + *tal2); *tal1 = *tal2 + *tal1; } Vi testar att kompilera programmet ovan på följande sätt: sc PekTest.c LINK När vi nu kör programmet får vi följande utskrift: PekTest 5 + 10 är 15 Value1 är 15. Skillanden i de båda fallen är alltså att efter funktionsanropet till 'calc()' är värdet i value1 något annat. Funktionen 'calc()' hittar sina båda tal ur de minnespositioner som de båda variablerna tal1 och tal2 pekar på. (Samma som i funktionen 'main()' ). Efter att skrivit ut och bekräknat, tilldelas minnespositionen för pekare 'tal1' den nya värdet. Eftersom detta är samma minnesposition som för funktionen 'main()', kan vi sedan skriva ut det nya värdet i value1 efter funktions- anropet till 'calc()' Detta är ett smidigt sätt om man vill få tillbaka flera värden än ett. Om det bara gäller ett ända värde kan man använda ett returnerat värde som funktionen lämnar (se Kurs-del 6). Anledningen till att man använder en stjärna framför tal1 och tal2 i funktionen 'calc()' är att man inte vill ändra/ha adressen till vart tal1 och tal2 pekar, (för de är ju pekare), utan man vill alltså ändra/se innehållet i dem. Genom att lägga till: printf("Adressen till tal1 %ld och till tal2 %ld\n", tal1, tal2); kan vi se vilken adress som tal1 och tal2 pekar på (skillanden mellan tal1 och *tal1). (%ld är samma sak som %d, men med skillnaden att vi vill ha en 32 bitars presentation). #include /****** prototyper ******/ void calc(int *, int *); /********* Pektest.c *********/ main() { int value1, value2; /* Anropar funktionen calc() för att beräkna och skriva ut talen */ value1 = 5; value2 = 10; calc(&value1, &value2); printf("Value1 är %d.\n", value1); } void calc(tal1, tal2) int *tal1, *tal2; { printf("%d + %d är %d\n", *tal1, *tal2, *tal1 + *tal2); printf("Adressen till tal1 %ld och till tal2 %ld\n", tal1, tal2); *tal1 = *tal2 + *tal1; } Vi testar att kompilera programmet ovan på följande sätt: sc PekTest.c LINK När vi nu kör programmet får vi följande utskrift: PekTest 5 + 10 är 15 Adressen till tal1 128849668 och till tal2 128849664 Value1 är 15. Det är alltså på adress 128849668 som värdet 5 lagras. På adress 128849664 lagras värdet 10. Då vi anropar funktionen calc() skriver vi ut ett '&' tecken framför value1 och value2. Detta skickar istället för värdet 5 och 10 adressen till value1 och value2. Value1 och value2 är ju inte några pekare. Om man utesluter '&' tecken kommer funktionen 'calc()' tro att de båda talen ligger på adress 5 och adress 10. Dessutom skulle kompilatorn troligtvis klaga och ge följade varningstext: Pektest.c: Warning 88 in Pektest.c line 18: argument type incorrect; Expecting "int *", found "int" Vi kan lägga till raden: printf("Adressen till value1 %ld och till value2 %ld\n", &value1, &value2); för att kontrollera att adresserna är samma i 'main()' som i 'calc()' #include /****** prototyper ******/ void calc(int *, int *); /********* Pektest.c *********/ main() { int value1, value2; /* Anropar funktionen calc() för att beräkna och skriva ut talen */ value1 = 5; value2 = 10; printf("Adressen till value1 %ld och till value2 %ld\n", &value1, &value2); calc(&value1, &value2); printf("Value1 är %d.\n", value1); } void calc(tal1, tal2) int *tal1, *tal2; { printf("%d + %d är %d\n", *tal1, *tal2, *tal1 + *tal2); printf("Adressen till tal1 %ld och till tal2 %ld\n", tal1, tal2); *tal1 = *tal2 + *tal1; } Vi testar att kompilera programmet ovan på följande sätt: sc PekTest.c LINK När vi nu kör programmet får vi följande utskrift: PekTest Adressen till value1 128869252 och till value2 128869248 5 + 10 är 15 Adressen till tal1 128869252 och till tal2 128869248 Value1 är 15. Listor ------- Listor består av en serie med samma datatyp. Alltå kan en lista vara en serie med strängar, det kan också vara en serie med tal av typen int. Listor kan ha lite olika uteseende, och med utseendet kan listor kallas för lite olika saker. Men vad man normalt tänker på när man hör listor är "vektor". Ett annat namn på en lista kan vara matris osv.. Här kommer ett deklarations exempel på en lista (Vektor). int dag[7]; /* Lista för dagar */ Denna typ av vektor kan användas för att exempelvis innehålla olika tal för varje dag! Kanske ett värde för hur många timmar man arbetat varje dag! Här skapas alltså 7 stycken int som ligger eftervarandra i en lista. int dagar[12]; /* Månadens dagar */ Vektorn ovan kan användas till för att hålla reda på hur många dagar det är i en månad. Vi gör ett programexempel av detta. /* Månadens dagar */ #include int dagar[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; main() { int index; for (index = 0; index < 12; index++) printf("Månad %d har %d dagar\n", index + 1, dagar[index]); } Vi testar att kompilera programmet ovan på följande sätt: sc List.c LINK När vi nu kör programmet får vi följande utskrift: Lista Månad 1 har 31 dagar Månad 2 har 28 dagar Månad 3 har 31 dagar Månad 4 har 30 dagar Månad 5 har 31 dagar Månad 6 har 30 dagar Månad 7 har 31 dagar Månad 8 har 31 dagar Månad 9 har 30 dagar Månad 10 har 31 dagar Månad 11 har 30 dagar Månad 12 har 31 dagar Vad händer i programmet? Lägg märke till att listan börjar på noll och inte på ett. Listan innehåller 7 element (0 - 6). Innehållet i listan initieras (tilldelas sina värden) i den globla deklarationen. Innehållet i första elementet (noll) är alltså '31' och i andra elementet (ett) är värdet '28' osv.... dagar[0] innehåller 31 dagar[1] innehåller 28 dagar[2] innehåller 31 ---- dagar[5] innehåller 30 dagar[6] innehåller 31 dagar är alltså en pekare till listan. Den pekar på första elementet i listan. dagar[0] pekar också på första elementet. dagar[1] pekar på andra elementet i listan osv... Det är alltså stora likheter mellan en pekare och en lista. Vi kan vidareutveckla programmet lite. Vi lägger till en lista som innehåller månadsnamnen. /* Månadens dagar */ #include int dagar[12] = {31,28,31,30,31,30,31,31,30,31,30,31}; char man[12][10] = {"Januari", "Feburari", "Mars", "April", "Maj", "Juni", "Juli", "Augusti", "September", "Oktober", "November", "December"}; main() { int index; for (index = 0; index < 12; index++) printf("Månad %s har %d dagar\n", man[index], dagar[index]); } Vi testar att kompilera programmet ovan på följande sätt: sc List.c LINK När vi nu kör programmet får vi följande utskrift: Lista Månad Januari har 31 dagar Månad Feburari har 28 dagar Månad Mars har 31 dagar Månad April har 30 dagar Månad Maj har 31 dagar Månad Juni har 30 dagar Månad Juli har 31 dagar Månad Augusti har 31 dagar Månad September har 30 dagar Månad Oktober har 31 dagar Månad November har 30 dagar Månad December har 31 dagar Som du säkert ser har listan 'man' två index. Detta kallas för matris. Det är tolv strängar med max 10 tecken i varje. Notera att du i detta fall också måste räkna med nollterminerningen efter sista teckenet. Eftersom den längsta strängen är hela 9 tecken lång måste vi ange att det skall få plats med tio tecken i vajre sträng. Så listan (matrisen) har alltså reserverats för att innehålla 10 gånger 12 tecken. Maximalt 120 tecken. Som du säkert redan har listat ut :-) är strängar en typ av lista. Varje element i strängen är av samma typ (med andra ord en char). Vi kommer att som en naturlig del av Amigans operativsystem stöta på detta med listor, så vi går inte in mer på detta nu! Strukturer ----------- Strukturer är en mycket trevlig och användbart sätt att lagra data. Dessutom är det ett vanligt förekommande i Amigavärden. En struktur kan innehålla flera element av data, men behöver nödvändigtvis inte vara av samma typ. En struktur kan till och med innehålla andra strukturer. Amigans operativsystem har redan massor av strukturer, men det finns också möjlighet att enkelt göra egna. Vi skall testa att göra en stuktur som vi kallar för person. Det kan liknas med ett personregister. Strukturen ser ut som följer: struct person { char namn[30]; char telefon[12]; int amigamodel; }; Detta kan liknas med ett personregister. Vi ser att strukturen person innehåller 3 olika element. 2 av dem är av typen char (listor). En av dem är av typen int. Genom att skriva strukturen på detta sätt deklarerar vi upp strukturen och talar om hur den ser ut i sin helhet. Vi skall nu testa detta i ett programexempel. /* Personregister */ #include #include /* Deklaration av strukturen person */ struct person { char namn[30]; char telefon[12]; int amigamodel; }; main() { struct person myperson; strcpy(myperson.namn, "Anders Andersson"); strcpy(myperson.telefon, "031-303030"); myperson.amigamodel = 4000; printf("\nUtskrift av personinnehåll\n"); printf("Namn %s\n", myperson.namn); printf("Telefonnr %s\n", myperson.telefon); printf("Amiga %d\n", myperson.amigamodel); } Vi testar att kompilera programmet ovan på följande sätt: sc Person.c LINK När vi nu kör programmet får vi följande utskrift: Person Utskrift av personinnehåll Namn Anders Andersson Telefonnr 031-303030 Amiga 4000 Jag skall nu förklara programmet. #include Eftersom funktionen 'strcpy()' används för att kopiera in namn och telefonnr in i strukturens strängvariabler, måste vi ha en prototyp som beskriver funktionen 'strcpy()' den återfinner vi i filen string.h. Det är därför som vi includerar den. struct person { char namn[30]; char telefon[12]; int amigamodel; }; Vi deklarerar hur strukturen person ser ut. Notera att detta bara beskriver hur den ser ut (vad den innehåller). Vi talar också om att det finns en struktur som heter person. Detta är inte en "variabel" som vi kan använda oss av att lagara data. struct person myperson; Här deklarerar vi upp en datatyp av typen struktur med namn myperson. myperson ärver alltså egenskaperna från strukturen person. myperson är en "variabel" som vi kan lagra data i. När vi vill lagra data i strukturen myperson anger vi helt enkelt just det variabelnamnet. Vi måste också ange i vilket element (index) som vi vill lagra data i. detta gör man genom att ange exempelvis namn. Vi måste använda en punkt mellan myperson och namn: myperson.namn På detta sätt vet vi vilket index i strukturen som vi vill påverka. strcpy(myperson.namn, "Anders Andersson"); Här kopieras strängen "Anders Andresson" in i strängen myperson.namn. Eftersom myperson.namn inte är något annat än en lista innehållande flera char datatyper kan man inte använda ett likamed tecken, utan blir tvungen att kopiera in hela strängen tecken för tecken. Detta är vad funktionen 'strcpy()' gör. strcpy(myperson.telefon, "031-303030"); Precis som vid namnet, kopieras telefonnr in. myperson.amigamodel = 4000; Här tilldelas strukturens sista element sitt värde. Detta är en int och därför kan man alltså använda ett likamed tecken. printf("Namn %s\n", myperson.namn); Vi skriver ut innehållet i strukturen. Vi talar om att vi vill använda oss av innehållet i namn strängen i strukturen myperson. Samma sak ser för de andra elementen i strukturen. Vi ändrar lite i programet. /* Personregister */ #include #include /* Deklaration av strukturen person */ struct person { char namn[30]; char telefon[12]; int amigamodel; }; main() { struct person myperson; printf("Ange namn / Blankt avslutar\n"); gets(myperson.namn); printf("Ange telefonnr\n"); gets(myperson.telefon); printf("Ange Amigamodell (500/600/1000/1200/2000/3000/4000)\n"); scanf("%d", &myperson.amigamodel); printf("\nUtskrift av personinnehåll\n"); printf("Namn %s\n", myperson.namn); printf("Telefonnr %s\n", myperson.telefon); printf("Amiga %d\n", myperson.amigamodel); } Vi testar att kompilera programmet ovan på följande sätt: sc Person.c LINK När vi nu kör programmet får vi följande utskrift: Person Ange namn / Blankt avslutar Anders Andersson Ange telefonnr 031-303030 Ange Amigamodell (500/600/1000/1200/2000/3000/4000) 4000 Utskrift av personinnehåll Namn Anders Andersson Telefonnr 031-303030 Amiga 4000 Vilket namn, telefonnr och amigamodel som blir beror på vad du matar in. Jag skall nu förklara programmet närmare. Skillnaden här är att vi använder en del funktioner för att kunna ändra data vi körningen i stället för att sätta fasta värden i programmet. Funktionen 'gets()' hämtar en sträng från tangentbordet (standard input) och lagar det i det medföljande argumentet. scanf("%d", &myperson.amigamodel); Funktionen 'scanf()' hämar värdet från tangetbordet och lagar det i myperson.amigamodel (se kursdel 7). Notera att 'scanf()' vill ha pekaren till argumentet. (OBS!!! 'gets()' vill också ha en pekare till sitt argument, men eftersom detta är en sträng (lista) så pekar ex. myperson.namn på första tecknet i strängen. myperson.namn[0] pekar också på första tecknet medan myperson.namn[1] pekar på andra tecknet osv...) Vi skall nu göra om myperson till en pekare till strukturen. Då får vi en strukturpekare. /* Personregister */ #include #include /* Deklaration av strukturen person */ struct person { char namn[30]; char telefon[12]; int amigamodel; }; /****** prototyper ******/ void printstrukt(struct person *); main() { struct person myperson; printf("Ange namn / Blankt avslutar\n"); gets(myperson.namn); printf("Ange telefonnr\n"); gets(myperson.telefon); printf("Ange Amigamodell (500/600/1000/1200/2000/3000/4000)\n"); scanf("%d", &myperson.amigamodel); printstrukt(&myperson); } void printstrukt(pers) struct person *pers; { printf("\nUtskrift av personinnehåll\n"); printf("Namn %s\n", pers->namn); printf("Telefonnr %s\n", pers->telefon); printf("Amiga %d\n", pers->amigamodel); } Genom att köra programmet ser vi inte någon skillnad mot tidigare. Det är bara ren programteknisk skillnad. Jag förklarar skillnaden. printstrukt(&myperson); Vi skickar med strukturen myperson som en pekare. (Kan man skicka med strukturen utan att det är en pekare?..... Svar nej! Eftersom strukturen är en samling av flera olika variabler kan man inte det. I så fall blir man tvungen att skicka varje separat variabel som ett eget argument, vilket helt klart blir mycket sämre!!!). struct person *pers; Vi delkarerar strukturen pers som en strukturepekare av strukturtypen person. Att det är en pekare ser vi genom att det är en stjärna framför variabelnamnet pers. printf("Namn %s\n", pers->namn); Vi skriver precis som tidigare ut innehållet ur strukturen, men eftersom pers är en pekare till vår struktur måste vi byta ut punkten mellan pers och namn till en pil (->). Pilen skrivs som ett minustecken och ett 'större än' tecken. Samma gäller också för de andra raderna. @BEGIN_FILE_ID.DIZVery good C Guide in swedish. @END_FILE_ID.DIZ