https://wiki.uio.no/mn/ifi/INF1060/api.php?action=feedcontributions&user=Bendiko%40uio.no&feedformat=atommn/ifi/INF1060 - Brukerbidrag [nb]2024-03-29T05:50:09ZBrukerbidragMediaWiki 1.27.4https://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=73Hovedside2011-09-15T20:43:27Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
Innholdet på denne siden er flyttet til http://programmering.wiki.ifi.uio.no/Kategori:C-programmering</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=72FAQ Hjemmeeksamen 22010-11-13T04:18:27Z<p>Bendiko@uio.no: /* Hvordan fanger jeg signalet fra CTRL-C? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Sjekk siden for [[FAQ Nettverksprogrammering]], se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se "man signal" i terminalen.<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. <br />
send 1555 11111111 22222222 33333333 <br />
skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. <br />
<br />
En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=71FAQ Hjemmeeksamen 22010-11-13T04:17:42Z<p>Bendiko@uio.no: /* Meldings-ID; lokal eller global? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Sjekk siden for [[FAQ Nettverksprogrammering]], se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. <br />
send 1555 11111111 22222222 33333333 <br />
skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. <br />
<br />
En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=70FAQ Hjemmeeksamen 22010-11-13T04:17:03Z<p>Bendiko@uio.no: /* Sende en melding til flere mobiler? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Sjekk siden for [[FAQ Nettverksprogrammering]], se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. <br />
send 1555 11111111 22222222 33333333 <br />
skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. <br />
<br />
En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=69FAQ Hjemmeeksamen 22010-11-13T04:15:41Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Sjekk siden for [[FAQ Nettverksprogrammering]], se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Nettverksprogrammering&diff=68FAQ Nettverksprogrammering2010-11-13T04:10:15Z<p>Bendiko@uio.no: </p>
<hr />
<div>= Hvordan bruker jeg Berkeley Sockets? =<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
= cannot bind to socket: address already in use? =<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
= Hvordan skriver og leser jeg fra nettverket? =<br />
Såfremt du har en gyldig socket til disposisjon kan du bruke funksjonene read og write. (man 2 read, man 2 write).<br />
<br />
= Kan jeg anta at read og write leser og skriver så mange byte jeg håper de vil? =<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
<br />
= select =<br />
<br />
Link som forklarer det mer praktiske, dog kortfattet: http://www.labbook.cs.purdue.edu/cpointers.php<br />
<br />
select sjekker hvorvidt en mengde fildeskriptorer er klare for lesing/skriving, eller har "exceptional condition pending", altså noe uvanlig, altså feil (vanligvis).<br />
<br />
select kan da brukes til å lytte etter nye tilkoblinger på lytte-socketen, samt de andre socketene som brukes til å kommunisere med klientene.<br />
<br />
Så kan man spørre, hvorfor ikke bare sjekke det manuelt ved å prøve å lese?<br />
<br />
Vel, på vanlig vis så blokker fildeskriptorer (En fildeskriptor er en FILE*, eller en socket, eller noe annet liknende. sockets i socket.h oppfører seg som vanlige filer på mange måter). Blokking betyr at du blir ventende på input, og programmet fortsetter ikke før noe input har dukket opp. Dette vil du ikke ha, da din server skal kunne behandle flere klienter samtidig, og kan dermed ikke vente på en bruker uten å behandle andre som kanskje er klare.<br />
<br />
Man kan unngå dette med O_NONBLOCK, som gjør at en fildeskriptor ikke blokker, men returnerer en kode som sier "jeg er tom". Dette vil imidlertid bety at du sjekker om og om igjen, til noe kommer - noe som spiser prosessortid. Resultat: Treg, samt uelegant server.<br />
<br />
Det er her select kommer inn: Gitt x antall pipes, finn ut om noen har data i dem, uten å spise opp prosessoren. select blokker hvis INGEN av dem har data, og ingen har dødd - da venter vi til noen får data.<br />
<br />
Ellers returnerer select en kode som sier noe om dette - og ett av argumentene til select holder på informasjon om hvilke pipes som har data.<br />
<br />
Så kan du behandle de aktuelle pipene, og kalle select nok en gang for å vente på neste "runde". (se linken)<br />
<br />
== fd_set ==<br />
<br />
Dette er et set med alle fildeskriptorene du ønsker å lytte på:<br />
<br />
fd_set readfds;<br />
<br />
Denne bruker så select for å vite hvilke fildeskriptorer den skal sjekke.<br />
<br />
For å endre dette settet brukes ulike makroer. (Makroer kan ses på som enkle funksjoner).<br />
* FD_SET(int fd, fd_set *set); - Legger fd til i set.<br />
* FD_CLR(int fd, fd_set *set); - Fjerner fd fra set.<br />
* FD_ISSET(int fd, fd_set *set); - Returnerer true hvis fd er satt i set.<br />
* FD_ZERO(fd_set *set); - Fjerner alle deskriptorer fra set.<br />
<br />
== select-funksjonen ==<br />
<br />
select tar flere parametre, ikke alle er like viktige for oppgaven. Signaturen ser ut som følger:<br />
<br />
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);<br />
<br />
* Returverdi: Antall endrede fildeskriptorer. 0 Hvis timeout. -1 ved error.<br />
* arg1: int nfds: høysteste fildeskriptor + 1. Hvis du f.eks. lytter på 0, 3, 5 og 8, skal denne verdien være 9.<br />
* arg2: fd_set *readfds: Settet som definerer hvilke fildeskriptorer som skal sjekkes for lesing.<br />
* arg3: fd_set *writefds: Settet som definerer hvilke fildeskriptorer som skal sjekkes for skriving.<br />
* arg4: fd_set *exceptfds Settet som definerer hvilke fildeskriptorer som skal sjekkes for exceptions.<br />
* arg5: struct timeval *timeout: Definerer timout for select-funksjonen.<br />
<br />
Returverdi:<br />
<br />
Hvis man angir en timeout, vil select returnere enten når det er aktivitet på en fildeskriptor, eller når timeouten går ut. Ved timeout vil den returnere 0. Hvis man ikke angir timout vil select blokkere helt noe skjer på en av fildeskriptorene. Hvis noe skjer på flere av fildeskriptorene samtidig, vil retuverdien til select angi antallet fildeskriptorer med aktivitet. Hvis en feil oppstår vil select returnere -1.<br />
<br />
fd_set readfds;<br />
<br />
Denne definerer hvilke fildeskriptorer som skal sjekkes for lesing. Hvis man ønsker å lytte på tastaturet gjør du følgende:<br />
<br />
fd_set read_fds;<br />
FD_ZERO(&read_fds);<br />
FD_SET(STDIN, &read_fds); // STDIN == 0<br />
int ret = select(STDIN+1, &read_fds, NULL, NULL, NULL);<br />
<br />
// Here you can read from keyboard with fgets.<br />
....<br />
<br />
Merk at select endrer read_fds ved at den markerer fildeskriptorene der det ligger data. Det betyr at denne må nullstilles manuelt for hver gang select kalles. Hvis dette ikke gjøres vil FD_ISSET returnere true på fildeskriptorer som tidligere ble markert av select, og ikke bare etter sist kall.<br />
<br />
fd_set *writefds<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2. NULL brukes for å "deaktivere" denne.<br />
<br />
fd_set *exceptfds<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2. NULL brukes for å "deaktivere" denne.<br />
<br />
struct timeval *timeout<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2, men brukes slik:<br />
<br />
struct timeval tv;<br />
tv.tv_sec = 1; // One second<br />
tv.tv_usec = 200000; // 200000 microseconds == 200 ms<br />
select(STDIN+1, &readfds, NULL, NULL, &tv);<br />
<br />
For å deaktivere timeout, bruk NULL.<br />
<br />
Pseudokode for håndtering av tilkoblinger i SMS-serveren:<br />
<br />
fd_set readfds, tmp_fds;<br />
//Set up fd_set with listener socket.<br />
<br />
while(1) {<br />
<br />
// Remember to reset the fd-set with fresh values before calling select.<br />
int ret = select(...);<br />
<br />
if (ret == -1) {<br />
// Handle error<br />
}<br />
<br />
for (i = 0; ...) {<br />
<br />
FD_ISSET(i, &tmp_fds) {<br />
<br />
if (i == listen_sock) {<br />
// Handle new connection<br />
}<br />
else {<br />
// Handle network data on socket i<br />
}<br />
}<br />
}<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Nettverksprogrammering&diff=67FAQ Nettverksprogrammering2010-11-13T04:04:18Z<p>Bendiko@uio.no: </p>
<hr />
<div>= Hvordan bruker jeg Berkeley Sockets? =<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
= cannot bind to socket: address already in use? =<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
<br />
= Kan jeg anta at read og write leser og skriver det jeg håper de vil? =<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
<br />
= select =<br />
<br />
Link som forklarer det mer praktiske, dog kortfattet: http://www.labbook.cs.purdue.edu/cpointers.php<br />
<br />
select sjekker hvorvidt en mengde fildeskriptorer er klare for lesing/skriving, eller har "exceptional condition pending", altså noe uvanlig, altså feil (vanligvis).<br />
<br />
select kan da brukes til å lytte etter nye tilkoblinger på lytte-socketen, samt de andre socketene som brukes til å kommunisere med klientene.<br />
<br />
Så kan man spørre, hvorfor ikke bare sjekke det manuelt ved å prøve å lese?<br />
<br />
Vel, på vanlig vis så blokker fildeskriptorer (En fildeskriptor er en FILE*, eller en socket, eller noe annet liknende. sockets i socket.h oppfører seg som vanlige filer på mange måter). Blokking betyr at du blir ventende på input, og programmet fortsetter ikke før noe input har dukket opp. Dette vil du ikke ha, da din server skal kunne behandle flere klienter samtidig, og kan dermed ikke vente på en bruker uten å behandle andre som kanskje er klare.<br />
<br />
Man kan unngå dette med O_NONBLOCK, som gjør at en fildeskriptor ikke blokker, men returnerer en kode som sier "jeg er tom". Dette vil imidlertid bety at du sjekker om og om igjen, til noe kommer - noe som spiser prosessortid. Resultat: Treg, samt uelegant server.<br />
<br />
Det er her select kommer inn: Gitt x antall pipes, finn ut om noen har data i dem, uten å spise opp prosessoren. select blokker hvis INGEN av dem har data, og ingen har dødd - da venter vi til noen får data.<br />
<br />
Ellers returnerer select en kode som sier noe om dette - og ett av argumentene til select holder på informasjon om hvilke pipes som har data.<br />
<br />
Så kan du behandle de aktuelle pipene, og kalle select nok en gang for å vente på neste "runde". (se linken)<br />
<br />
== fd_set ==<br />
<br />
Dette er et set med alle fildeskriptorene du ønsker å lytte på:<br />
<br />
fd_set readfds;<br />
<br />
Denne bruker så select for å vite hvilke fildeskriptorer den skal sjekke.<br />
<br />
For å endre dette settet brukes ulike makroer. (Makroer kan ses på som enkle funksjoner).<br />
* FD_SET(int fd, fd_set *set); - Legger fd til i set.<br />
* FD_CLR(int fd, fd_set *set); - Fjerner fd fra set.<br />
* FD_ISSET(int fd, fd_set *set); - Returnerer true hvis fd er satt i set.<br />
* FD_ZERO(fd_set *set); - Fjerner alle deskriptorer fra set.<br />
<br />
== select-funksjonen ==<br />
<br />
select tar flere parametre, ikke alle er like viktige for oppgaven. Signaturen ser ut som følger:<br />
<br />
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);<br />
<br />
* Returverdi: Antall endrede fildeskriptorer. 0 Hvis timeout. -1 ved error.<br />
* arg1: int nfds: høysteste fildeskriptor + 1. Hvis du f.eks. lytter på 0, 3, 5 og 8, skal denne verdien være 9.<br />
* arg2: fd_set *readfds: Settet som definerer hvilke fildeskriptorer som skal sjekkes for lesing.<br />
* arg3: fd_set *writefds: Settet som definerer hvilke fildeskriptorer som skal sjekkes for skriving.<br />
* arg4: fd_set *exceptfds Settet som definerer hvilke fildeskriptorer som skal sjekkes for exceptions.<br />
* arg5: struct timeval *timeout: Definerer timout for select-funksjonen.<br />
<br />
Returverdi:<br />
<br />
Hvis man angir en timeout, vil select returnere enten når det er aktivitet på en fildeskriptor, eller når timeouten går ut. Ved timeout vil den returnere 0. Hvis man ikke angir timout vil select blokkere helt noe skjer på en av fildeskriptorene. Hvis noe skjer på flere av fildeskriptorene samtidig, vil retuverdien til select angi antallet fildeskriptorer med aktivitet. Hvis en feil oppstår vil select returnere -1.<br />
<br />
fd_set readfds;<br />
<br />
Denne definerer hvilke fildeskriptorer som skal sjekkes for lesing. Hvis man ønsker å lytte på tastaturet gjør du følgende:<br />
<br />
fd_set read_fds;<br />
FD_ZERO(&read_fds);<br />
FD_SET(STDIN, &read_fds); // STDIN == 0<br />
int ret = select(STDIN+1, &read_fds, NULL, NULL, NULL);<br />
<br />
// Here you can read from keyboard with fgets.<br />
....<br />
<br />
Merk at select endrer read_fds ved at den markerer fildeskriptorene der det ligger data. Det betyr at denne må nullstilles manuelt for hver gang select kalles. Hvis dette ikke gjøres vil FD_ISSET returnere true på fildeskriptorer som tidligere ble markert av select, og ikke bare etter sist kall.<br />
<br />
fd_set *writefds<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2. NULL brukes for å "deaktivere" denne.<br />
<br />
fd_set *exceptfds<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2. NULL brukes for å "deaktivere" denne.<br />
<br />
struct timeval *timeout<br />
<br />
Ikke nødvendig å bruke i hjemmeeksamen 2, men brukes slik:<br />
<br />
struct timeval tv;<br />
tv.tv_sec = 1; // One second<br />
tv.tv_usec = 200000; // 200000 microseconds == 200 ms<br />
select(STDIN+1, &readfds, NULL, NULL, &tv);<br />
<br />
For å deaktivere timeout, bruk NULL.<br />
<br />
Pseudokode for håndtering av tilkoblinger i SMS-serveren:<br />
<br />
fd_set readfds, tmp_fds;<br />
//Set up fd_set with listener socket.<br />
<br />
while(1) {<br />
<br />
// Remember to reset the fd-set with fresh values before calling select.<br />
int ret = select(...);<br />
<br />
if (ret == -1) {<br />
// Handle error<br />
}<br />
<br />
for (i = 0; ...) {<br />
<br />
FD_ISSET(i, &tmp_fds) {<br />
<br />
if (i == listen_sock) {<br />
// Handle new connection<br />
}<br />
else {<br />
// Handle network data on socket i<br />
}<br />
}<br />
}<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Nettverksprogrammering&diff=66FAQ Nettverksprogrammering2010-11-13T03:55:16Z<p>Bendiko@uio.no: Ny side: == Hvordan bruker jeg Berkeley Sockets? == Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia]. == cannot bind to socket: address already in use?…</p>
<hr />
<div>== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
<br />
== Kan jeg anta at read og write leser og skriver det jeg håper de vil? ==<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=65FAQ Hjemmeeksamen 22010-11-13T03:54:07Z<p>Bendiko@uio.no: /* Kan dere fortelle mer om Select()? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Sjekk siden for [[FAQ Nettverksprogrammering]], se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=64Hovedside2010-11-13T03:52:36Z<p>Bendiko@uio.no: /* Orakelside for INF1060 */</p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[FAQ Nettverksprogrammering]]<br />
* [[FAQ Oblig 1]]<br />
* [[FAQ Hjemmeeksamen 1]]<br />
* [[FAQ Hjemmeeksamen 2]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Hvordan strukturere et C-program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]<br />
* [[Andre tips]]<br />
* [[Andre ressurser]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=63FAQ Hjemmeeksamen 22010-11-13T03:51:04Z<p>Bendiko@uio.no: /* cannot bind to socket: address already in use? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Her er en forklaring på select, se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
Kan jeg anta at read og write leser og skriver det jeg håper de vil?<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=62FAQ Hjemmeeksamen 22010-11-13T03:50:23Z<p>Bendiko@uio.no: /* Hvordan bruker jeg Berkeley Sockets? */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på [http://en.wikipedia.org/wiki/Berkeley_sockets wikipedia].<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Her er en forklaring på select, se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
Kan jeg anta at read og write leser og skriver det jeg håper de vil?<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=61FAQ Hjemmeeksamen 22010-11-13T03:49:15Z<p>Bendiko@uio.no: /* Datastruktur for lagring av meldinger */</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på wikipedia.<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Her er en forklaring på select, se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
Kan jeg anta at read og write leser og skriver det jeg håper de vil?<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Hjemmeeksamen_2&diff=60FAQ Hjemmeeksamen 22010-11-13T03:48:23Z<p>Bendiko@uio.no: Ny side: == Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? == Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifi…</p>
<hr />
<div>== Må jeg gjøre alt fra hjemmeeksamen 1 i innleveringen av hjemmeeksamen 2? ==<br />
<br />
Nei, det er ikke nødvendig. Det eneste som er nødvendig å gjøre i hjemmeeksamen 2 er det som er spesifisert i oppgaveteksten for hjemmeeksamen 2.<br />
<br />
=== Prompt og innlesning ===<br />
<br />
Her kan du sannsynligvis bruke mye av koden fra hjemmeeksamen 1, så lenge det er i henhold til oppgaveteksten i hjemmeeksamen 2.<br />
<br />
=== Datastruktur for lagring av meldinger ===<br />
<br />
Hva slags struktur du bruker for å lagre meldingene er opp til deg. Hvis koden fra hjemmeeksamen 1 fungerte kan du bruke den, hvis ikke må du gjerne lage en enklere løsning.<br />
<br />
I hjemmeeksamen 2 er det ikke nødvendig å:<br />
<br />
* ha ett kontinuerlig minne for dataene<br />
* bruke bitmap eller bytemap<br />
* dele opp meldingene i datablokker<br />
<br />
Det blir altså ikke gitt ekstrapoeng for slike løsninger.<br />
<br />
== SMS-serveren skal kunne håndtere flere innkommende meldinger samt multiple telefoner ==<br />
<br />
Serveren skal kunne håndtere flere tilkoblinger på en gang; den skal altså kunne lytte på alle socketer og håndtere data som kommer fra klientene.<br />
<br />
== Hvordan bruker jeg Berkeley Sockets? ==<br />
<br />
Det står en meget bra artikkel på wikipedia.<br />
<br />
== cannot bind to socket: address already in use? ==<br />
<br />
Dette kan skje hvis du avslutter server/klient og starter opp igjen med en gang. Når du kjører bind vil porten være bundet til en socket, og vil da ikke være mulig å binde den samme porten på nytt. Når du avslutter programmet vil socketen havne i TIME_WAIT-tilstand, og porten vil ikke kunne brukes igjen før denne timeouten er ferdig.<br />
<br />
Ved å bruke flagget SO_REUSEADDR vil det likevel være mulig å bruke en port som er bundet til en socket i TIME_WAIT-tilstand.<br />
<br />
Legg til følgende i koden på egnet sted (før bind-kallet):<br />
<br />
int activate = 1;<br />
setsockopt(your_socket, SOL_SOCKET, SO_REUSEADDR, &activate, sizeof(int));<br />
<br />
== Kan dere fortelle mer om Select()? ==<br />
<br />
Her er en forklaring på select, se ellers man select i terminalen. Sjekk også Beej's guide to network programming.<br />
Kan jeg anta at read og write leser og skriver det jeg håper de vil?<br />
<br />
Det er ingen garanti for hvor mange byte read og write leser og skriver. read vil aldri lese mer enn det som oppgis i count, men den kan godt lese mindre. Det samme gjelder write; den vil aldri skrive mer enn count, men den kan skrive mindre. Det kan være ulike grunner til at de gjør nettopp det, og det er ingen god idé å anta at de ikke gjør det. Når du kaller write to ganger, er det ingen måte å skille mellom dataene fra disse to kallene på andre siden. To kall på write (på samme socket) rett etter hverandre som skriver 10 byte hver, vil sannsynligvis leses som 20 byte på andre siden. Det er dette applikasjonslagsprotokollen skal løse; hvordan skille mellom ulike meldinger.<br />
<br />
== Hvordan fanger jeg signalet fra CTRL-C? ==<br />
se man signal<br />
<br />
== Hva er en ACK, og når skal det brukes? ==<br />
<br />
ACK er en kortversjon av ACKnowledge og betyr bekreftelse. Når en melding sendes, skal det sendes en ACK-melding tilbake som bekrefter at denne (unike) meldingen har blitt mottatt. Både server og klient (mobil) skal sende ACK på meldinger som mottas.<br />
<br />
== Applikasjonslagsprotokoll, hva er det? ==<br />
<br />
I hjemmeeksamen 2 skal data sendes via et nettverk ved hjelp av TCP/IP, mellom klienter (mobil) og en server. TCP er en pålitelig protokoll som garanterer at dataene som sendes kommer fram på andre siden i eksakt samme form og rekkefølge. TCP kan dog ikke fortelle programmet ditt hva dataene betyr; det er bare bits. Derfor er det nødvendig med en applikasjonslagsprotokoll som definerer rammene rundt hva dataene som kommer på socketen faktisk betyr. Denne protokollen skal forklares og begrunnes i rapporten, så enkelt og konkret som mulig.<br />
<br />
== Skal jeg teste på en egen server, og hvordan gjøres det? ==<br />
<br />
Det fungerer fint å kjøre både klient (mobil) og server på den lokale maskinen, men det kan være greit å teste serveren på en av Ifi-serverne. Logg inn på login-maskinene slik: ssh login.ifi.uio.no og kjør server-programmet ditt derfra.<br />
<br />
== Meldings-ID; lokal eller global? ==<br />
<br />
Det var opprinnelig tenkt at alle IDer som klientene (mobilene) lager skulle være globalt unike. Dette ble endret slik at det ikke lenger er et krav. IDene skal altså kun være unike lokalt for hver mobil/server.<br />
<br />
== Sende en melding til flere mobiler? ==<br />
<br />
Kommandoen send skal kunne sende en melding til flere telefonnumre. send 11111111 22222222 33333333 1555 skal sende melding (ID 1555) til de tre numrene 11111111, 22222222 og 33333333. En enkel løsning vil være å sende meldingene tre ganger, med tre ulike destinasjons-telefonnumre. Dette er en løsning som vil noe poeng. En løsning som gir full uttelling er hvis man bruker multicast. Det vil si at meldingen sendes en gang til serveren, og serveren videresender meldingen til de telefonene som er oppført i "TO-feltet".<br />
<br />
== Ubegrenset kø-lengden på serveren, må jeg da skrive til disk hvis minnet er fullt? ==<br />
<br />
Når det i oppgaven beskrives at en løsning som gir ubegrenset antall meldinger i køen gir mer poeng, refererer det til implementasjonen, dvs. at løsningen ikke har en begrensning, med f.eks. et array på N plasser. Det er ikke nødvendig å skrive meldinger til disk hvis minnet er fullt.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=59Hovedside2010-11-13T03:43:19Z<p>Bendiko@uio.no: /* Orakelside for INF1060 */</p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[FAQ Oblig 1]]<br />
* [[FAQ Hjemmeeksamen 1]]<br />
* [[FAQ Hjemmeeksamen 2]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Hvordan strukturere et C-program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]<br />
* [[Andre tips]]<br />
* [[Andre ressurser]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=55Hvordan skrive et godt program2010-10-27T10:37:42Z<p>Bendiko@uio.no: /* Strukturer koden skikkelig */</p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
<br />
=== Strukturér koden skikkelig ===<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Strukturerer du programmet ditt skikkelig, blir det veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and returns their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the two integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=54Hvordan skrive et godt program2010-10-27T10:36:13Z<p>Bendiko@uio.no: /* Dokumentér hver metode */</p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
<br />
=== Strukturer koden skikkelig ===<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Strukturerer du programmet ditt skikkelig, blir det veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and returns their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the two integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_strukturere_et_C-program&diff=53Hvordan strukturere et C-program2010-10-22T22:33:59Z<p>Bendiko@uio.no: Ny side: Når et program vokser kan det vært lurt å vurdere om noe av koden bør skilles ut i egne filer. Hvis vi har en fil oblig1.c som du ønsker å dele opp, oppretter vi en ny fil med filend…</p>
<hr />
<div>Når et program vokser kan det vært lurt å vurdere om noe av koden bør skilles ut i egne filer. <br />
Hvis vi har en fil oblig1.c som du ønsker å dele opp, oppretter vi en ny fil med filendelse "c", f.eks. linked_list.c. I denne nye filen kan vi legge metodene som håndtere den lenkede listen.<br />
<br />
Eksempelvis kan vi si at filene har følgende metoder:<br />
oblig1:<br />
- main<br />
- print_list<br />
<br />
linked_list.c<br />
- void add(char *str)<br />
- char *get(int index)<br />
<br />
For at du skal kunne kalle disse metodene fra oblig1.c må vi fikse og ordne litt.<br />
Under kompilering må nemlig metodene være kjent når du kaller de, og slikt skjer ikke automatisk slik som i Java. Du må selv fortelle oblig1.c at vi har disse metodene tilgjengelig. <br />
Måten det gjøres på er å definere en header-fil med filendelse "f", linked_list.h og definere metodene i denne filen slik:<br />
<br />
void add(char *str);<br />
char *get(int index);<br />
<br />
I oblig1.c legger vi så til følgende ved de andre include-linjene:<br />
#include "linked_list.h"<br />
<br />
Ved kompilering ser kompilatoren du disse metodene er definert.<br />
<br />
Når du så kompilerer må du oppgi begge filene:<br />
gcc oblig1.c linked_list.c -o oblig1</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=52Hovedside2010-10-22T22:18:22Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[FAQ Oblig 1]]<br />
* [[FAQ Hjemmeeksamen 1]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Hvordan strukturere et C-program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]<br />
* [[Andre tips]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=51FAQ C-programmering2010-10-11T10:25:04Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
<br />
=== C Library ===<br />
<br />
Hvis du vil ha en side med god oversikt over standardbibliotekene i C så kan vi anbefale denne siden: http://www.cplusplus.com/reference/clibrary/ <br />
Merk at dette er en side for C++ men det inneholder også en god oversikt over standardbibliotekene som er i C.<br />
<br />
I menyen på venstre side så finner du de viktigste bibliotekene i C. F.eks så kan vi se at det er et bibliotek som heter stdio.h. Her kan du finne funksjonene som har med input/output å gjøre. Hvis du trykker på en funksjon så finnes det gode eksempler på hvordan de skal brukes.<br />
<br />
VIKTIG: Merk at c++ versjonen av stdio.h heter cstdio.h, men siden vi programmerer i C så skal vi bruke C-versjonen som heter stdio.h og husk dette når du skal inkludere header i toppen av ditt c-program.<br />
<br />
== Vanlige spørsmål ==<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
== Feilmeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med [http://en.wikipedia.org/wiki/Segmentation_fault Wikipedia]<br />
<br />
Les om hvordan du debugger dette på siden om [[debugging]].<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Feilmeldinger ved kompilering ==<br />
<br />
==== "error: dereferencing pointer to incomplete type" ==== <br />
<br />
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.<br />
<br />
==== "implicit function declaration" ==== <br />
<br />
Det betyr vanligvis at du har glemt å inkludere en header-fil øverst i programmet (#include). Bruk man-sidene for å finne hvilke headerfiler hver funksjon krever.<br />
<br />
==== "assignment type mismatch" og "incompatible types in assignment" ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== "initialization makes pointer from integer without a cast" ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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 headerfilene slik som stdio.h er at de ligger i libglibc som alltid linkes med programmene dine.<br />
C-programmering<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut feilmelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=50Hvordan skrive et godt program2010-10-11T07:12:40Z<p>Bendiko@uio.no: </p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
<br />
=== Strukturer koden skikkelig ===<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Strukturerer du programmet ditt skikkelig, blir det veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and return their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the to integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=49Hvordan skrive et godt program2010-10-11T07:12:12Z<p>Bendiko@uio.no: </p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
<br />
== Strukturer koden skikkelig ==<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Strukturerer du programmet ditt skikkelig, blir det veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and return their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the to integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=48Hvordan skrive et godt program2010-10-06T20:18:17Z<p>Bendiko@uio.no: /* Flyttet makefile til 'andre tips' */</p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and return their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the to integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
== Ikke legg all koden i main-metoden ==<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Srukturerer du programmet ditt skikkelig, blir veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Andre_tips&diff=47Andre tips2010-10-06T20:17:40Z<p>Bendiko@uio.no: Ny side: == Finnes det noen big-endian maskiner jeg kan teste programmet mitt på? == Ja, ''ulrik'' er en big-endian maskin. Logg inn med ssh ulrik == Lag en Make-fil == Make-filer kan brukes til…</p>
<hr />
<div>== Finnes det noen big-endian maskiner jeg kan teste programmet mitt på? ==<br />
<br />
Ja, ''ulrik'' er en big-endian maskin. Logg inn med ssh ulrik<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
'''clean target'''<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
$ make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=46Hovedside2010-10-06T20:15:05Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[FAQ Oblig 1]]<br />
* [[FAQ Hjemmeeksamen 1]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]<br />
* [[Andre tips]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_Oblig_1&diff=40FAQ Oblig 12010-09-14T22:55:12Z<p>Bendiko@uio.no: Ny side: == Siste linje i filen printes fire ganger == Grunnen til dette er at hver struct har en peker til det samme minneområdet som innholder den siste linjen i filen.</p>
<hr />
<div>== Siste linje i filen printes fire ganger ==<br />
<br />
Grunnen til dette er at hver struct har en peker til det samme minneområdet som innholder den siste linjen i filen.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=39Hovedside2010-09-14T22:52:40Z<p>Bendiko@uio.no: /* Orakelside for INF1060 */</p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[FAQ Oblig 1]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Vanlige_feil_i_oblig_og_hjemmeeksamen&diff=37Vanlige feil i oblig og hjemmeeksamen2010-09-01T22:22:36Z<p>Bendiko@uio.no: </p>
<hr />
<div>Her er en kjapp oversikt over feil mange gjør i Oblig 1 og hjemmeeksamenene.<br />
<br />
== Innlevering av hjemmeeksamen inneholder navn på kandidaten ==<br />
<br />
Innleveringen skal være anonym, så skriv ikke «Hilsen ditt_navn» i readme, eller «author ditt_navn» i kildekoden. Slikt vil gi trekk!<br />
<br />
== Kopiere en string ==<br />
<br />
char *string1 = "Tullball";<br />
char *string2 = string1;<br />
printf("string1:%p\n", string1);<br />
printf("string2:%p\n", string2);<br />
<br />
Hvis du kjører koden ovenfor vil du se at de to variablene inneholder samme minneadresse. Det vil si at begge peker på samme sted i minnet, og følgelig samme data. Endringer i den ene vil føre til endringer i den andre.<br />
<br />
For å lage en kopi av en string må man sette av et nytt minneområde, og kopiere stringen over i denne.<br />
<br />
== Allokere plass til en string ==<br />
<br />
For å lagre en string må man ha plass i minnet, og det kan ordnes med malloc<br />
<br />
char *string = malloc(10);<br />
<br />
Det man så kan tro er at denne stringen nå har plass til 10 tegn. Det har den på et vis, men det siste tegnet må alltid være 0. Dette kalles null-byten, og er det som terminerer stringen slik at man kan vite hvor lang den er. I realiteten har derfor stringen kun plass til 9 bokstaver.<br />
<br />
==== Eksempel: ====<br />
<br />
strcpy(string, "0123456789");<br />
<br />
vil kopiere de 10 tegnene minneområde som er allokert, i tillegg til at den legger '\0' (0) på den ellevte plassen. Det betyr at den skriver over 1 byte i minnet som ikke er allokert. Resultatet er at programme kan kræsje.<br />
<br />
Les mer om null-byten<br />
<br />
== struct og nestepeker ==<br />
<br />
Vi har følgende struct:<br />
<br />
struct liste_elem {<br />
struct liste_elem *next;<br />
char *data;<br />
};<br />
<br />
Vi allokerer plass til en struct:<br />
<br />
struct liste_elem *e = malloc(sizeof(struct liste_elem));<br />
<br />
Vi har nå allokert plass i minnet, og adressen til dette minnet befinner seg i variabelen e. Når man allokerer plass vet man ikke hva minnet faktisk inneholder, så variablene neste og data kan inneholde hva som helst. Derfor er det viktig at man alltid gir dem en verdi. Spesielt neste-pekeren er det mange som glemmer:<br />
<br />
e->next = NULL;<br />
<br />
== Minnelekasje og feil bruk av minnet ==<br />
<br />
«Det er ingen feil i programmet, du ser jo at det kjører helt fint!» vil du kanskje svare. Men det er feil!<br />
<br />
Det er ikke kjøringen av programmet som avgjør om det inneholder feil, det er det koden din som gjør. C-programmer kan kjøre tilsynelatende fint i lang tid med minnefeil, men plutselig skjer det noe spesielt slik at programmet kræsjer. Det flere opplever er at programmet kjører fint, mens den som skal rette oppgaven ikke får kjørt programmet fordi det kræsjer. På hjemmeeksamen hjelper det ikke at programmet kjørte da du testet det. Hvis det ikke kjører når eksamensretter tester blir det trekk. Kjør programmet ditt med valgrind slik som forklart i [[Debugging]] for å avdekke minne-feil i programmet ditt. Når programmet avslutter vil du også få en oversikt over hvor mye minne som ikke ble frigjort før programmet avsluttet.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Vanlige_feil_i_oblig_og_hjemmeeksamen&diff=36Vanlige feil i oblig og hjemmeeksamen2010-09-01T22:21:48Z<p>Bendiko@uio.no: </p>
<hr />
<div>Vanlige feil i oblig og hjemmeeksamen<br />
<br />
Her er en kjapp oversikt over feil mange gjør i Oblig 1 og hjemmeeksamenene.<br />
<br />
== Innlevering av hjemmeeksamen inneholder navn på kandidaten ==<br />
<br />
Innleveringen skal være anonym, så skriv ikke «Hilsen ditt_navn» i readme, eller «author ditt_navn» i kildekoden. Slikt vil gi trekk!<br />
<br />
== Kopiere en string ==<br />
<br />
char *string1 = "Tullball";<br />
char *string2 = string1;<br />
printf("string1:%p\n", string1);<br />
printf("string2:%p\n", string2);<br />
<br />
Hvis du kjører koden ovenfor vil du se at de to variablene inneholder samme minneadresse. Det vil si at begge peker på samme sted i minnet, og følgelig samme data. Endringer i den ene vil føre til endringer i den andre.<br />
<br />
For å lage en kopi av en string må man sette av et nytt minneområde, og kopiere stringen over i denne.<br />
<br />
== Allokere plass til en string ==<br />
<br />
For å lagre en string må man ha plass i minnet, og det kan ordnes med malloc<br />
<br />
char *string = malloc(10);<br />
<br />
Det man så kan tro er at denne stringen nå har plass til 10 tegn. Det har den på et vis, men det siste tegnet må alltid være 0. Dette kalles null-byten, og er det som terminerer stringen slik at man kan vite hvor lang den er. I realiteten har derfor stringen kun plass til 9 bokstaver.<br />
<br />
==== Eksempel: ====<br />
<br />
strcpy(string, "0123456789");<br />
<br />
vil kopiere de 10 tegnene minneområde som er allokert, i tillegg til at den legger '\0' (0) på den ellevte plassen. Det betyr at den skriver over 1 byte i minnet som ikke er allokert. Resultatet er at programme kan kræsje.<br />
<br />
Les mer om null-byten<br />
<br />
== struct og nestepeker ==<br />
<br />
Vi har følgende struct:<br />
<br />
struct liste_elem {<br />
struct liste_elem *next;<br />
char *data;<br />
};<br />
<br />
Vi allokerer plass til en struct:<br />
<br />
struct liste_elem *e = malloc(sizeof(struct liste_elem));<br />
<br />
Vi har nå allokert plass i minnet, og adressen til dette minnet befinner seg i variabelen e. Når man allokerer plass vet man ikke hva minnet faktisk inneholder, så variablene neste og data kan inneholde hva som helst. Derfor er det viktig at man alltid gir dem en verdi. Spesielt neste-pekeren er det mange som glemmer:<br />
<br />
e->next = NULL;<br />
<br />
== Minnelekasje og feil bruk av minnet ==<br />
<br />
«Det er ingen feil i programmet, du ser jo at det kjører helt fint!» vil du kanskje svare. Men det er feil!<br />
<br />
Det er ikke kjøringen av programmet som avgjør om det inneholder feil, det er det koden din som gjør. C-programmer kan kjøre tilsynelatende fint i lang tid med minnefeil, men plutselig skjer det noe spesielt slik at programmet kræsjer. Det flere opplever er at programmet kjører fint, mens den som skal rette oppgaven ikke får kjørt programmet fordi det kræsjer. På hjemmeeksamen hjelper det ikke at programmet kjørte da du testet det. Hvis det ikke kjører når eksamensretter tester blir det trekk. Kjør programmet ditt med valgrind slik som forklart i [[Debugging]] for å avdekke minne-feil i programmet ditt. Når programmet avslutter vil du også få en oversikt over hvor mye minne som ikke ble frigjort før programmet avsluttet.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=35Hvordan skrive et godt program2010-09-01T22:16:26Z<p>Bendiko@uio.no: /* Kommentér paragrafer */</p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and return their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the to integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. <br />
// Negative values are set to zero. <br />
int i; <br />
int zero_count = 0; <br />
<br />
for (i = 0; i &lt; length; i++) { <br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
} <br />
} <br />
<br />
// Calculate the average of the positive numbers <br />
int average = 0; <br />
<br />
for (i = 0; i < length; i++) { <br />
average += array[i];<br />
} <br />
average = average / (length - zero_count);<br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
== Ikke legg all koden i main-metoden ==<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Srukturerer du programmet ditt skikkelig, blir veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
'''clean target'''<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
$ make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=34Hvordan skrive et godt program2010-09-01T22:12:56Z<p>Bendiko@uio.no: /* Dokumentér hver metode */</p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
Takes two integers as arguments and return their sum. <br />
- arg1: First integer <br />
- arg2: Second integer <br />
- return: The sum of the to integers <br />
*/<br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. // Negative values are set to zero. int i; int zero_count = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
if (array[i] &lt; 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
<br />
} <br />
<br />
// Calculate the average of the positive numbers int average = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
average += array[i];<br />
<br />
} average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
== Ikke legg all koden i main-metoden ==<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Srukturerer du programmet ditt skikkelig, blir veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
'''clean target'''<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
$ make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=33Hvordan skrive et godt program2010-09-01T22:11:30Z<p>Bendiko@uio.no: </p>
<hr />
<div>= Hvordan skrive et godt og ryddig program =<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
<br />
Takes two numbers as arguments and return their sum. <br />
- arg1: First number <br />
- arg2: Second number <br />
- return: The sum of the to numbers <br />
<br />
*/<br />
<br />
int add_numbers(int num1, int num2) { <br />
<br />
return num1 + num 2; <br />
<br />
} <br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. // Negative values are set to zero. int i; int zero_count = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
if (array[i] &lt; 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
<br />
} <br />
<br />
// Calculate the average of the positive numbers int average = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
average += array[i];<br />
<br />
} average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
== Ikke legg all koden i main-metoden ==<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
Srukturerer du programmet ditt skikkelig, blir veldig mye enklere å holde det ved like, samt å debugge når problemer oppstår. <br />
<br />
Når du strukturer bør du lage metoder med avgrensede oppgaver, og ikke la metoden gjøre andre oppgaver i tillegg.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
'''clean target'''<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
$ make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=32Hvordan skrive et godt program2010-09-01T22:05:48Z<p>Bendiko@uio.no: /* Don’t insult the reader’s intelligence */</p>
<hr />
<div>== Hvordan skrive et godt og ryddig program ==<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
<br />
Takes two numbers as arguments and return their sum. <br />
- arg1: First number <br />
- arg2: Second number <br />
- return: The sum of the to numbers <br />
<br />
*/<br />
<br />
int add_numbers(int num1, int num2) { <br />
<br />
return num1 + num 2; <br />
<br />
} <br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. // Negative values are set to zero. int i; int zero_count = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
if (array[i] &lt; 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
<br />
} <br />
<br />
// Calculate the average of the positive numbers int average = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
average += array[i];<br />
<br />
} average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) {// if a equals 5 <br />
counter = 0; // set the counter to zero<br />
} <br />
fclose(file); // Closing file descriptor <br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
Ikke legg all koden i main-metoden<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
clean target<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=31Hvordan skrive et godt program2010-09-01T22:04:01Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Hvordan skrive et godt og ryddig program ==<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
# Andre skjønner det ikke. <br />
# Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
<br />
Takes two numbers as arguments and return their sum. <br />
- arg1: First number <br />
- arg2: Second number <br />
- return: The sum of the to numbers <br />
<br />
*/<br />
<br />
int add_numbers(int num1, int num2) { <br />
<br />
return num1 + num 2; <br />
<br />
} <br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. // Negative values are set to zero. int i; int zero_count = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
if (array[i] &lt; 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
<br />
} <br />
<br />
// Calculate the average of the positive numbers int average = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
average += array[i];<br />
<br />
} average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) // if a equals 5 <br />
<br />
counter = 0; // set the counter to zero<br />
<br />
fclose(file); // Closing file descriptor <br />
<br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
Ikke legg all koden i main-metoden<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
clean target<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=30Hvordan skrive et godt program2010-09-01T22:02:34Z<p>Bendiko@uio.no: /* Kommentering */</p>
<hr />
<div>== Hvordan skrive et godt og ryddig program ==<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; <br />
<br />
#Andre skjønner det ikke. <br />
#Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller.<br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips: <br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør. <br />
<br />
/* <br />
<br />
Takes two numbers as arguments and return their sum. <br />
- arg1: First number <br />
- arg2: Second number <br />
- return: The sum of the to numbers <br />
<br />
*/<br />
<br />
int add_numbers(int num1, int num2) { <br />
<br />
return num1 + num 2; <br />
<br />
} <br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse. <br />
<br />
// Verify that all numbers are positive. // Negative values are set to zero. int i; int zero_count = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
if (array[i] &lt; 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
<br />
} <br />
<br />
// Calculate the average of the positive numbers int average = 0; for (i = 0; i &lt; length; i++) { <br />
<br />
average += array[i];<br />
<br />
} average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget. <br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter: <br />
<br />
if (a == 5) // if a equals 5 <br />
<br />
counter = 0; // set the counter to zero<br />
<br />
fclose(file); // Closing file descriptor <br />
<br />
// Output space printf("\n"); <br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
Ikke legg all koden i main-metoden<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
clean target<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hvordan_skrive_et_godt_program&diff=29Hvordan skrive et godt program2010-09-01T22:01:31Z<p>Bendiko@uio.no: /* Unngå tett kode */</p>
<hr />
<div>== Hvordan skrive et godt og ryddig program ==<br />
<br />
Det finnes utallige meninger om hvordan et godt C-program skal se ut, men enkelte retningslinjer er de fleste enige om.<br />
<br />
Her er en liste over viktige ting å huske på (i mer eller mindre tilfeldig rekkefølge)<br />
<br />
=== Unngå tett kode ===<br />
<br />
Mange skriver kode uten å bruke plass, dvs. tomme linjer for å skape naturlige avgrensninger mellom kodeblokker.<br />
<br />
Ha alltid minst én tom linje i følgende tilfeller:<br />
<br />
* Mellom metoder.<br />
* Mellom deklarasjoner av lokale variabler og den første “statement”-setningen i en metode.<br />
* Før en ny kode-blokk.<br />
* Mellom logiske oppdelinger av en metode.<br />
<br />
'''Kun et statement per linje'''<br />
<br />
Mange liker å bruke flere statements per linje:<br />
<br />
if (1 == 1) {return 1;} <br />
else {return 0;}<br />
<br />
Slik koding bidrar ikke til annet enn å gjøre programmet vanskeligere å lese. Det er med andre ord en uting.<br />
<br />
=== Kommentering ===<br />
<br />
Hvordan man skal kommentere kode er ikke lett å vite alltid, men her kommer en liste over nyttige tips. Mange tenker at "Nei, kommentere koden gidder jeg ikke for jeg skjønner jo hva som skjer." Det er to problemer med denne tankegangen; 1) Andre skjønner det ikke. 2) Det skal ikke mange dagene/ukene til før du ikke skjønner det du heller. <br />
<br />
Det er bare en ting å gjøre; lære seg å kommentere skikkelig, og her kommer noen tips:<br />
<br />
==== Dokumentér hver metode ====<br />
<br />
Hva er denne metodens oppgave? Beskrivelsen skal være så kort og konsis som mulig. Her skal også argumenter samt retur-verdi dokumenteres. Her er Java-doc-syntax helt fint hvis man foretrekker det. Formen på forklaringen skal ikke være "Jeg gjør slik og slik". Det skal forklares hva metoden gjør.<br />
<br />
/* <br />
Takes two numbers as arguments and return their sum. <br />
- arg1: First number <br />
- arg2: Second number <br />
- return: The sum of the to numbers <br />
*/ <br />
int add_numbers(int num1, int num2) { <br />
return num1 + num 2; <br />
}<br />
<br />
==== Kommentér paragrafer ====<br />
<br />
Del koden opp i logiske deler og kommenter disse.<br />
<br />
// Verify that all numbers are positive.<br />
// Negative values are set to zero.<br />
int i;<br />
int zero_count = 0;<br />
for (i = 0; i < length; i++) {<br />
if (array[i] < 0) {<br />
array[i] = 0;<br />
zero_count++;<br />
}<br />
}<br />
<br />
// Calculate the average of the positive numbers<br />
int average = 0;<br />
for (i = 0; i < length; i++) {<br />
average += array[i];<br />
}<br />
average = average / (length - zero_count); <br />
<br />
==== Kom til poenget! ====<br />
<br />
Ikke skriv mer enn det som er nødvendig for å forklare poenget.<br />
<br />
==== Don’t insult the reader’s intelligence ====<br />
<br />
Unngå å forklare selvfølgeligheter:<br />
<br />
if (a == 5) // if a equals 5<br />
counter = 0; // set the counter to zero<br />
<br />
fclose(file); // Closing file descriptor<br />
<br />
// Output space<br />
printf("\n");<br />
<br />
Det er bortkastet tid å skrive unødvendige kommentarer, og det gjør det vanskeligere å lese koden.<br />
<br />
=== Lesbar kode ===<br />
<br />
Det aller viktigste er å skrive kode som ikke trenger kommentering. Hvis man gir metoder og variabler fornuftige navn er det ofte ikke nødvendig å kommentere så mye. Kommentarer skal kun skrives når det er nødvendig, så jo mer selvforklarende koden er, jo færre kommentarer trengs.<br />
<br />
<br />
Ikke legg all koden i main-metoden<br />
<br />
En del legger veldig mye kode i main-metoden. main-metoden har kun en funksjon, og det er å starte programmet.<br />
<br />
Main bør kun inneholde logikk for å sjekke kommandolinjeparametre, samt kall på metoder som faktisk skal utføre oppgavene.<br />
<br />
<br />
== Lag en Make-fil ==<br />
<br />
Make-filer kan brukes til så mangt, og egner seg spesielt godt til å kompilere et program. Programmet make vil, når det kjøres, lete etter en fil ved navn Makefile i katalogen. I denne filen kan man definere metoder (kalt target) som kan kjøres.<br />
<br />
default:<br />
gcc program.c -o program<br />
<br />
Her har vi altså et target ved navn default. Ved å kjøre make, vil default kjøre kommandoen som kompilerer programmet. Det er mulig å definere flere kommandoer under hverandre.<br />
<br />
Hver kommando i make-filen må indenteres med tab.<br />
<br />
clean target<br />
<br />
Vi legger til et target for å slette den kompilerte filen samt backup-filene til Emacs.<br />
<br />
default:<br />
gcc program.c -o program<br />
clean:<br />
rm program *~<br />
<br />
For å kalle clean, kjører du følgende kommando:<br />
<br />
make clean</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=28FAQ C-programmering2010-09-01T21:58:27Z<p>Bendiko@uio.no: /* Filemeldinger ved kompilering */</p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
<br />
== Vanlige spørsmål ==<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med [http://en.wikipedia.org/wiki/Segmentation_fault Wikipedia]<br />
<br />
Les om hvordan du debugger dette på siden om [[debugging]].<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== "error: dereferencing pointer to incomplete type" ==== <br />
<br />
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.<br />
<br />
==== "implicit function declaration" ==== <br />
<br />
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.<br />
<br />
==== "assignment type mismatch" og "incompatible types in assignment" ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== "initialization makes pointer from integer without a cast" ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=27FAQ C-programmering2010-09-01T21:57:31Z<p>Bendiko@uio.no: /* Hva er segmentation fault? */</p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
<br />
== Vanlige spørsmål ==<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med [http://en.wikipedia.org/wiki/Segmentation_fault Wikipedia]<br />
<br />
Les om hvordan du debugger dette på siden om [[debugging]].<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== Hva betyr "error: dereferencing pointer to incomplete type"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "implicit function declaration"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "assignment type mismatch" og "incompatible types in assignment"? ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== Hva betyr "initialization makes pointer from integer without a cast"? ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=26FAQ C-programmering2010-09-01T21:54:48Z<p>Bendiko@uio.no: /* Vanlige spørsmål */</p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
<br />
== Vanlige spørsmål ==<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med Wikipedia<br />
<br />
Les om hvordan du debugger dette på siden om debugging.<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== Hva betyr "error: dereferencing pointer to incomplete type"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "implicit function declaration"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "assignment type mismatch" og "incompatible types in assignment"? ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== Hva betyr "initialization makes pointer from integer without a cast"? ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=25FAQ C-programmering2010-09-01T21:53:53Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
<br />
== Vanlige spørsmål ==<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med Wikipedia<br />
<br />
Les om hvordan du debugger dette på siden om debugging.<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== Hva betyr "error: dereferencing pointer to incomplete type"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "implicit function declaration"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "assignment type mismatch" og "incompatible types in assignment"? ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== Hva betyr "initialization makes pointer from integer without a cast"? ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=24FAQ C-programmering2010-09-01T21:52:14Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med Wikipedia<br />
<br />
Les om hvordan du debugger dette på siden om debugging.<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== Hva betyr "error: dereferencing pointer to incomplete type"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "implicit function declaration"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "assignment type mismatch" og "incompatible types in assignment"? ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== Hva betyr "initialization makes pointer from integer without a cast"? ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=FAQ_C-programmering&diff=23FAQ C-programmering2010-09-01T21:49:16Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Hvor finner jeg et API for C slik Java har? ==<br />
<br />
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.<br />
<br />
=== man-sider ===<br />
<br />
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<br />
<br />
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.<br />
<br />
'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'.<br />
<br />
== Filemeldinger under kjøring av programmer ==<br />
<br />
==== Hva er segmentation fault? ====<br />
<br />
Ulovlig lesing eller skriving til minnet. Les mer om segmention fault med Wikipedia<br />
<br />
Les om hvordan du debugger dette på siden om debugging.<br />
<br />
==== Hva er *** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0848d4f0 *** ==== <br />
<br />
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.<br />
<br />
<br />
== Filemeldinger ved kompilering ==<br />
<br />
==== Hva betyr "error: dereferencing pointer to incomplete type"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "implicit function declaration"? ==== <br />
<br />
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.<br />
<br />
==== Hva betyr "assignment type mismatch" og "incompatible types in assignment"? ==== <br />
<br />
Disse feilmeldingene kommer når du prøver å sette verdien av en peker til en variabel som ikke er en peker. F.eks. slik:<br />
<br />
double d = 1.0;<br />
int *i;<br />
i = d;<br />
<br />
==== Hva betyr "initialization makes pointer from integer without a cast"? ==== <br />
<br />
Denne feilmeldingen kommer når du prøver å gi en pekervariabel en verdi som ikke er en peker (f.eks. int *u = 10; ).<br />
<br />
==== <math.h> ==== <br />
Jeg prøver å bruke <math.h>, men får feilmeldingen "undefined reference to ....". Jeg har inkludert math.h så hva er galt?<br />
<br />
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.<br />
C-programmering<br />
<br />
==== Hvorfor viser ikke ''sizeof'' riktig størrelse på minneområdet? ==== <br />
<br />
char *mem = malloc(sizeof(struct Data))<br />
printf("Size:%d\n", sizeof(mem));<br />
<br />
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.<br />
<br />
==== Hvordan sammenligner jeg strukter? ==== <br />
<br />
Du må sammenligne hvert element i struktene, hver for seg.<br />
<br />
==== Jeg vil konvertere en int til en string med metoden ''itoa'', men funksjonen finnes ikke! ==== <br />
<br />
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)<br />
<br />
==== Hvordan finner jeg lengden på en string? ==== <br />
<br />
Lengden på en string finner du med metoden ''strlen''. En enkel og dum implementasjon av denne ser slik ut:<br />
<br />
/*<br />
* Looks for the first byte in the string containing 0 (zero). <br />
* The number of bytes preceding the zero is the length of the string.<br />
*/<br />
int strlen2(char *str) {<br />
int len = 0;<br />
<br />
while(*str != '\0') {<br />
len++;<br />
str++;<br />
}<br />
return len;<br />
}<br />
<br />
<br />
== Feilhåndtering i C-programmer ==<br />
<br />
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.<br />
<br />
'''errno'''<br />
<br />
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.<br />
<br />
Mange metoder i C-biblioteker bruker ''errno'', noen eksempler er ''fopen'', ''fclose'', ''read'', ''write''.<br />
<br />
* 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.<br />
* strerror tar errno-variabel som input og returnerer en string med feilmeldingen.<br />
<br />
'''Et eksempel på bruk av errno'''<br />
<br />
#include <stdio.h><br />
#include <stdlib.h><br />
#include <string.h><br />
#include <errno.h><br />
<br />
int main(void) {<br />
<br />
char *fname1 = "ikkeeksisterendefil.txt";<br />
FILE *fp = fopen(fname1, "r");<br />
<br />
if (fp == NULL) {<br />
// perror sjekker errno, og skriver ut filemelding til standard error.<br />
perror("ERROR");<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname1);<br />
} <br />
<br />
char *fname2 = "/etc/shadow";<br />
fp = fopen(fname2, "r");<br />
<br />
if (fp == NULL) {<br />
// strerror returnere en char-peker som skrives ut med printf.<br />
printf("ERROR opening %s. %s\n", fname2, strerror(errno));<br />
}<br />
else {<br />
printf("%s was opened successfully\n", fname2);<br />
}<br />
<br />
return 0;<br />
}</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=22Hovedside2010-09-01T21:47:15Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[FAQ C-programmering]]<br />
* [[Debugging]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=21Hovedside2010-09-01T21:46:59Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[C-basics]]<br />
* [[Debugging]]<br />
* [[FAQ C-programmering]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=C-basics&diff=20C-basics2010-09-01T21:46:29Z<p>Bendiko@uio.no: Ny side: == 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, …</p>
<hr />
<div>== Utskrift til skjerm ==<br />
<br />
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.<br />
<br />
printf("Dette skrives ut på skjermen\n");<br />
<br />
Denne stringen kalles format-stringen, og kan inneholde ulike tegn som angir hva slags argumenter som kommer senere:<br />
<br />
int tall = 10;<br />
printf("Dette er et tall:%d\n", tall);<br />
<br />
Her brukes %d for å angi at det kommer et argument etter format-stringen som i eksempelet overfor er et heltall.<br />
<br />
Det er ingen grense for hvor mange argumenter som kan angis.<br />
<br />
char *text = "Eksempel på et desimaltall:";<br />
float desimaltall = 3.14;<br />
int heltall = 10;<br />
printf("%s %f og et heltall i hex-format:%x\n", text, desimaltall, heltall); <br />
<br />
Merk at man må angi linjeskift selv med '\n'.<br />
<br />
Det er fullt mulig å kalle ''printf'' uten format-string slik:<br />
<br />
char *text = "Dette er en tekst";<br />
printf(text);<br />
<br />
...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!<br />
<br />
Mer informasjon finnes på man-siden til ''printf''.</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Debugging&diff=19Debugging2010-09-01T21:28:54Z<p>Bendiko@uio.no: </p>
<hr />
<div>=== Jeg skjønner ikke hva som skjer i programmet ===<br />
<br />
En vanlig måte å debugge på er å skrive ut verdiene av variablene i programmet med printf. Ofte er nemlig problemet at du ikke har peiling på hva variablene faktisk inneholder, og da hjelper det ikke å gjette, noe veldig mange gjør. Skriv ut verdien så er det ingen tvil! Legg gjerne inn 20 printf-kall hvis det er nødvendig. <br />
<br />
=== Utskriften kommer ikke alltid når jeg forventer det ===<br />
<br />
Grunnen til dette er ofte på grunn av at ''printf'' skriver til ''stdout'' (standard out) som buffrer før dataene skrives ut. Dvs. at utskriften ikke nødvendigvis kommer med en gang, men heller når det passer eller når nok data blir sendt til bufferet. Dette er veldig ofte merkbart hvis utskriften ikke inkluderer newline (\n) på slutten. <br />
<br />
For å unngå buffring, slik at man er sikker på at utskriften kommer med gang kan man skrive til stderr (standard error). Det kan gjøres med ''fprintf'' slik: <br />
<br />
fprintf(stderr, "%s\n", "Dette sendes til stderr, og buffres ikke\n");<br />
<br />
Les om mer standard streams <br />
<br />
=== Programmet kræsjer: Prøv valgrind ===<br />
<br />
Hvis programmet kræsjer har du garantert gjort noe galt. Dette vises ofte i form av ''segmentation fault''. Et triks er da å bruke programmet ''valgrind''. Når du normalt kjører programmet slik: <pre>$ ./a.out print tresmaa.txt</pre> kjører du det med valgrind slik: <pre>$ valgrind ./a.out print tresmaa.txt</pre>. <br />
<br />
For at ''valgrind'' skal skrive ut linjenummer i filen hvor det er problemer, må du huske å kompilere med opsjonen '''-g2''' eller '''-g3'''. <br />
''Valgrind'' gir en del output som kan virke i overkant mye, men ofte gir kun én feil flere feilbeskjeder. <br />
De vanligste feilmeldingene: <br />
<br />
* '''Invalid read of size X''' - Du leser X byte fra minnet som ikke er allokert. <br />
* '''Invalid write of size X''' - Du skriver til X byte i minnet som ikke er allokert. Dette skjer ofte hvis man allokerer til en streng slik: char *str = malloc(strlen(buf)), og glemmer at man må ha plass til null-byten på slutten, altså må man legge til 1. <br />
* '''Process terminating with default action of signal 11 (SIGSEGV)''' - Programmet ditt segger fordi du roter med minnet, f.eks. ved å bruke en ulovlig minnepeker. <br />
* '''Use of uninitialised value of size 4 og Conditional jump or move depends on uninitialised value(s)''' er resultatet av at man bruker variabler/pekere som ikke er initialisert til en verdi.<br />
<br />
=== Programmet kræsjer 2: Prøv GDB ===<br />
<br />
GDB er en mer avansert debugger som gir langt flere muligheter enn valgrind. Hvis valgrind ikke er til hjelp kan det være nødvendig å ta i bruk GDB. GDB gir blant annet muligheter til å steppe gjennom programmet for hver instruksjon, samt skrive ut verdier av variabler midt i kjøringen. <br />
<br />
[http://www.google.no/search?q=gdb+quick+guide Søk etter en guick guide for GDB]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Debugging&diff=18Debugging2010-09-01T21:27:30Z<p>Bendiko@uio.no: </p>
<hr />
<div>=== Jeg skjønner ikke hva som skjer i programmet ===<br />
<br />
En vanlig måte å debugge på er å skrive ut verdiene av variablene i programmet med printf. Ofte er nemlig problemet at du ikke har peiling på hva variablene faktisk inneholder, og da hjelper det ikke å gjette, noe veldig mange gjør. Skriv ut verdien så er det ingen tvil! Legg gjerne inn 20 printf-kall hvis det er nødvendig. <br />
<br />
=== Utskriften kommer ikke alltid når jeg forventer det ===<br />
<br />
Grunnen til dette er ofte på grunn av at printf skriver til stdout (standard out) som buffrer før dataene skrives ut. Dvs. at utskriften ikke nødvendigvis kommer med en gang, men heller når det passer eller når nok data blir sendt til bufferet. Dette er veldig ofte merkbart hvis utskriften ikke inkluderer newline (\n) på slutten. <br />
<br />
For å unngå buffring, slik at man er sikker på at utskriften kommer med gang kan man skrive til stderr (standard error). Det kan gjøres med fprintf slik: <br />
<br />
fprintf(stderr, "%s\n", "Dette sendes til stderr, og buffres ikke\n");<br />
<br />
Les om mer standard streams <br />
<br />
=== Programmet kræsjer: Prøv valgrind ===<br />
<br />
Hvis programmet kræsjer har du garantert gjort noe galt. Dette vises ofte i form av ''segmentation fault''. Et triks er da å bruke programmet ''valgrind''. Når du normalt kjører programmet slik: <pre>$ ./a.out print tresmaa.txt</pre> kjører du det med valgrind slik: <pre>$ valgrind ./a.out print tresmaa.txt</pre>. <br />
<br />
For at ''valgrind'' skal skrive ut linjenummer i filen hvor det er problemer, må du huske å kompilere med opsjonen '''-g2''' eller '''-g3'''. <br />
''Valgrind'' gir en del output som kan virke i overkant mye, men ofte gir kun én feil flere feilbeskjeder. <br />
De vanligste feilmeldingene: <br />
<br />
* '''Invalid read of size X''' - Du leser X byte fra minnet som ikke er allokert. <br />
* '''Invalid write of size X''' - Du skriver til X byte i minnet som ikke er allokert. Dette skjer ofte hvis man allokerer til en streng slik: char *str = malloc(strlen(buf)), og glemmer at man må ha plass til null-byten på slutten, altså må man legge til 1. <br />
* '''Process terminating with default action of signal 11 (SIGSEGV)''' - Programmet ditt segger fordi du roter med minnet, f.eks. ved å bruke en ulovlig minnepeker. <br />
* '''Use of uninitialised value of size 4 og Conditional jump or move depends on uninitialised value(s)''' er resultatet av at man bruker variabler/pekere som ikke er initialisert til en verdi.<br />
<br />
=== Programmet kræsjer 2: Prøv GDB ===<br />
<br />
GDB er en mer avansert debugger som gir langt flere muligheter enn valgrind. Hvis valgrind ikke er til hjelp kan det være nødvendig å ta i bruk GDB. GDB gir blant annet muligheter til å steppe gjennom programmet for hver instruksjon, samt skrive ut verdier av variabler midt i kjøringen. <br />
<br />
[http://www.google.no/search?q=gdb+quick+guide Søk etter en guick guide for GDB]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Debugging&diff=17Debugging2010-09-01T21:20:09Z<p>Bendiko@uio.no: </p>
<hr />
<div>=== Jeg skjønner ikke hva som skjer i programmet ===<br />
<br />
En vanlig måte å debugge på er å skrive ut verdiene av variablene i programmet med printf. Ofte er nemlig problemet at du ikke har peiling på hva variablene faktisk inneholder, og da hjelper det ikke å gjette, noe veldig mange gjør. Skriv ut verdien så er det ingen tvil! Legg gjerne inn 20 printf-kall hvis det er nødvendig. <br />
<br />
=== Utskriften kommer ikke alltid når jeg forventer det ===<br />
<br />
Grunnen til dette er ofte på grunn av at printf skriver til stdout (standard out) som buffrer før dataene skrives ut. Dvs. at utskriften ikke nødvendigvis kommer med en gang, men heller når det passer eller når nok data blir sendt til bufferet. Dette er veldig ofte merkbart hvis utskriften ikke inkluderer newline (\n) på slutten. <br />
<br />
For å unngå buffring, slik at man er sikker på at utskriften kommer med gang kan man skrive til stderr (standard error). Det kan gjøres med fprintf slik: <br />
<br />
fprintf(stderr, "%s\n", "Dette sendes til stderr, og buffres ikke\n");<br />
<br />
Les om mer standard streams <br />
<br />
=== Programmet kræsjer: Prøv valgrind ===<br />
<br />
Hvis programmet kræsjer har du garantert gjort noe galt. Dette vises ofte i form av segmentation fault. Et triks er da å bruke programmet valgrind. Når du normalt kjører programmet slik: "./a.out print tresmaa.txt" kjører du det med valgrind slik: "valgrind ./a.out print tresmaa.txt". <br />
<br />
For at valgrind skal skrive ut linjenummer i filen hvor det er problemer, må du huske å kompilere med opsjonen -g2 eller -g3. <br />
<br />
Valgrind gir en del output som kan virke i overkant mye, men ofte gir kun én feil flere feilbeskjeder. <br />
<br />
De vanligste feilmeldingene: <br />
<br />
*Invalid read of size X - Du leser X byte fra minnet som ikke er allokert. <br />
*Invalid write of size X - Du skriver til X byte i minnet som ikke er allokert. Dette skjer ofte hvis man allokerer til en streng slik: char *str = malloc(strlen(buf)), og glemmer at man må ha plass til null-byten på slutten, altså må man legge til 1. <br />
*Process terminating with default action of signal 11 (SIGSEGV) - Programmet ditt segger. <br />
*Use of uninitialised value of size 4 og Conditional jump or move depends on uninitialised value(s) er resultatet av at man bruker variabler/pekere som ikke er initalisert til en verdi.<br />
<br />
=== Programmet kræsjer 2: Prøv GDB ===<br />
<br />
GDB er en mer avansert debugger som gir langt flere muligheter enn valgrind. Hvis valgrind ikke er til hjelp kan det være nødvendig å ta i bruk GDB. GDB gir blant annet muligheter til å steppe gjennom programmet for hver instruksjon, samt skrive ut verdier av variabler midt i kjøringen. <br />
<br />
[http://www.google.no/search?q=gdb+quick+guide Søk etter en guick guide for GDB]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=16Hovedside2010-08-30T13:58:49Z<p>Bendiko@uio.no: /* Orakelside for INF1060 */</p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
* [[Debugging]]<br />
* [[FAQ C-programmering]]<br />
* [[Hvordan skrive et godt program]]<br />
* [[Vanlige feil i oblig og hjemmeeksamen]]</div>Bendiko@uio.nohttps://wiki.uio.no/mn/ifi/INF1060/index.php?title=Hovedside&diff=15Hovedside2010-08-30T13:58:19Z<p>Bendiko@uio.no: </p>
<hr />
<div>== Orakelside for INF1060 ==<br />
<br />
På denne siden vil du finne hjelp og tips til oblig og hjemmeeksamen iINF1060.<br />
<br />
[[Debugging]]<br />
<br />
[[FAQ C-programmering]]<br />
<br />
[[Hvordan skrive et godt program]]<br />
<br />
[[Vanlige feil i oblig og hjemmeeksamen]]</div>Bendiko@uio.no