Rättningsmall DD2387 oktober 2008 Tal 1 lösningsförslag
01 void remove(LinkedList<T> *& p, T data) { 02 if (p != 0) {
03 if (data == p->data) {
04 LinkedList<T> * tmp = p;
05 p = p->next;
06 delete tmp;
07 remove(p, data);
08 } else {
09 remove(p->next, data);
10 } 11 } 12 }
Det går att lösa på annat sätt utan att utnyttja att p är referensdeklarerad, funktionen måste då returnera en pekare och nextpekaren sättas lika med det returnerade värdet. Det är fel att anta att remove ligger som medlemsfunktion i en klass och definiera införa egna medlemsvariabler.
FEL:
1-9-30 Missat typdeklarera listan kontrollera:
rad 01 LinkedList<T> *& p p rad 04 LinkedList<T> * tmp
1-9-50 saknas rekursivt anrop 1-9-51 felaktigt rekursivt anrop
1-9-51 Ingen else-sats med rekursivt anrop
rad 09 remove(p->next, data);
1-9-52 Buggigt rekursivt anrop (kraschar om man tagit bort sista elementet) rad 07 remove(p.next) istället för remove(p);
1-9-53 Missat kontrollera tomma listan rad 02 if (p != 0) {
1-9-54 Felaktig borttagning, t.ex. tar bort utan temporär variabel 1-1-54 Felaktig borttagning, t.ex. stavar fel på tmp vid delete rad 04 LinkedList<T> * tmp = p;
rad 05 p = p->next;
rad 06 delete tmp;
1-5-99 annat fel, okänt hur allvarligt 1-1-99 annat litet
1-9-99 annat allvarligt fel
Tal 2
Det här är en variant på tentatal där klasser hanterar dynamiskt minne där jag brukar fråga efter copy- konstruktor, operator= och destructor.
Koden är medvetet svårtytt skriven. Pekaren current pekar på nästa lediga element att stoppa in ett värdet på. I funktionen pop blir namnet current förvillande eftersom man inledningsvis tror att den pekar på nästa värde att returnera.
2a)
lösningsförslag: operator= och copy-konstruktor
Destruktorn behöver inte nämnas och det är inte fel att nämna den. Defaultkonstruktorn finns redan och ska inte nämnas. Man behöver inte precisera med parametrar och åtkomst.
FEL:
2-9-40 operator= och/eller copy-konstruktor saknas 2-1-41 defaultkonstruktorn nämns
2b)
Lösningsförslag: Stack-klassen har en intern pekare current som kommer att peka på fel minne när Stack-klassen kopieras eller tilldelas. När man använder kopian kommer man att skriva/läsa i fel minne.
FEL:
Icke allvarligt fel är att påstå att mp också kommer att peka fel. Det är fel att påstå det, mp är en array som kommer att kopieras värde för värde.
Det är inte fel att nämna att nrItems också kommer att kopieras
2-9-70 missa att pekaren current kopieras och pekar på fel minne
2-9-50 oprecist svar: enbart säga att en pekare kopieras utan att reflektera över följderna 2-9-51 oprecist svar: säger att en pekare pekar på fel minne utan att precisera vilken pekare 2-1-72 svarar rätt men tillägger att m_p också pekar på fel minne
2-1-19 påstå max kopieras, max är statisk och kopieras inte 2c)
Det intressanta i det här talet är att argumentet s inte ska vara const-deklarerad vilken den normalt brukar vara. Det går att lösa uppgiften genom att manipulera pekarna. Det kan vara svårt att rätta.
Lösningsförslag:
void operator=(Stack<T> & s) {
nrItems = 0; // initialisera som current = mp; // defaulkonsstruktorn
Stack(Stack<T> & s) : nrItems(0),
current(mp) {
put(s.pop());
put(s.pop());
} put(s.pop());
put(s.pop());
}
FEL:
2-9-11 Allvarligt fel att const-deklarera s.
void operator=(const Stack<T> & s) { 2-1-50 litet fel om koden nästan gör rätt.
2-9-51 fel om koden inte gör vad den ska 2-5-99 oförutsett fel
Tal 3
Kommentar till talet: Eftersom index()-metoderna i lösningen inte är virtual får man olika resultat med referenserna även om de refererar till samma instans. Man har fog att tycka att det är dålig
objektorienterad programmering eftersom man inte uppfyller "is a " relationen.
En alternativ lösning är att ha en medlemsvariabel som ändras vid varje anrop och dessutom påverkar resultatet.
Lösningsförslag:
01 struct OldWay { 02 float index() { 03 return 3.7;
04 } 05 };
06
07 struct NewDeal : OldWay { FEL
3-9-20 virtual deklarerade metoder, koden skriver inte ut why 3-9-50 Logiskt fel. Koden skriver inte ut WHY
3-9-15 Koden deklarerad private så att exemplet inte fungerar 3-9-16 inget arv
3-5-99 oförutsett fel
08 float index() { 09 return 5.6;
10 } 11 };
Tal 4
Lösningsförslag:
struct Bank {
bool nogood() const {return true};
FEL
4-9-10 Allvarligt fel om Banks metoder inte är const-deklarerade 4-9-40 Allvarligt fel om operator[] inte returnerar en
referens (l-value)
4-9-50 Allvarligt fel om operator[] och in_depth returtyper inte matchar
4-9-51 Allvarligt fel om operator[]-argumentet inte tar en typ man kan göra ++ på.
4-5-99 oförutsett fel int in_depth() const {return 4;};
};
struct State { int next;
int & operator[](int & x) { return next;
} };
Tal 5a
FEL:
5-9-30 Fel om koden inte kompilerar 5-9-31 Fel om koden inte fungerar 5-5-99 oförutsett fel
Lösningsförslag
const & T max(const T & x, const T & y) { if (x < y) return y;
else return x;
} // alternativ till if-sats return x < y ? y : x;
Det spelar ingen roll om man skickar/returnerar kopia i 5a) men det måste motiveras i 5c)
5b)
Lösningen kräver operator<
Det går att implementera med operator> operator<= operator>=
Även metoder (less, greater_...) godkänns om man är konsekvent i a och b
5-9-32 Fel om man inte identiferar krav på typparametern.
5-5-99 oförutsett fel
5c)
Det är mer användbart att returnera en referens. T.ex. när man vill förändra det största av två objekt.
Returnerar man en kopia så förändrar man kopian.
En någorlunda vettig förklaring på att man returnerar en kopia är också godkänd.
5-1-33 Fel är att inte inse att man har ett val att returnera en kopia eller en referens.
5-1-34 Fel om man returnerar något helt annat.
5-1-60 Otydligt svar 5-5-99 oförutsett fel
5d)
Lösningsförslag: Man kan bara deklarera en och endast en returtyp
FEL
5-9-90 Alla andra svar.
5-5-60 Otydligt svar - kanske rätt.
6
FEL
6-9-20 Grovt fel om utskriften fel.
6-1-91 Missat endl svarat c a d e d c a
d e d
Mellanslag räknas inte som fel.