Tentamen *:58/ID100V Programmering i C Exempel 3

DSV
Jozef Swiatycki
Tentamen *:58/ID100V
Sid 1(5)
Exempel 3
Tentamen *:58/ID100V Programmering i C Exempel 3
Denna tentamen består av fyra uppgifter som tillsammans kan de ge maximalt 22 poäng.
För godkänt resultat krävs minst 14 poäng , för VG krävs minst 18 poäng.
För KTH-studenter tillämpas A/B/C/D/E/F-skalan enligt betygskriterier på kursens
webbsida.
Observera:
- skriv tydligt, oläsbar lösning medför 0 poäng
- börja varje uppgift på nytt blad
- skriv endast på ena sidan av pappret
- skriv namn på varje inlämnat blad
- redovisa eventuella antaganden (som givetvis inte får strida mot uppgiftstexten)
- tänk på att det kan passa dig bättre att lösa uppgifterna i annan ordning
Tillåtna hjälpmedel:
- valfria medhavda böcker om programmering i C
- medhavt häfte med kopior av föreläsningsbilder
LYCKA TILL !
DSV
Jozef Swiatycki
Tentamen *:58/ID100V
Sid 2
Exempel 3
Uppgift 1 (Sammanlagt 6 poäng)
Denna uppgift består av tre deluppgifter som vardera ger två poäng. Varje uppgift består
av en liten C-programsnutt behäftat med ett fel samt en beskrivning av programsnuttens
felaktiga beteende. Din uppgift är att I) ange vad felet är och II) ange hur felet skall
rättas. Obs! att du för att få poängen skall rätta just detta fel, en omskrivning av
programmet med andra konstruktioner duger inte. Obs! vidare att det i vissa fall kan
krävas små ändringar på flera ställen i programsnutten för att rätta ett fel.
Samtliga fel är av "klassisk" karaktär, som det varnats för i undervisningen och/eller i
litteraturen. Det är inte fråga om syntaxfel, utan om felaktigheter som gör att programmet
inte beter sig som det skall eller får exekveringsavbrott.
a) Följande funktion är tänkt att kopiera en fil till en annan:
#include <stdio.h>
void copyfile(FILE *inf, FILE *outf){
char c;
while ((c=getc(inf))!=EOF)
putc(c, outf);
}
Funktionen har testats på flera system, på vissa går den in i en oändlig loop, på andra
slutar den för tidigt vid kopiering av binärfiler.
b) I följande program verkar det vara något fel på funktionen geVarden(). Funktionen
skall fylla posten den får som argument med värden som den också får som argument,
men den verkar inte åstadkomma någon förändring
typedef struct _post{
char *namn;
int data;
} Post;
void geVarden(Post p, char *n, int d){
p.namn=n;
p.data=d;
}
int main(void){
Post pst;
geVarden(pst, "Jozef", 53);
printf("%s %d\n", pst.namn, pst.data);
return 0;
}
Deluppgift c) på nästa sida!
DSV
Jozef Swiatycki
c)
Tentamen *:58/ID100V
Sid 3
Exempel 3
Funktionen getstr() nedan skall användas för inläsning av strängar från stdin.
Satserna i funktionen följer ett välkänt mönster och är inte felaktiga. Funktionen
verkar fungera i mycket små testprogram, men vid användning i lite mer komplexa
program verkar den inlästa strängen blir förstörd på något sätt.
#include <stdio.h>
#include <string.h>
char *getstr(int max){
char buff[100];
char *cpek;
fgets(buff, max, stdin);
if (cpek=strchr(buff, '\n'))
*cpek='\0';
else
while(getchar()!='\n')
;
return buff;
}
Uppgift 2 (Variabla argumentlistor - 2 poäng)
Skriv funktionen char *strconc(char *dest, ...); som kan konkatenera ett
godtyckligt antal strängar som den får som argument. Det sista argumentvärdet vid ett
anrop till strconc skall vara NULL för att markera att argumenlistan är slut. Strängarna
skall konkateneras i utrymmet dest. Det är anroparens ansvar att se till att dest kan
rymma alla dessa konkatenerade strängar.
strconc skall returnera dest.
Exempel på anrop:
strconc(buff, "Detta ", "var ", "lätt", NULL);
Efter detta anrop skall buff innehålla strängen "Detta var lätt".
Uppgift 3 (Otypat minne - 2 poäng)
Skriv funktionen
void *memmem(void *ptr1, void *ptr2, size_t n1, size_t n2);
Denna funktion skall fungera på godtyckliga minnesareor på samma sätt som funktionen
strstr() fungerar på strängar: den skall gå igenom arean som pekas ut av ptr1 och är
n1 bytes stor och den skall söka där efter en byteföljd som är lika med den byteföljd som
finns i arean som pekas ut av ptr2 och är n2 bytes stor.
memmem() skall returnera en pekare till den första påträffade förekomsten av denna
byteföljd, eller NULL om ingen sådan förekomst påträffas.
DSV
Jozef Swiatycki
Tentamen *:58/ID100V
Sid 4
Exempel 3
Uppgift 4 (Generella moduler, dynamiska arrayer, funktionspekare - 12 poäng)
Denna uppgift handlar om att skriva (delar av) en återanvändbar modul som skall
definiera datastrukturen Arrayset för representation av mängder av element av
godtyckliga typer, samt visa vad en tillämpning behöver göra för att kunna använda
modulen. Till skillnad från inlämningsuppgift 3 skall denna datastruktur kunna hantera
godtyckliga data. Detta innebär att den bör implementeras med pekare till de data som
stoppas in i mängden.
En mängd är ju en datastruktur där det inte förekommer dubletter. T.ex. ska funktionen
add() nedan inte förändra mängden om det i mängden redan finns ett element som är
lika med det nya element som tillämpningen försöker addera. Men eftersom modulen
ska kunna hantera element av godtyckliga typer så är det upp till tillämpningen att
bestämma vad ”lika med” betyder för dess objekt.
Internt ska Arrayset (som själva namnet visar) vara implementerad som en
omallokerbar array av pekare till tillämpningsobjekt. Du behöver inte ta hänsyn till
några effektivitetsaspekter.
a) Skriv modulen arrayset.c. Modulen beskrivs av nedanstående ofullständiga
headerfil arrayset.h, där argumenten till funktionerna initset() och removeset()
saknas - du ska själv bestämma vilka de ska vara.
#ifndef ARRAYSET
#define ARRAYSET
typedef struct arrstruct *Arrayset;
Arrayset initset(???????????);
int addset(Arrayset s, void *new);
void removeset(Arrayset s, ???????????);
#endif
• initset() ska skapa, initiera och returnera en Arrayset
• addset() ska stoppa in elementet new i Arrayset:et s om det inte redan finns ett
element som är ”lika med” new i s. Returnerar 1 vid lyckad operation, 0 annars.
• removeset() ska ta bort från Arrayset:et s alla element som uppfyller något villkor
som tillämpningen anger. Du måste alltså komma på ett sätt för en tillämpning att ange ett
villkor så att removeset() kan testa om elementen uppfyller villkoret. Du måste också
se till att man kan förhindra att minnesläckage uppstår vid denna operation. Titta gärna på
uppgift b) när du bestämmer hur argumenten till removeset ()ska se ut.
Uppgift b) finns på nästa sida!
DSV
Jozef Swiatycki
Tentamen *:58/ID100V
Sid 5
Exempel 3
b) Antag en tillämpning där man hanterar namn mha följande struct:
typedef struct name{
char *firstname;
char *lastname;
} Name;
Objekt av denna typ skapas med följande funktion:
Name *makename(char *fn, char *ln){
Name *tmp = malloc(sizeof(Name));
tmp->firstname = malloc(strlen(fn)+1);
strcpy(tmp->firstname, fn);
tmp->lastname = malloc(strlen(ln)+1);
strcpy(tmp->lastname, ln);
return tmp;
} /* makename */
Två Name-objekt är lika om resp. firstname och lastname i båda har samma strängvärde.
Komplettera följande program med vad som behövs för att det ska kunna använda
Arrayset på sina namn :
#include ”arrayset.h”
int main(void){
Arrayset namn = initset(???????????);
addset(namn, makename("john", "grisham"));
addset(namn, makename("ken", "follet"));
addset(namn, makename("mike", "palmer"));
addset(namn, makename("james", "follet"));
addset(namn, makename("mike", "ridpath"));
removeset(namn, ???? /* de som heter "john" i förnamn */);
removeset(namn, ???? /* de som heter "mike" i förnamn */);
return 0;
}