Α.Μ. ΒΑΘΜΟΣ ΣΧΟΛΙΑ Δεν κάνει compile και το λάθος είναι σηµαντικό: Το head1 είναι δείκτης σε struct, εποµένως η προσπέλαση πεδίου γίνεται 321 FAIL µε head1->next και όχι head1.next. Επιπλέον, έχετε λάθος και στη λογική. Θέλουµε να κάνουµε το newlist->prev ίσο µε head2 κι όχι το newlist ίσο µε head1->prev. Μετά, θέλουµε το head2->next να γίνει newlist. Τέλος, πρέπει να συνδέσουµε το head1 µε το head2 1349 Όλα οκ, εκτός από την τιµή που επιστρέφει η συνάρτηση. Το curr είναι η οριακό κεφαλή της επιµέρους λίστας που επιστρέφει η αναδροµική κλήση. PASS Η σωστή κεφαλή της λίστας που κατασκευάζετε είναι το head 1482 PASS main : Η recinterleave επιστρέφει την κεφαλή της νέας λίστας που κατασκευάστηκε. Πρέπει να αποθηκεύετε το αποτέλεσµά της στο head. Με τον τρόπο που γίνεται το interleave, θα δουλέψει και όπως το έχετε τώρα, αλλά το πιο σωστό είναι να χρησιµοποιείτε αυτό που σας επιστρέφει (γιατί δεν υπάρχει καµία εγγύηση ότι η συνάρτηση θα έχει υλοποιηθεί µε τέτοιο τρόπο ώστε η κεφαλή να µείνει ίδια. Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούσαν τη δεύτερη λίστα τώρα πια έχουν προστεθεί στην πρώτη. Το παλιό head2 είναι το επόµενο στοιχείο του head εποµένως έχει ήδη σβηστεί από την πρώτη clearlist. Σωστή, και µπράβο που µεριµνήσατε για λίστες διαφορετικών µεγεθών. 1556 PASS 1559 PASS Πολύ σωστή η υλοποίηση και κλήση της συνάρτησης, αλλά θα έπρεπε να έχετε και το prototype της πάνω από τη main. Σωστή, µπράβο. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Δεν κάνει compile. Καλή αρχή, αλλά το πιο σηµαντικό λάθος είναι ότι δεν αποθηκεύετε σε µεταβλητή το αποτέλεσµα της recstrlen κατά την αναδροµική κλήση. Σωστή γενικά, αλλά θα πετάξει segmentation fault αν η λίστα είναι αρχικά άδεια. Γιατί χρησιµοποιείτε (*newnode).data και όχι newnode->data όπως στα υπόλοιπα σηµεία? Επίσης, έπρεπε να αρχικοποιείτε το newnode->prev σε NULL. Δεν κάνει compile, λίγος κώδικας. Page 1
Εξαιρετική δουλειά, µπράβο! 1562 PASS 1563 PASS 1565 PASS 1566 PASS Πολύ καλή δουλειά. Αντί για &string[1] θα µπορούσατε να είχατε γράψει string+1 και αντί για string[0] θα µπορούσατε να είχατε *string. Καθαρά θέµα στυλ: διατήρηση της σύνταξης δεικτών µια και έτσι είναι και το υπόλοιπο πρόγραµµα. Σωστή αλλά στην περίπτωση που το head->prev είναι NULL ξεχνάτε να το κάνετε ίσο µε curr. Σε αυτό οφείλεται το ότι "χάνεται" ένας κόµβος όταν εκτυπώνετε τη λίστα ανάποδα. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Σωστή, µπράβο. Σωστή, µπράβο. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Δεν αρχικοποιείτε το plithos, οπότε όταν το string[0] είναι '\0' επιστρέφει σκουπίδια και τελικά δε βγαίνουν σωστά αποτελέσµατα. Το πρώτο if δε χρειαζόταν, αρκούσε σε εκείνο το σηµείο να γράψετε plithos = 0; Αν µετά µπει στο if (string[0]=='\0') θα επιστρέψει τη σωστή τιµή (0), κι αν δε µπει, θα έχει τη σωστή τιµή για τους επόµενους υπολογισµούς. Όλα οκ στη σύνδεση, εκτός από τη γραµµή head2->prev=head; που είναι λάθος κι έπρεπε να αφαιρεθεί. Η παράµετρος string έπρεπε να είναι δηλωµένη ως char * γιατί είναι string. Η συνάρτηση δεν υλοποιήθηκε. Page 2
1568 FAIL 1570 PASS Sheet2 Αν το newnode είναι NULL, δεν έχει νόηµα να το κάνεις free. Στην περίπτωση που αποτυγχάνει το malloc, θα ήταν καλό ή να αποδεσµεύεις όλη τη λίστα ή να επιστρέφεις την κεφαλή της χωρίς να έχει γίνει το cloning Το newnode έπρεπε να προστίθεται πριν το head, αλλά το προσθέτεις µετά. Το base case είναι λάθος. Αν το head είναι NULL δεν πρέπει να τερµατίζει το πρόγραµµα,αλλά να επιστρέφεις NULL (τότε η αναδροµή αρχίζει να "γυρίζει πίσω" αφού φτάσαµε στη µικρότερη δυνατή λίστα) Αν το group είναι NULL, το group->next θα κάνει segfault. Χρειαζόταν έλεγχος γι αυτό. Το newnode->next->next = NULL έχει ως αποτέλεσµα να χαθεί το κοµµάτι της λίστας που ξεκινά στο newnode->next->next Επίσης, θα µπορούσες να είχες εκµεταλλευτεί την ύπαρξη της addtofront Σωστή εκτός από τον αρχικό έλεγχο. Έπρεπε να ελέγχετε αν το curr2 είνα NULL, κι όχι το curr2->next. Σε αυτό το λάθος οφείλετε το ότι χάνετε ένα κόµβο στο τέλος (ο τελευταίος κόµβος κάθε λίστας δεν εισάγεται στην τελική) 1571 οριακό PASS. main: Η συνάρτηση recduplicate επιστρέφει την κεφαλή της λίστας που κατασκευάζει. Έπρεπε να αποθηκεύετε την τιµή που επιστρέφει στη µεταβλητή head. Με τον τρόπο που το κάνατε, χάνεται ο πρώτος κόµβος της νέας λίστας. Λειτουργεί σωστά αλλά έχετε κάποια λαθάκια και το πρόγραµµα δεν είναι πολύ καλογραµµένο. Κατ'αρχήν είναι λάθος να δεσµεύετε µνήµη για το curr. Πρόκειται να το χρησιµοποιήσετε για να αποθηκεύσετε ένα δείκτη σε ήδη δεσµευµένη µνήµη, όχι για κάτι καινούργιο. Στον έλεγχο που κάνετε µετά από malloc, αν πχ το new είναι NULL, τότε δεν έχει νόηµα να το κάνετε free - αφού απέτυχε η δέσµευση µνήµης γι αυτό. Ο πιο πολύς κώδικας που έχετε στο if και στο else είναι ακριβώς ο ίδιος. Θα ήταν πολύ πιο κατανοητό το πρόγραµµα αν τα κοινά κοµµάτια ήταν έξω από το if/else (αφού εκτελούνται σε κάθε περίπτωση). Αρκετά άσχηµη στοίχιση. Page 3
1573 οριακό PASS Sheet2 Όλα οκ στη σύνδεση, αλλά χαλάτε τη λίστα στο τέλος. Αντί για komvos = head έπρεπε να είχατε head = komvos. Έτσι όπως το κάνατε τώρα, επιστρέφετε το δεύτερο κόµβο κι όχι τον πρώτο. Στην περίπτωση που αποτυγχάνει το malloc, θα ήταν καλό ή να αποδεσµεύετε τη λίστα ή να επιστρέφετε την κεφαλή της χωρίς να έχει γίνει το cloning. Επίσης, θα µπορούσατε να είχατε εκµεταλλευτεί την ύπαρξη της addtofront 1577 PASS Σωστή, µπράβο. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. 1579 οριακό PASS Δεν κάνει compile. Καλή αρχή, αλλά το πιο σηµαντικό λάθος είναι ότι δεν αποθηκεύετε σε µεταβλητή το αποτέλεσµα της recstrlen κατά την αναδροµική κλήση. Όλα οκ στη σύνδεση, αλλά χαλάτε τη λίστα στο τέλος. Αντί για komvos = head έπρεπε να είχατε head = komvos. Έτσι όπως το κάνατε τώρα, επιστρέφετε το δεύτερο κόµβο κι όχι τον πρώτο. Στην περίπτωση που αποτυγχάνει το malloc, θα ήταν καλό ή να αποδεσµεύετε τη λίστα ή να επιστρέφετε την κεφαλή της χωρίς να έχει γίνει το cloning. Επίσης, θα µπορούσατε να είχατε εκµεταλλευτεί την ύπαρξη της addtofront 1587 PASS σωστή Page 4
1602 PASS 1607 PASS 1608 PASS 1609 PASS Sheet2 Σωστή, µπράβο. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Δεν αρχικοποιείτε το plithos, οπότε όταν το string[0] είναι '\0' επιστρέφει σκουπίδια και τελικά δε βγαίνουν σωστά αποτελέσµατα. Το πρώτο if δε χρειαζόταν, αρκούσε σε εκείνο το σηµείο να γράψετε plithos = 0; Αν µετά µπει στο if (string[0]=='\0') θα επιστρέψει τη σωστή τιµή (0), κι αν δε µπει, θα έχει τη σωστή τιµή για τους επόµενους υπολογισµούς. Σωστή. Καλή δουλειά : Πολύ καλή δουλειά, µπράβο! Στην περίπτωση που αποτυγχάνει το malloc, θα ήταν καλό ή να αποδεσµεύετε τη λίστα ή να επιστρέφετε την κεφαλή της χωρίς να έχει γίνει το cloning. Επίσης, θα µπορούσατε να είχατε εκµεταλλευτεί την ύπαρξη της addtofront ΆΣΚΗΣΗ 1, extra: Σωστή ΆΣΚΗΣΗ 2: Πολύ καλή δουλειά, µπράβο Σωστή. Καλή δουλειά main: Σωστή 1611 PASS Σωστά αποτελέσµατα αλλά δέχεται βελτίωση. Ο λόγος που χρησιµοποιούµε enum αντί για ακεραίους είναι για να έχουµε πιο κατανοητό πρόγραµµα, δεδοµένου ότι η τιµή ενός enum είναι µια περιγραφική λέξη. Έπρεπε αντί για curr->state = 2 να είχατε γράψει curr->state = COPY. Επίσης, µε τον τρόπο που εξετάζετε το base case, το πρόγραµµά σας θα πετάξει segmentation fault αν η λίστα είναι αρχικά άδεια. Σωστή. Page 5
1612 PASS : main: Σωστή Σωστή. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Πολύ καλή δουλειά, µπράβο. : Πολύ καλή δουλειά, µπράβο! Θα µπορούσατε να είχατε εκµεταλλευτεί και την ύπαρξη της addtofront 1619 PASS 1622 PASS ΆΣΚΗΣΗ 1, extra: Σωστή ΆΣΚΗΣΗ 2: Πολύ καλή δουλειά, µπράβο main : Η recinterleave επιστρέφει την κεφαλή της νέας λίστας που κατασκευάστηκε. Πρέπει να αποθηκεύετε το αποτέλεσµά της στο head. Με τον τρόπο που γίνεται το interleave, θα δουλέψει και όπως το έχετε τώρα, αλλά το πιο σωστό είναι να χρησιµοποιείτε αυτό που σας επιστρέφει (γιατί δεν υπάρχει καµία εγγύηση ότι η συνάρτηση θα έχει υλοποιηθεί µε τέτοιο τρόπο ώστε η κεφαλή να µείνει ίδια. ) Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούσαν τη δεύτερη λίστα τώρα πια έχουν προστεθεί στην πρώτη. Το παλιό head2 είναι το επόµενο στοιχείο του head εποµένως έχει ήδη σβηστεί από την πρώτη clearlist. Σωστή, και µπράβο που µεριµνήσατε για λίστες διαφορετικών µεγεθών. 1624 PASS Πολύ σωστή η υλοποίηση και κλήση της συνάρτησης, αλλά θα έπρεπε να έχετε και το prototype της πάνω από τη main. : Πολύ καλή δουλειά, µπράβο! Στην περίπτωση που αποτυγχάνει το malloc, θα ήταν καλό ή να αποδεσµεύετε τη λίστα ή να επιστρέφετε την κεφαλή της χωρίς να έχει γίνει το cloning. Επίσης, θα µπορούσατε να είχατε εκµεταλλευτεί την ύπαρξη της addtofront ΆΣΚΗΣΗ 1, extra: Σωστή ΆΣΚΗΣΗ 2: Πολύ καλή δουλειά, µπράβο Page 6
1628 οριακό PASS Sheet2 Όλα οκ, εκτός από την τιµή που επιστρέφει η συνάρτηση. Το curr είναι η κεφαλή της επιµέρους λίστας που επιστρέφει η αναδροµική κλήση. Η σωστή κεφαλή της λίστας που κατασκευάζετε είναι το head 1630 PASS 1632 PASS 1633 FAIL 1642 FAIL 1648 PASS : main: Σωστή Σωστή. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Πολύ καλή δουλειά, µπράβο. Σωστή γενικά, αλλά θα πετάξει segmentation fault αν η λίστα είναι αρχικά άδεια. Γιατί χρησιµοποιείτε (*newnode).data και όχι newnode->data όπως στα υπόλοιπα σηµεία? Επίσης, έπρεπε να αρχικοποιείτε το newnode->prev σε NULL. Δεν κάνει compile, λίγος κώδικας. main: Όλος ο κώδικας ανάµεσα στην κλήση στη recduplicate και στην printlist δεν έπρεπε να υπάρχει. Όλη η δουλειά πρέπει να γίνεται µέσα στη recduplicate Συνάρτηση που χρησιµοποιεί static και µετρητή i παύει να είναι αναδροµική στην ουσία. Δεν ακολουθήσατε καθόλου τις υποδείξεις που έγιναν στην αρχή του εργαστηρίου. Το ίδιο ισχύει και για την άσκηση 2. Δεν κάνει compile και το λάθος είναι σηµαντικό: Το head1 είναι δείκτης σε struct, εποµένως η προσπέλαση πεδίου γίνεται µε head1->next και όχι head1.next. Επιπλέον, έχετε λάθος και στη λογική. Θέλουµε να κάνουµε το newlist->prev ίσο µε head2 κι όχι το newlist ίσο µε head1->prev. Μετά, θέλουµε το head2->next να γίνει newlist. Τέλος, πρέπει να συνδέσουµε το head1 µε το head2 main: Στο τέλος έπρεπε να καλείτε και την clearlist. Κατά τα άλλα είναι σωστή Σωστή. Η γραµµή 118 (head->prev->next = copy) δεν είναι απαραίτητη γιατί καλύπτεται από την αναδροµή. Πολύ σωστή, µπράβο. Page 7
1651 PASS Όλα οκ στη σύνδεση, εκτός από τη γραµµή head2->prev=head; που είναι λάθος κι έπρεπε να αφαιρεθεί. Η παράµετρος string έπρεπε να είναι δηλωµένη ως char * γιατί είναι string. Η συνάρτηση δεν υλοποιήθηκε. main : Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούν τη λίστα που ξεκινά στο newhead είναι οι κόµβοι που υπήρχαν στη λίστα που ξεκινά στο head συν τα αντίγραφα. Εποµένως η δεύτερη κλήση στην clearlist προσπαθεί να σβήσει στοιχεία που έχουν ήδη σβηστεί από την πρώτη κλήση. Κατά τα άλλα είναι οκ η main Σωστή, και µπράβο που σκεφτήκατε να χρησιµοποιήσετε την έτοιµη συνάρτηση addtofront. 1652 PASS 1653 FAIL Υπάρχουν τρία σηµαντικά λάθη στην υλοποίηση. Το πρώτο είναι ότι δεν αρχικοποιείτε το plithos (σε 0) οπότε όταν κάνετε plithos++ η τιµή έχει σκουπίδια. Αυτό προκαλεί και segmentation fault. Το δεύτερο λάθος είναι ότι δε χρησιµοποιείτε το αποτέλεσµα της αναδροµικής κλήσης στη γραµµή 19. Η countones σε αυτό το σηµείο επιστρέφει το πλήθος των άσων από τη θέση i και πέρα, το οποίο πρέπει να προσθέσετε στο plithos. Το τρίτο και πολύ σηµαντικό λάθος είναι ότι δε χειρίζεστε σωστά το base case. Η αναδροµική κλήση πρέπει να γίνεται όταν το string δεν έχει ακόµη τερµατίσει, δηλαδή µέσα στο if. Αν το string[i] είναι 0, τότε η συνάρτηση πρέπει απλά να επιστρέφει 0. Αυτό το λάθος προκαλεί segmentation fault. Τὸ δὶς ἐξαµαρτεῖν οὐκ ἀνδρὸς σοφοῦ Page 8
main : Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούν τη λίστα που ξεκινά στο newhead είναι οι κόµβοι που υπήρχαν στη λίστα που ξεκινά στο head συν τα αντίγραφα. Εποµένως η δεύτερη κλήση στην clearlist προσπαθεί να σβήσει στοιχεία που έχουν ήδη σβηστεί από την πρώτη κλήση. Κατά τα άλλα είναι οκ η main Σωστή, και µπράβο που σκεφτήκατε να χρησιµοποιήσετε την έτοιµη συνάρτηση addtofront. 1654 PASS 1656 PASS Υπάρχουν τρία σηµαντικά λάθη στην υλοποίηση. Το πρώτο είναι ότι δεν αρχικοποιείτε το plithos σε 0) οπότε όταν κάνετε plithos++ η τιµή έχει σκουπίδια. Αυτό προκαλεί και segmentation fault. Το δεύτερο λάθος είναι ότι δε χρησιµοποιείτε το αποτέλεσµα της αναδροµικής κλήσης στη γραµµή 19. Η countones σε αυτό το σηµείο επιστρέφει το πλήθος των άσων από τη θέση i και πέρα, το οποίο πρέπει να προσθέσετε στο plithos. Το τρίτο και πολύ σηµαντικό λάθος είναι ότι δε χειρίζεστε σωστά το base case. Η αναδροµική κλήση πρέπει να γίνεται όταν το string δεν έχει ακόµη τερµατίσει, δηλαδή µέσα στο if. Αν το string[i] είναι 0, τότε η συνάρτηση πρέπει απλά να επιστρέφει 0. Αυτό το λάθος προκαλεί segmentation fault. main: Σωστή Έχετε την πιο µπερδεµένη λογική που έχω δει σε αναδροµή µε λίστες και είναι προς έπαινό σας το γεγονός ότι τελικά δουλεύει κατά το πλείστον σωστά. Καλό θα ήταν όµως να προσπαθήσετε να ξανακάνετε την άσκηση ακολουθώντας τις υποδείξεις που δόθηκαν στην αρχή του εργαστηρίου. Ο λόγος που χάνεται το πρώτο στοιχείο της λίστας είναι το γεγονός το temp είναι η αρχική κεφαλή, η οποία µετά την προσθήκη του new καταλήγει να είναι ο δεύτερος κι όχι ο πρώτος κόµβος της λίστας. Το σωστό θα ήταν να επιστρέφετε το new. Το temp δεν χρειάζεται καθόλου. Όταν γράφετε µια αναδροµική συνάρτηση, πρέπει να ελέγχετε το base case πριν κάνετε την αναδροµική κλήση, διαφορετικά η αναδροµή δε θα τερµατίσει ποτέ (ή για την ακρίβεια θα τερµατίσει όταν ξεµείνετε από stack. Η λύση σας θα ήταν σωστή αν ο έλεγχος για το \0 είχε γίνει στην αρχή. : Πολύ καλή δουλειά, µπράβο! Θα µπορούσατε να είχατε εκµεταλλευτεί και την ύπαρξη της addtofront 1657 PASS 1658 FAIL ΆΣΚΗΣΗ 1, extra: Σωστή ΆΣΚΗΣΗ 2: Πολύ καλή δουλειά, µπράβο Τὸ δὶς ἐξαµαρτεῖν οὐκ ἀνδρὸς σοφοῦ Page 9
main: Στο τέλος έπρεπε να καλείτε και την clearlist. Κατά τα άλλα είναι σωστή 1659 PASS 1664 PASS 1666 PASS Σωστή. Η γραµµή 118 (head->prev->next = copy) δεν είναι απαραίτητη γιατί καλύπτεται από την αναδροµή. Πολύ σωστή, µπράβο. Σωστή, και µπράβο που µεριµνήσατε για λίστες διαφορετικών µεγεθών. Σωστή. Αντί για strcmp, µπορούσατε να είχατε ελέγξει απλά αν το *word είναι == '\0' Σωστή αλλά στην περίπτωση που το head->prev είναι NULL ξεχνάτε να το κάνετε ίσο µε curr. Σε αυτό οφείλεται το ότι "χάνεται" ένας κόµβος όταν εκτυπώνετε τη λίστα ανάποδα. Καλό θα ήταν να είχατε ακολουθήσει το στυλ του υπόλοιπου προγράµµατος. Το πρωτότυπο της συνάρτησης πάνω από τη main και η υλοποίησή της κάτω από τη main. Σωστή, µπράβο. main: Σωστή 1668 PASS Σωστά αποτελέσµατα αλλά δέχεται βελτίωση. Ο λόγος που χρησιµοποιούµε enum αντί για ακεραίους είναι για να έχουµε πιο κατανοητό πρόγραµµα, δεδοµένου ότι η τιµή ενός enum είναι µια περιγραφική λέξη. Έπρεπε αντί για curr->state = 2 να είχατε γράψει curr->state = COPY. Επίσης, µε τον τρόπο που εξετάζετε το base case, το πρόγραµµά σας θα πετάξει segmentation fault αν η λίστα είναι αρχικά άδεια. Σωστή. Page 10
1669 PASS 1671 PASS Sheet2 main: Σωστή Έχετε την πιο µπερδεµένη λογική που έχω δει σε αναδροµή µε λίστες και είναι προς έπαινό σας το γεγονός ότι τελικά δουλεύει κατά το πλείστον σωστά. Καλό θα ήταν όµως να προσπαθήσετε να ξανακάνετε την άσκηση ακολουθώντας τις υποδείξεις που δόθηκαν στην αρχή του εργαστηρίου. Ο λόγος που χάνεται το πρώτο στοιχείο της λίστας είναι το γεγονός το temp είναι η αρχική κεφαλή, η οποία µετά την προσθήκη του new καταλήγει να είναι ο δεύτερος κι όχι ο πρώτος κόµβος της λίστας. Το σωστό θα ήταν να επιστρέφετε το new. Το temp δεν χρειάζεται καθόλου. Όταν γράφετε µια αναδροµική συνάρτηση, πρέπει να ελέγχετε το base case πριν κάνετε την αναδροµική κλήση, διαφορετικά η αναδροµή δε θα τερµατίσει ποτέ (ή για την ακρίβεια θα τερµατίσει όταν ξεµείνετε από stack. Η λύση σας θα ήταν σωστή αν ο έλεγχος για το \0 είχε γίνει στην αρχή. Σωστή, και µπράβο που µεριµνήσατε για λίστες διαφορετικών µεγεθών. Σωστή. Αντί για strcmp, µπορούσατε να είχατε ελέγξει απλά αν το *word είναι == '\0' main: Η συνάρτηση recduplicate επιστρέφει την κεφαλή της λίστας που κατασκευάζει. Έπρεπε να αποθηκεύετε την τιµή που επιστρέφει στη µεταβλητή head. Με τον τρόπο που το κάνατε, χάνεται ο πρώτος κόµβος της νέας λίστας. 1672 οριακό PASS Λειτουργεί σωστά αλλά έχετε κάποια λαθάκια και το πρόγραµµα δεν είναι πολύ καλογραµµένο. Κατ'αρχήν είναι λάθος να δεσµεύετε µνήµη για το curr. Πρόκειται να το χρησιµοποιήσετε για να αποθηκεύσετε ένα δείκτη σε ήδη δεσµευµένη µνήµη, όχι για κάτι καινούργιο. Στον έλεγχο που κάνετε µετά από malloc, αν πχ το new είναι NULL, τότε δεν έχει νόηµα να το κάνετε free - αφού απέτυχε η δέσµευση µνήµης για αυτό. Ο πιο πολύς κώδικας που έχετε στο if και στο else είναι ακριβώς ο ίδιος. Θα ήταν πολύ πιο κατανοητό το πρόγραµµα αν τα κοινά κοµµάτια ήταν έξω από το if/else (αφού εκτελούνται σε κάθε περίπτωση). Αρκετά άσχηµη στοίχιση. Εξαιρετική δουλειά, µπράβο! 1673 PASS Πολύ καλή δουλειά. Αντί για &string[1] θα µπορούσατε να είχατε γράψει string+1 και αντί για string[0] θα µπορούσατε να είχατε *string. Καθαρά θέµα στυλ: διατήρηση της σύνταξης δεικτών µια και έτσι είναι και το υπόλοιπο πρόγραµµα. Page 11
1684 PASS Σωστή εκτός από τον αρχικό έλεγχο. Έπρεπε να ελέγχετε αν το curr2 είναι NULL, κι όχι το curr2->next. Σε αυτό το λάθος οφείλετε το ότι χάνετε ένα κόµβο στο τέλος (ο τελευταίος κόµβος κάθε λίστας δεν εισάγεται στην τελική). main : Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούν τη λίστα που ξεκινά στο newhead είναι οι κόµβοι που υπήρχαν στη λίστα που ξεκινά στο head συν τα αντίγραφα. Εποµένως η δεύτερη κλήση στην clearlist προσπαθεί να σβήσει στοιχεία που έχουν ήδη σβηστεί από την πρώτη κλήση. Κατά τα άλλα είναι οκ η main 1692 PASS Σωστή. Ο έλεγχος στη γραµµή 72 είναι περιττός. Αν βγάλετε τα κοινά κοµµάτια, αυτό που τελικά κάνετε είναι: if (head->prev == NULL) { curr->prev = NULL; } else { curr->prev = head->prev; } Το ίδιο ακριβώς θα συνέβαινε αν απλά είχατε γράψει curr->prev = head->prev; Αν τύχει το head->prev να είναι NULL, πάλι σωστή θα είναι η ανάθεση. main : Ο λόγος που πετάει segfault είναι γιατί καλείτε δύο φορές την clearlist ξεχνώντας ότι οι κόµβοι που αποτελούν τη λίστα που ξεκινά στο newhead είναι οι κόµβοι που υπήρχαν στη λίστα που ξεκινά στο head συν τα αντίγραφα. Εποµένως η δεύτερη κλήση στην clearlist προσπαθεί να σβήσει στοιχεία που έχουν ήδη σβηστεί από την πρώτη κλήση. Κατά τα άλλα είναι οκ η main 1703 PASS Σωστή. Ο έλεγχος στη γραµµή 72 είναι περιττός. Αν βγάλετε τα κοινά κοµµάτια, αυτό που τελικά κάνετε είναι: if (head->prev == NULL) { curr->prev = NULL; } else { curr->prev = head->prev; } Το ίδιο ακριβώς θα συνέβαινε αν απλά είχατε γράψει curr->prev = head->prev; Αν τύχει το head->prev να είναι NULL, πάλι σωστή θα είναι η ανάθεση. Page 12
1705 FAIL 1711 PASS 1714 PASS main: Όλος ο κώδικας ανάµεσα στην κλήση στη recduplicate και στην printlist δεν έπρεπε να υπάρχει. Όλη η δουλειά πρέπει να γίνεται µέσα στη recduplicate Συνάρτηση που χρησιµοποιεί static και µετρητή i παύει να είναι αναδροµική στην ουσία. Δεν ακολουθήσατε καθόλου τις υποδείξεις που έγιναν στην αρχή του εργαστηρίου. Το ίδιο ισχύει και για την άσκηση 2. σωστή main: Η συνάρτηση recduplicate επιστρέφει την κεφαλή της λίστας που κατασκευάζει. Αυτή λοιπόν πρέπει να χρησιµοποιείς και στην printlist και clearlist που ακολουθεί. Σε αυτό το λάθος οφείλεται το ότι χάνεται ένας κόµβος κατά την εκτύπωση. Παράγει το σωστό αποτέλεσµα αλλά η δηµιουργία της λίστας δε γίνεται πολύ καθαρά Σύµφωνα µε τον ορισµό της συνάρτησης, πρέπει να επιστρέφει την κεφαλή της νέας λίστας που κατασκευάζει κι αυτό δε φαίνεται από τον τρόπο που κάνεις την αναδροµική κλήση. Δεν είναι λάθος ο τρόπος σου, αλλά καλό είναι να προσπαθήσεις να κάνεις και την άσκηση της Παρασκευής για να καταλάβεις ακριβώς την ιδέα. Η λύση δεν είναι ουσιαστικά αναδροµική. Όχι µόνο χρησιµοποιείς static µεταβλητή αλλά και τ συνάρτηση strlen. Τι νόηµα έχει να λύσουµε αναδροµικά το πρόβληµα τότε? Page 13