7/1/2014 ΣΗΜΑΝΤΙΚΗ ΑΝΑΚΟΙΝΩΣΗ: Όπως ακούσατε και στο σηµερινό µάθηµα, θα υπάρξει ειδική ρύθµιση όσον αφορά τις εξετάσεις για όσους φοιτητές δεν πληρούν τις προϋποθέσεις είτε για τα quiz είτε για τις απουσίες (των τελευταίων εργαστηρίων). Εποµένως, ακόµη κι αν έχετε πάρει τρίτο fail στο lab10, ελάτε στο quiz της ερχόµενης εβδοµάδας. Αντίστροφα, ακόµα και αν φαίνεται να µην περνάτε τα quiz, µην εγκαταλείψετε το εργαστήριο αν δεν έχετε συµπληρώσει 3 απουσίες ΑΕΜ ΒΑΘΜΟΣ ΣΧΟΛΙΑ - Σωστά αποτελέσµατα, γενικά καλή δουλειά - Ο τελευταίος έλεγχος στη συνάρτηση είναι περιττός. Αν έχει φτάσει µέχρι εκεί το πρόγραµµα, τότε αναγκαστικά το µήκος είναι >= του PASSWD_MIN_LEN. - Να κατασκευάζετε πάντα το format string µε χρήση sprintf. 357 PASS - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνατε και το username. - Σωστή χρήση malloc/free και έλεγχοι για NULL.Αν το ptr_2 είναι NULL, θα πρέπει να κάνετε free το ptr_1 πριν το exit. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10).
400 FAIL 402 PASS - Άδεια main - Δεν κάνει compile λόγω λάθους σύνταξης στην κλήση της malloc. Ελάχιστος κώδικας. - Καλή δουλειά. Να διαβάζετε πιο προσεκτικά την εκφώνηση/σχόλια: Οι έλεγχοι στην checkaddress έπρεπε να γίνονται µε διαφορετική σειρά. - Μετά από κάθε κλήση στη malloc πρέπει να ελέγχετε αν επέστρεψε NULL. - Σωστή η άσκηση κατά τα άλλα. - Σωστά αποτελέσµατα, γενικά καλή δουλειά - Ο τελευταίος έλεγχος στη συνάρτηση είναι περιττός. Αν έχει φτάσει µέχρι εκεί το πρόγραµµα, τότε αναγκαστικά το µήκος είναι >= του PASSWD_MIN_LEN. - Να κατασκευάζετε πάντα το format string µε χρήση sprintf. 403 PASS - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνατε και το username. - Σωστή χρήση malloc/free και έλεγχοι για NULL.Αν το ptr_2 είναι NULL, θα πρέπει να κάνετε free το ptr_1 πριν το exit. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10).
Λάθος στο όνοµα του φακέλου. - Όχι µόνο δε βάλατε δικά σας σχόλια, αλλά σβήσατε κι αυτά που υπήρχαν. ΓΙΑΤΙ? - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Τυπικά βάζουµε το πρωτότυπο της συνάρτησης πάνω από τη main και την υλοποίηση κάτω. - Όταν δουλεύετε µε pointers να χρησιµοποιείτε NULL κι όχι 0. 1560 FAIL - Είναι επιθυµητό να έχουµε special characters, εποµένως ο σχετικός έλεγχος έπρεπε να ήταν == NULL και όχι!= NULL. - Σωστή κατασκευή format string για την ανάγνωση συµβολοσειρών - Ο έλεγχος τερµατισµού της do/while λειτουργεί σωστά, αλλά δεν είναι πολύ καλά σχεδιασµένος. Τι θα κάνατε αν υπήρχαν 20 πιθανοί κωδικοί λάθους? Θα είχατε ένα σύνθετο µε 20 υποεκφράσεις? Πιο σωστό θα ήταν απλά να γράφατε while (check_user_adr!= VALID_ADDRESS) - Δεν κάνει compile. Δηλώνετε τη µεταβλητή rantevou δύο φορές, µία ως char* και µία ως struct appointmentt * Επίσης, στην ανάγνωση ακεραίων µε scanf πρέπει να χρησιµοποιείτε & πριν το όνοµα της µεταβλητής που διαβάζετε. - Λάθος χρήση malloc. Δεσµεύουµε µνήµη για ραντεβού, όχι για χαρακτήρες. Φαίνεται να κάνατε copy+paste κάτι από τις διαφάνειες.
- Τι είναι το j και γιατί το χρησιµοποιείτε? Έχετε ήδη την epistrofh και ξέρετε ότι το loop πρέπει να συνεχίζει όσο αυτή δεν είναι VALID_ADDRESS οπότε γιατί να µπερδέψετε τον κώδικά σας µε µια µεταβλητή που το όνοµά της υπονοεί ότι πρόκειται για µετρητή loop κι ένα κατεβατό από if/else? Τελικά το πρόγραµµα δε λειτουργεί σωστά. Αν το λάθος είναι MISSING_DOT, τότε το πρώτο if (για το MISSING_AT) θα βγει false, οπότε το j θα γίνει 1 και το while θα τερµατίσει χωρίς να πρέπει. - Αντί να βάζετε το \0 και µετά strcat, θα ήταν πολύ πιο κοµψό να είχατε µόνο µια strcpy. - Η printf για το Name έπρεπε να είναι µέσα στο for. 1588 PASS - Σωστή η checkaddress αλλά προσέξτε τη µορφή του κώδικά σας. Αφήνετε πολλές κενές γραµµές και δε διαβάζεται εύκολα. - Σωστή χρήση malloc, αλλά µετά από κάθε κλήση σε αυτή πρέπει πάντα να ελέγχετε αν επέστρεψε NULL. - Αντί για scanf(formatstr, onoma); strcpy(a_ptr->shmeio, onoma); θα µπορούσατε να είχατε γράψει απευθείας scanf(formatstr, a_ptr->shmeio). - Σωστά κατά τα άλλα, αλλά προσέξτε τα ονόµατα των µεταβλητών/πεδίων σας. Δεν είναι καθόλου περιγραφικά και µερικές φορές παραπλανητικά (πχ το shmeio θα έπρεπε να είναι onoma)
1614 οριακό PASS - Καλό θα ήταν να είχατε τον ορισµό του struct έξω από τη main. Τυπικά τον βάζουµε κάτω από τα #define. Δεν είναι λάθος όπως το κάνατε, αλλά αν χρειαζόταν να γράψουµε µια συνάρτηση που να θέλει πρόσβαση στο struct, τότε δε θα ήταν ορατό σε αυτή (τώρα το έχετε δηλώσει τοπικά στη main) - Στη κατασκευή του format string έπρεπε να είχατε STR_MAX_LEN-1. Αφήνουµε πάντα µια θέση για το \0. Επίσης, καλό θα ήταν να είχατε την sprintf έξω από το loop ώστε να καλείται µόνο µια φορά κι όχι σε κάθε µία επανάληψη (έτσι κι αλλιώς, το ίδιο format string φτιάχνει πάντα) - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα ήταν πιο κοµψό να είχατε switch. - Λάθος στη λογική του προγράµµατος: Στη while θα έπρεπε να ξανακαλείτε την checkpasswd µετά από κάθε scanf του password, ώστε να ελέγχεται κάθε φορά το νέο password. - Λάθος στην έξοδο: στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Παρόλο που φτιάξατε format string, στη δεύτερη scanf όχι µόνο δεν το χρησιµοποιείτε αλλά έχετε σκέτο %s που έχουµε πει ότι είναι επικίνδυνο! - Όχι µόνο δε βάλατε σχόλια, αλλά σβήσατε από τη συνάρτηση και τα σωστά, περιγραφικά σχόλια που σας δώσαµε έτοιµα. ΓΙΑΤΙ? - Τυπικά γράφουµε το prototype της συνάρτησης πάνω από τη main και την υλοποίηση µετά τη main. - Μη περιγραφικά ονόµατα µεταβλητών (res, x). - Δεν κάνει compile: Όταν διαβάζετε ακέραιες τιµές µε scanf πρέπει να βάζετε & στη µεταβλητή όπου θα αποθηκευτεί η τιµή. Επίσης σε κάποια έκφραση έχετε λάθος το όνοµα του πεδίου (wra αντί για wres) - Σωστή χρήση malloc/free αλλά πρέπει πάντα να κάνετε typecast το αποτέλεσµα και να ελέγχετε αν επέστρεψε NULL. - Ο υπολογισµός της διαφοράς ώρας δε γίνεται σωστά: δε λαµβάνετε υπόψη την περίπτωση που η diaflepta είναι αρνητική (πχ αν οι ώρες είναι 9:40, 10:10)
- Σοβαρό πρόβληµα στην προσπέλαση πινάκων: Και στα δύο for loop βγαίνετε εκτός ορίων. Δε θα έπρεπε να κάνετε τέτοια λάθη σε αυτό το στάδιο. - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα σβήσατε? - Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. 1717 FAIL - Σωστή υλοποίηση της checkaddress - Δεν κάνει compile. Λάθος typecast στη malloc και λάθος παράµετρος. Αντί για την έκφραση που γράψατε ως παράµετρο, έπρεπε να είχατε sizeof(struct pointt), γιατί δεν είναι εγγυηµένο ότι το µέγεθος του struct θα είναι ακριβώς όσο το άθροισµα των µεγεθών των πεδίων. - Μετά από κάθε κλήση σε malloc πρέπει να ελέγχετε αν επέστρεψε NULL. - Έπρεπε να χρησιµοποιείτε -> κι όχι τελεία για να προσπελάσετε τα πεδία του struct. - Δεν κάνετε free στο τέλος
1718 οριακό PASS - Στην checkpasswd, στον έλεγχο για το µήκος έπρεπε να είχατε χρησιµοποιήσει τη σταθερά PASSWD_MIN_LEN και όχι το 8. Έτσι όπως το έχετε, αν αλλάξει η τιµή του PASSWD_MIN_LEN, το πρόγραµµά σας δε θα λειτουργεί σωστά. Επίσης, ο έλεγχος έπρεπε να είναι < και όχι <= - Σωστός έλεγχος αποτελέσµατος κι εκτύπωση µηνυµάτων. Εδώ θα ήταν κατάλληλη και η χρήση switch εφόσον το result είναι ακέραιος. Εναλλακτικά, θα µπορούσατε να είχατε else if. Έτσι, αν πχ το αποτέλεσµα είναι TOO_SHORT, δε θα χρειαστεί να γίνουν οι υπόλοιποι έλεγχοι. - Στο τέλος δεν εκτυπώνονται σωστά τα περιεχόµενα του πίνακα γιατί έχετε τερµατίσει το for µε ; στη γραµµή 72 - Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. - Σωστή χρήση sprintf για τη δηµιουργία format string. - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα αλλάξατε? Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. - Σωστό struct. - Σωστή χρήση malloc, αλλά θα έπρεπε µετά από κάθε malloc να ελέγχετε για NULL και σε αυτή την περίπτωση να εκτυπώνετε κατάλληλο µήνυµα, να απελευθερώνετε ότι δυναµικά δεσµευµένη µνήµη υπάρχει και να τερµατίζετε. Ειδικά ο τερµατισµός είναι σηµαντικός, γιατί αν τα first_ap, second_ap είναι NULL, το πρόγραµµα θα πετάξει segmentation fault όταν πάτε να τα προσπελάσετε - Ο υπολογισµός της διαφοράς ώρας δε γίνεται σωστά: δε λαµβάνετε υπόψη την περίπτωση που η diafora_min είναι αρνητική (πχ αν οι ώρες είναι 9:40, 10:10) - Σωστή απελευθέρωση µνήµης στο τέλος. - Καλά ονόµατα µεταβλητών, στοίχιση.
1719 PASS - Η δεύτερη παράµετρος της sprintf έπρεπε να είναι STR_MAX_LEN-1 κι όχι STR_MAX_LEN, γιατί χρειάζεται χώρος για το \0.Κατά τα άλλα καλή δουλειά. Οι έλεγχοι του αποτελέσµατος της συνάρτησης θα µπορούσαν να είχαν γίνει και µε switch. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10). Κατά τα άλλα καλή δουλειά. Δε χρειάζεται να βάζετε σε κάθε γραµµή σχόλια (από ένα σηµείο και µετά πνίγουν τον κώδικα). Για παράδειγµα, είναι προφανές τι κάνουν οι free. Άσκηση 1; - Λάθος στη λογική της άσκησης. Έπρεπε να είχατε ένα loop που τρέχει NUMUSERS φορές και σε κάθε επανάληψη (1) διαβάζει το username και (2) περιέχει ένα do-while παρόµοιο µε αυτό που γράψατε στο οποίο καλεί την checkpasswd κι ελέγχει το αποτέλεσµά της. Εσείς φαίνεται να ενώσατε τα δύο loops σε ένα. Επίσης, για κάποιο λόγο εκτυπώνετε τα µηνύµατα Username και Password µόνο όταν το i είναι 0. Γιατί? 1720 οριακό PASS - Σωστές οι εκτυπώσεις των µηνυµάτων λάθους. - Όταν δουλεύετε µε pointers να χρησιµοποιείτε NULL κι όχι 0. - Προσέξτε τη στοίχιση - Οι έλεγχοι στην checkpasswd είναι ανάποδα. Είναι επιθυµητό να υπάρχουν ειδικοί χαρακτήρες, εποµένως σε αυτή την περίπτωση πρέπει να ελέγχετε αν το αποτέλεσµα είναι ίσο µε NULL. Αντίθετα, δεν είναι επιθυµητό να περιλαµβάνεται το username εποµένως σε αυτή την περίπτωση έπρεπε να ελέγχετε αν το αποτέλεσµα είναι διάφορο του NULL. - Όταν ορίζετε ένα struct καλό είναι να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή. - Καλή δουλειά όσον αφορά δέσµευση µνήµης και τους ελέγχους (µπράβο για το free όταν το ptr2 είναι NULL). - Δε λαµβάνετε υπόψη την περίπτωση που η διαφορά λεπτών είναι αρνητική (πχ 9:40 µε 10:10) - Το ptr1->rantevou είναι string εποµένως δεν πρέπει να βάλετε & στη scanf - Στο τέλος του προγράµµατος πρέπει να κάνετε free τη δυναµικά δεσµευµένη µνήµη.
- Το µέγεθος του format string δεν έχει ΚΑΜΙΑ σχέση µε το MAX_NAME_LEN. Αντιθέτως, εξαρτάται από το τι θα περιέχει (το %, το πολύ 10 ψηφία για έναν ακέραιο, το s και το \0). Οµοίως και για τη δεύτερη άσκηση. - Η δεύτερη παράµετρος της sprintf έπρεπε να ήταν MAX_NAME_LEN-1 κι όχι MAX_NAME_LEN γιατί χρειάζεται να κρατηθεί µια θέση για το \0. Οµοίως και για τη δεύτερη άσκηση. 1721 PASS - Καλό θα ήταν ο ορισµός του struct να µην ήταν κρυµµένος µέσα στον κώδικα της main, και τα πεδία να ήταν σε ξεχωριστή γραµµή το καθένα. - Σωστή χρήση switch αλλά µη βάζετε ποτέ πολλαπλές εντολές στην ίδια γραµµή. - Σωστή η cehckaddress αλλά γιατί σβήσατε τα σωστά και καλογραµµένα σχόλια που σας δώσαµε? - Καλή δουλειά, παραλείψατε µόνο να ελέγξετε για NULL µετά από κάθε κλήση στη malloc. - Σωστή λειτουργία. Καλή δουλειά γενικά. - Προσοχή στην έξοδο. Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username και στην τελική εκτύπωση ξεχάσατε το χαρακτήρα αλλαγής γραµµής.. 1722 PASS - Στη συνάρτηση θα µπορούσατε να είχατε κάνει τους ελέγχους απευθείας στην if αντί να αποθηκεύετε το αποτέλεσµα σε µεταβλητή (και µάλιστα µη-περιγραφική). Θα ήταν πιο καθαρός ο κώδικας έτσι, ειδικά αν υπήρχαν και περισσότεροι έλεγχοι. Για παράδειγµα: if (strstr(passwd, username)!= NULL) {... - Στον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. - Αν η malloc επιστρέψει NULL, είναι καλό να εκτυπώνετε κι ένα µήνυµα λάθους προς τον χρήστη. - Πολύ σωστά, µπράβο.
- Σωστή λειτουργία της checkpasswd, αλλά ως συνάρτηση δεν είναι πολύ καλογραµµένη. Αντί να χρησιµοποιείτε τις µεταβλητές prwto_lathos, deutero_lathos κτλ, τα ονόµατα των οποίων δε δίνουν καµία πληροφορία για το τι εννοούν, θα ήταν καλύτερα να έχετε απευθείας το κατάλληλο return µετά από κάθε έλεγχο. Έτσι, ο αναγνώστης θα έβλεπε άµεσα τι επιστρέφει η συνάρτηση σε κάθε περίπτωση, αντί να χρειάζεται να διαβάσει πιο κάτω. Για παράδειγµα, if (strstr(passwd, username)!= NULL) { return INCLUDES_USERNAME; } Επίσης, µε αυτές τις µεταβλητές είναι πολύ πιο εύκολο να γίνει λάθος από τον προγραµµατιστή (δηλαδή να µην επιστρέψει τη σωστή τιµή σε κάποια περίτπωση επειδή πχ µπέρδεψε πού αντιστοιχεί το deutero_lathos. - Σωστή δηµιουργία format string για την ανάγνωση συµβολοσειρών. 1723 PASS - Καλά ονόµατα µεταβλητών εκτός από το k. Θα µπορούσατε να το είχατε πει errorcode. Εναλλακτικά (και πιο κοµψά) θα µπορούσατε να είχατε χρησιµοποιήσει switch ως εξής: switch ( checkpasswd(elegxos_passwd, xrhstes[i].username) ) { case TOO_SHORT: printf(...) κτλ. - Στην τελική εκτύπωση των περιεχοµένων του πίνακα δεν έχετε χαρακτήρα αλλαγής γραµµής µετά από κάθε password. Επίσης, στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε το username στη θέση του s κι όχι το γράµµα s. - Στην περίπτωση που αποτυγχάνει η malloc έπρεπε να εκτυπώνετε κι ένα µήνυµα προς τον χρήστη για να γνωρίζει γιατί τερµάτισε το πρόγραµµα. Επίσης, οι έλεγχοι για NULL έπρεπε να γίνονται χωριστά. Αν πετύχει το malloc για το radevou1 αλλά αποτύχει αυτό για το radevou2, τότε θα πρέπει να κάνετε πρώτα free το radevou1 πριν τερµατίσει το πρόγραµµα. - Αντί για *. είνα γενικά προτιµότερο (και πιο ξεκάθαρο) να χρησιµοποιείτε -> - Σωστός υπολογισµός διαφοράς ώρας.
- Σωστή λειτουργία, αλλά να διαβάζετε πιο προσεκτικά την εκφώνηση: οι εκτυπώσεις έπρεπε να γίνονται στη main κι όχι µέσα στη συνάρτηση. Σκοπός της συνάρτησης ήταν αποκλειστικά ο έλεγχος και η επιστροφή του κωδικού (όπως έλεγαν και τα σχόλια) - Στον ορισµό του struct είναι καλό να βάζετε τα πεδία σε ξεχωριστές γραµµές για να είναι πιο ευανάγνωστος ο κώδικας. 1724 PASS - Στην κατασκευή του format string έπρεπε να είχατε STR_MAX_LEN-1 κι όχι +1. Θέλουµε να διαβαστεί ένας λιγότερος χαρακτήρας για να µπει και το \0 στην τελευταία θέση. Επίσης, το format string πρέπει να έχει µεγαλύτερο µέγεθος (1 για το %, 1 για το s, µέχρι 10 για τον ακέραιο κι 1 για το \0 --> µέγεθος 13) - Η main σας είναι κάπως απλοποιηµένη εφόσον δεν περιέχει τους κατάλληλους ελέγχους του αποτελέσµατος της συνάρτησης. - Σωστή η τελική εκτύπωση - Σωστή χρήση malloc/free. Μετά από κάθε malloc όµως πρέπει να ελέγχετε οπωσδήποτε αν επέστρεψε NULL. - Στον υπολογισµό της διαφοράς λεπτών έχετε app_2oy_ptr->mins)-(app_2oy_ptr->mins) οπότε βγαίνει πάντα 0. - Καλή προσπάθεια.
1725 οριακό PASS ΛΑΘΟΣ ΟΝΟΜΑ ΦΑΚΕΛΟΥ! Πόσες φορές πρέπει να το αναφέρουµε? - Να διαβάζετε πιο προσεκτικά την εκφώνηση. Οι εκτυπώσεις των µηνυµάτων λάθους έπρεπε να γίνονται στη main. - Οι sprintf θα ήταν καλύτερα να βρίσκονται εκτός loop ώστε να καλούνται από µία φορά κι όχι σε κάθε επανάληψη. Έτσι κι αλλιώς το ίδιο πράγµα κατασκευάζουν κάθε φορά. - Μετά από κάθε malloc πρέπει πάντα να ελέγχετε για NULL. - Το ptr_1->name είναι string εποµένως δεν πρέπει να βάλετε & στη scanf. - Για µια ακόµη φορά έχετε ονόµατα της µορφής ptr_1, ptr_2. Αυτή είναι η τελευταία φορά που σας γράφουµε σχόλια βαθµολόγησης, εφόσον προφανώς δεν τα διαβάζετε. - Στην τελική εκτύπωση έπρεπε να εµφανίζονται τα ονόµατα των σηµείων κι όχι τα γράµµατα x, y, z. - Δεν κάνετε free τη δυναµικά δεσµευµένη µνήµη.
- Σωστή υλοποίηση της checkpasswd - Προσοχή στη στοίχιση: οι δηλώσεις µεταβλητών στη main έπρεπε να ήταν ένα tab πιο δεξιά - Σωστή κατασκευή του format string. Θα ήταν καλύτερα η sprintf να βρισκόταν έξω από το loop ώστε να εκτελείται µόνο µια φορά κι όχι σε κάθε επανάληψη (άλλωστε το ίδιο format string κατασκευάζεται κάθε φορά) 1726 FAIL - Οι έλεγχοι του αποτελέσµατος της checkpasswd στη main θα µπορούσαν να είχαν γίνει και µε switch. - Γενικά καλά ονόµατα µεταβλητών, αλλά το πεδίο Onomata είναι παραπλανητικό. Το όνοµα ΕΝΟΣ χρήστης αποθηκεύεται σε αυτό. - Το τελευταίο else είναι λάθος. Σε εκείνο το σηµείο, µόλις έχετε οριστικοποιήσει το username και το password για ΕΝΑΝ χρήστη, και για την ακρίβεια για τον χρήστη στη θέση i. Εσείς τα αντιγράφετε σε όλες τις θέσεις του πίνακα χρηστών. Επιπλέον χρησιµοποιείτε πάλι i (παρόλο που το i ελέγχει και το εξωτερικό loop) κι έτσι "καταστρέφετε" την τιµή του. - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Δεν έγινε - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα σβήσατε? 1727 PASS -Σωστή λειτουργία. Οι έλεγχοι για το αποτέλεσµα της συνάρτησης θα µπορούσαν να γίνουν και µε switch. - Σωστή χρήση malloc, αλλά µετά από κάθε κλήση πρέπει να ελέγχετε αν επέστρεψε NULL. - Μη χρησιµοποιείτε ΠΟΤΕ σκέτο %s στη scanf. Έχουµε πει πολλές φορές ότι είναι επικίνδυνο.
- Όταν ορίζετε ένα struct είναι καλύτερα να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή για να είναι πιο κατανοητός ο κώδικας. - Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. Επίσης, η συνάρτηση είχε εκτενή και σωστά σχόλια, τα οποία αφαιρέσατε! Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. 1728 FAIL - Λάθος στην υλοποίηση της checkaddress που έχει ως αποτέλεσµα ατέρµονο loop. Αν το email έχει έστω κι έναν παράνοµο χαρακτήρα έπρεπε να επιστρέφετε HAS_ILLEGAL_CHARS. Εσείς, αν έχει παράνοµο χαρακτήρα καλείτε επαναληπτικά την strpbrk. Το loop θα τερµατίσει αν δεν υπάρχει άλλος παράνοµος χαρακτήρας µετά από αυτόν που βρέθηκε. Αν όµως υπάρχει, δε θα τερµατίσει ποτέ γιατί το address+1 είναι πάντα η ίδια διεύθυνση. Τελικά, επιστρέφετε HAS_ILLEGAL_CHARS αφού ελέγξετε ότι δεν υπάρχουν παράνοµοι χαρακτήρες, που είναι το αντίθετο από αυτό που θέλουµε. - Σωστή δηµιουργία των format string για την ανάγνωση των συµβολοσειρών, αλλά θα ήταν καλύτερα να είχατε τις δύο sprintf έξω από το for ώστε να καλούνται µόνο µια φορά η καθεµία. Άλλωστε, το ίδιο format string κατασκευάζει η κάθε µία κάθε φορά που εκτελείται. - Ο έλεγχος του αποτελέσµατος είναι σωστός. Θα µπορούσε να είχε γίνει και µε switch. - Ο έλεγχος τερµατισµού της do/while λειτουργεί σωστά, αλλά δεν είναι πολύ καλά σχεδιασµένος. Τι θα κάνατε αν υπήρχαν 20 πιθανοί κωδικοί λάθους? Θα είχατε ένα σύνθετο µε 20 υποεκφράσεις? Πιο σωστό θα ήταν απλά να γράφατε while (check_user_adr!= VALID_ADDRESS) - Δεν κάνει compile, ελάχιστος κώδικας. Σωστή η δηµιουργία του struct αλλά οι malloc είναι λάθος. Το size_t(struct) δεν έχει κανένα νόηµα.
1731 οριακό PASS - Το πρόγραµµα δεν ακολουθεί τις προδιαγραφές: Τα µηνύµατα για λάθος password έπρεπε να εκτυπώνονται στη main και τα username/passwords έπρεπε να εκτυπώνονται ΑΦΟΤΟΥ έχει γεµίσει ο πίνακας κι όχι µε κάθε εισαγωγή στοιχείων. Κυρίως γι αυτό παίρνετε οριακό pass. - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Σωστή κατασκευή format string, αλλά θα ήταν πιο πρακτικό η sprintf να είναι έξω από το loop ώστε να καλείται µόνο µία φορά - έτσι κι αλλιώς το ίδιο πράγµα κατασκευάζει κάθε φορά - Στη main έπρεπε να χρησιµοποιείτε τον κωδικό VALID_PASSWD κι όχι την τιµή 1. - Όχι µόνο δε βάλατε σχόλια, αλλά σβήσατε και τα σωστά, περιγραφικά σχόλια που σας δώσαµε έτοιµα. ΓΙΑΤΙ? - Τυπικά γράφουµε το prototype της συνάρτησης πάνω από τη main και την υλοποίηση µετά τη main. 1734 FAIL - Compile µε warnings. - Όταν χρησιµοποιείτε malloc πρέπει να κάνετε #include το stdlib.h - Μετά από κάθε malloc πρέπει να ελέγχετε αν επέστρεψε NULL - Καλό είναι να µην ανακατεύετε δηλώσεις µεταβλητών µε άλλο κώδικα, αλλά να βάζετε τις δηλώσεις στην αρχή. Οι µεταβλητές prwto_rant, deutero_rant τι σκοπό εξυπηρετούν? Έπρεπε να χρησιµοποιείτε σε όλες τις περιπτώσεις τις prwto και deutero. - Ο υπολογισµός της διαφοράς δεν είναι σωστός. Έπρεπε να κάνετε κάτι παρόµοιο µε αυτό που είχαµε στο hw1. - Στο τέλος έπρεπε να κάνετε free τη δυναµικά δεσµευµένη µνήµη. - Δεν κάνει compile. Σοβαρά λάθη σχεδόν σε κάθε γραµµή! - Περιέχει µόνο το struct.
1735 οριακό PASS - Καλό θα ήταν να είχατε τον ορισµό του struct έξω από τη main. Τυπικά τον βάζουµε κάτω από τα #define. Δεν είναι λάθος όπως το κάνατε, αλλά αν χρειαζόταν να γράψουµε µια συνάρτηση που να θέλει πρόσβαση στο struct, τότε δε θα ήταν ορατό σε αυτή (τώρα το έχετε δηλώσει τοπικά στη main) - Στη κατασκευή του format string έπρεπε να είχατε STR_MAX_LEN-1. Αφήνουµε πάντα µια θέση για το \0. Επίσης, καλό θα ήταν να είχατε την sprintf έξω από το loop ώστε να καλείται µόνο µια φορά κι όχι σε κάθε µία επανάληψη (έτσι κι αλλιώς, το ίδιο format string φτιάχνει πάντα) - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα ήταν πιο κοµψό να είχατε switch. - Λάθος στη λογική του προγράµµατος: Στη while θα έπρεπε να ξανακαλείτε την checkpasswd µετά από κάθε scanf του password, ώστε να ελέγχεται κάθε φορά το νέο password. - Λάθος στην έξοδο: στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Παρόλο που φτιάξατε format string, στη δεύτερη scanf όχι µόνο δεν το χρησιµοποιείτε αλλά έχετε σκέτο %s που έχουµε πει ότι είναι επικίνδυνο! - Όχι µόνο δε βάλατε σχόλια, αλλά σβήσατε από τη συνάρτηση και τα σωστά, περιγραφικά σχόλια που σας δώσαµε έτοιµα. ΓΙΑΤΙ? - Τυπικά γράφουµε το prototype της συνάρτησης πάνω από τη main και την υλοποίηση µετά τη main. - Μη περιγραφικά ονόµατα µεταβλητών (res, x). - Δεν κάνει compile: Όταν διαβάζετε ακέραιες τιµές µε scanf πρέπει να βάζετε & στη µεταβλητή όπου θα αποθηκευτεί η τιµή. Επίσης σε κάποια έκφραση έχετε λάθος το όνοµα του πεδίου (wra αντί για wres) - Σωστή χρήση malloc/free αλλά πρέπει πάντα να κάνετε typecast το αποτέλεσµα και να ελέγχετε αν επέστρεψε NULL. - Ο υπολογισµός της διαφοράς ώρας δε γίνεται σωστά: δε λαµβάνετε υπόψη την περίπτωση που η diaflepta είναι αρνητική (πχ αν οι ώρες είναι 9:40, 10:10)
1736 PASS 1737 PASS - Πολύ καλή δουλειά, µπράβο. Για τον έλεγχο του αποτελέσµατος θα µπορούσατε να είχατε χρησιµοποιήσει και switch. - Πολύ καλή δουλειά, µπράβο.. Άσκηση 1 - Το πρόγραµµά σας έχει κάποια bugs τα οποία καταλήγουν στο να "σκάει" µε µήνυµα "pointer being freed was not allocated": ---Δεσµεύετε στην αρχή µνήµη για το database των χρηστών (το οποίο δεν ήταν απαραίτητο γιατί ξέρουµε το πλήθος τους από πριν, οπότε αρκούσε να χρησιµοποιήσετε στατικό πίνακα). Στη µνήµη αυτή δείχνουν δύο δείκτες, ο userdb και ο current. Μέσα στην additem καλείτε realloc στη µνήµη που δείχνει ο current, εποµένως δεσµεύετε νέα µνήµη και η παλιά απελευθερώνεται. Όταν τελειώσει το πρόγραµµα κάνετε free(userdb) το οποίο προσπαθεί να απελευθερώσει (για µια ακόµη φορά) την αρχική µνήµη. Γι αυτό βγαίνει το µήνυµα λάθους. Το σωστό θα ήταν να είχατε free(current) διότι ο current είναι αυτός που δείχνει πάντα στη σωστή µνήµη που έχετε τους χρήστες. --- Για τον ίδιο λόγο, θα έπρεπε στην τελική εκτύπωση να χρησιµοποιείτε current[i] και όχι userdb[i]. --- Όταν κάνετε realloc την πρώτη φορά, ζητάτε *count κελιά το οποίο είναι όσο το i, το οποίο είναι 0, εποµένως ζητάτε 0 bytes. Έπρεπε να είχατε (*count+1) - Μη χρησιµοποιείτε "τυχαίες" τιµές για κωδικούς λάθους, γιατί µπερδεύουν τον αναγνώστη. Τι σηµαίνει -456 και τι διαφορά έχει από το -3409? Αρκούσε ένα exit(1) ή ένα #define για τον κωδικό MALLOC_ERROR και µετά να επιστρέφετε αυτό. - Σωστή χρήση sprintf για τη δηµιουργία format string. - Σωστή χρήση switch για τον έλεγχο του αποτελέσµατος της συνάρτησης. - Γενικά σωστή η τελική εκτύπωση, εκτός από το θέµα µε το userdb - Γενικά σωστή η additem εκτός από το θέµα µε το *count - Σωστή η checkspecial, αλλά θα ήταν πιο απλό να είχατε χρησιµοποιήσει την strpbrk. - Γενικά οκ, αλλά: --- Να κάνετε πάντα typecast το αποτέλεσµα της malloc --- Να ελέγχετε για NULL µετά από κάθε malloc --- Δεν καλύπτετε την περίπτωση που η διαφορά λεπτών είναι αρνητική (πχ 9:40 µε 10:10) --- Δεν κάνετε free 1738 FAIL Εστάλη λάθος εργαστήριο
- Ελάχιστος κώδικας. 1740 FAIL - Το loop βγαίνει εκτός ορίων πίνακα. - Δε χρησιµοποιείτε κατάλληλο format string στη scanf. - Δεν έγινε 1741 PASS - Η δεύτερη παράµετρος της sprintf έπρεπε να είναι STR_MAX_LEN-1 κι όχι STR_MAX_LEN, γιατί χρειάζεται χώρος για το \0.Κατά τα άλλα καλή δουλειά. Οι έλεγχοι του αποτελέσµατος της συνάρτησης θα µπορούσαν να είχαν γίνει και µε switch. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10). Κατά τα άλλα καλή δουλειά. Δε χρειάζεται να βάζετε σε κάθε γραµµή σχόλια (από ένα σηµείο και µετά πνίγουν τον κώδικα). Για παράδειγµα, είναι προφανές τι κάνουν οι free. - Καλή δουλειά, µπράβο. Ο έλεγχος του αποτελέσµατος της συνάρτησης µπορούσε να γίνει και µε switch. - Στην τελική εκτύπωση δεν έχετε \n 1742 PASS - Καλή δουλειά στη χρήση malloc και στα free στις περιπτώσεις που επεστράφη NULL. - Πριν το τελευταίο return 0 πρέπει να γίνουν και τα 3 σηµεία free, όχι µόνο το p3. - Άσχηµα ονόµατα µεταβλητών. Επίσης, µη χρησιµοποιείτε ποτέ σκέτο %s όταν διαβάζετε strings, αλλά να προσδιορίζετε και µέγεθος (%9s ή δηµιουργία format string µε sprintf). - Ελλιπής άσκηση, αλλά σωστή µέχρι το σηµείο που υλοποιήσατε.
- Καλή δουλειά, µπράβο. Ο έλεγχος του αποτελέσµατος της συνάρτησης µπορούσε να γίνει και µε switch. - Στην τελική εκτύπωση δεν έχετε \n 1743 PASS - Καλή δουλειά στη χρήση malloc και στα free στις περιπτώσεις που επεστράφη NULL. - Πριν το τελευταίο return 0 πρέπει να γίνουν και τα 3 σηµεία free, όχι µόνο το p3. - Άσχηµα ονόµατα µεταβλητών. Επίσης, µη χρησιµοποιείτε ποτέ σκέτο %s όταν διαβάζετε strings, αλλά να προσδιορίζετε και µέγεθος (%9s ή δηµιουργία format string µε sprintf). - Ελλιπής άσκηση, αλλά σωστή µέχρι το σηµείο που υλοποιήσατε. Όπως έχουµε αναφέρει ξανά, ΤΟ ΟΝΟΜΑ ΤΟΥ ΦΑΚΕΛΟΥ ΔΕΝ ΑΚΟΛΟΥΘΕΙ ΤΙΣ ΠΡΟΔΙΑΓΡΑΦΕΣ. - Καλή δουλειά γενικά. - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. 1745 PASS - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνατε και το username. - Καλή δουλειά. - Σωστή χρήση malloc/free κι έλεγχος για NULL. Αν το datedetails2 είναι NULL, θα πρέπει να κάνετε free το datedetails1 πριν το return. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10). - Είναι καλύτερα να χρησιµοποιείτε -> αντί για *.
1746 οριακό PASS - Σωστή λειτουργία. Προσέξτε λίγο το output όσον αφορά τις προδιαγραφές. - Σκοπός των #define για τους κωδικούς λάθους είναι να κάνουν πιο ευανάγνωστο το πρόγραµµα αλλά και πιο εύκολο στη συντήρηση. Με το να χρησιµοποιείτε -1 αντί για TOO_SHORT στη main, όχι µόνο αναγκάζετε τον αναγνώστη να ψάξει να βρει τι σηµαίνει το -1, αλλά αυξάνετε και την πιθανότητα να "σπάσει" το πρόγραµµα αν αργότερα αλλάξουν οι τιµές των σταθερών (πχ µετά από προσθήκη νέων κωδικών λάθους) ή απλά να γίνει κάποιο λάθος από µέρους του προγραµµατιστή (πχ να γράψετε -1 ενώ θέλατε -2) - Το µέγεθος του format string δεν έχει ΚΑΜΙΑ σχέση µε το STR_MAX_LEN. Αντιθέτως, εξαρτάται από το τι θα περιέχει (το %, το πολύ 10 ψηφία για έναν ακέραιο, το s και το \0) - Δεν κάνει compile. Ξεχάσατε το ; στο τέλος του ορισµού του struct, µπερδέψατε τις παρενθέσεις στις scanf και ξεχάσατε το & σε 2 σηµεία. - Καλό είναι να αποφεύγετε το *. γιατί κάνει πιο πολύπλοκες τις εκφράσεις (όπως φάνηκε και στις scanf σας). Είναι πολύ πιο απλό και κατανοητό το &(rantevou1->hour) από το &((*rantevou1).hour). - Καλή προσπάθεια, παρά τα λάθη.
1747 οριακό PASS - Όταν ορίζετε ένα struct να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή για να είναι πιο ξεκάθαρος ο κώδικας. - Προσέξτε τη στοίχιση. Είναι ασυνεπής (αλλού tab, αλλού κενό) και σε αρκετά σηµεία λάθος. - Θα µπορούσατε να είχατε ένα format string για κάθε περίπτωση και να καλέσετε τις δύο sprintf έξω από τα loops. Έτσι θα είχατε δύο µόνο κλήσεις της sprintf αντί για πολλαπλές µέσα στις επαναλήψεις. Έτσι κι αλλιώς το ίδιο πράγµα κατασκευάζεται κάθε φορά. - Ο έλεγχος του αποτελέσµατος της συνάρτησης θα µπορούσε να γίνει και µε switch. - Σωστή υλοποίηση της checkaddress, αλλά άσχηµα ονόµατα µεταβλητών. Δεν είναι καν απαραίτητα: µπορείτε να κάνετε όλους τους ελέγχους µέσα στις if. - Λείπει το \n στην τελική εκτύπωση. - Απαράδεκτα ονόµατα µεταβλητών! Ειδικά τα LA, LB είναι τραγικά (και τα κεφαλαία υπονοούν σταθερές). Οριακό pass γιατί σας έχουµε ξαναπεί να δίνετε καλύτερα ονόµατα. Περιµένουµε βελτίωση την επόµενη φορά. - Να ελέγχετε χωριστά για NULL σε κάθε malloc. Αν το p2 είναι NULL πρέπει να γίνει free το p1, κι αν το p3 είναι NULL πρέπει να γίνουν free τα p1, p2. Επίσης, σε κάθε περίπτωση πρέπει να εκτυπώνεται ένα µήνυµα ώστε να ξέρει ο χρήστης γιατί τερµάτισε το πρόγραµµα. - Στη scanf για το όνοµα δεν πρέπει να έχετε & γιατί διαβάζετε string. - Σωστά κατά τα άλλα.
- Τι είναι το j και γιατί το χρησιµοποιείτε? Έχετε ήδη την epistrofh και ξέρετε ότι το loop πρέπει να συνεχίζει όσο αυτή δεν είναι VALID_ADDRESS οπότε γιατί να µπερδέψετε τον κώδικά σας µε µια µεταβλητή που το όνοµά της υπονοεί ότι πρόκειται για µετρητή loop κι ένα κατεβατό από if/else? Τελικά το πρόγραµµα δε λειτουργεί σωστά. Αν το λάθος είναι MISSING_DOT, τότε το πρώτο if (για το MISSING_AT) θα βγει false, οπότε το j θα γίνει 1 και το while θα τερµατίσει χωρίς να πρέπει. - Αντί να βάζετε το \0 και µετά strcat, θα ήταν πολύ πιο κοµψό να είχατε µόνο µια strcpy. - Η printf για το Name έπρεπε να είναι µέσα στο for. 1748 PASS - Σωστή η checkaddress αλλά προσέξτε τη µορφή του κώδικά σας. Αφήνετε πολλές κενές γραµµές και δε διαβάζεται εύκολα. - Σωστή χρήση malloc, αλλά µετά από κάθε κλήση σε αυτή πρέπει πάντα να ελέγχετε αν επέστρεψε NULL. - Αντί για scanf(formatstr, onoma); strcpy(a_ptr->shmeio, onoma); θα µπορούσατε να είχατε γράψει απευθείας scanf(formatstr, a_ptr->shmeio). - Σωστά κατά τα άλλα, αλλά προσέξτε τα ονόµατα των µεταβλητών/πεδίων σας. Δεν είναι καθόλου περιγραφικά και µερικές φορές παραπλανητικά (πχ το shmeio θα έπρεπε να είναι onoma) - Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. 1749 PASS - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα έσβησες? Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. - Σωστός κώδικας. Ο έλεγχος του αποτελέσµατος της συνάρτησης θα µπορούσε να είχε γίνει και µε switch. - Καλή δουλειά, µπράβο. - Στον έλεγχο για το αν η malloc επέστρεψε NULL, Αν ένα από τα ptr[i] είναι NULL θα πρέπει να γίνουν free τα προηγούµενα πριν το return.
1750 PASS - Καλή δουλειά. Να διαβάζετε πιο προσεκτικά την εκφώνηση/σχόλια: Οι έλεγχοι στην checkaddress έπρεπε να γίνονται µε διαφορετική σειρά. - Μετά από κάθε κλήση στη malloc πρέπει να ελέγχετε αν επέστρεψε NULL. - Σωστή η άσκηση κατά τα άλλα. - Στα προηγούµενα εργαστήρια είχατε σωστά κατασκευάσει format string για την ανάγνωση συµβολοσειρών. Γιατί χρησιµοποιήσατε το πολύ επικίνδυνο %s αυτή τη φορά? - Να διαβάζετε προσεκτικά την εκφώνηση. Η εκτύπωση των µηνυµάτων έπρεπε να γίνεται στη main µετά τον έλεγχο του αποτελέσµατος της συνάρτησης. Επίσης, στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνατε και το username. - Όλα σωστά κατά τα άλλα. 1751 PASS - Όταν ελέγχετε αν η malloc επέστρεψε NULL είναι πιο σωστό να το κάνετε ξεχωριστά για κάθε δείκτη. Για παράδειγµα, αν ο app1_ptr είναι οκ, αλλά ο app2_ptr είναι NULL, τότε πριν τερµατίσετε θα πρέπει να κάνετε free τον app1_ptr. Με τον τρόπο που το έχετε τώρα αυτό δε µπορεί να γίνει βολικά. - Δεν καλύπτετε την περίπτωση το minute_difference να είναι αρνητικό (πχ να έχετε 9:40 και 10:10). - Είναι γενικά προτιµότερο να χρησιµοποιείτε -> αντί για *. - Καλή δουλειά γενικά - Πολύ καλή δουλειά, µπράβο. ο έλεγχος του αποτελέσµατος της συνάρτησης θα µπορούσε να γίνει και µε switch. 1752 PASS - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα σβήσατε? - Σωστή χρήση malloc κι έλεγχοι. Αν το point2 είναι NULL πρέπει να κάνετε free το point1 πριν το return. Αντίστοιχα και για το point3. - Καλή δουλειά
1753 οριακό PASS - Όταν ορίζετε ένα struct να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή για να είναι πιο ξεκάθαρος ο κώδικας. - Προσέξτε τη στοίχιση. Είναι ασυνεπής (αλλού tab, αλλού κενό) και σε αρκετά σηµεία λάθος. - Θα µπορούσατε να είχατε ένα format string για κάθε περίπτωση και να καλέσετε τις δύο sprintf έξω από τα loops. Έτσι θα είχατε δύο µόνο κλήσεις της sprintf αντί για πολλαπλές µέσα στις επαναλήψεις. Έτσι κι αλλιώς το ίδιο πράγµα κατασκευάζεται κάθε φορά. - Ο έλεγχος του αποτελέσµατος της συνάρτησης θα µπορούσε να γίνει και µε switch. - Σωστή υλοποίηση της checkaddress, αλλά άσχηµα ονόµατα µεταβλητών. Δεν είναι καν απαραίτητα: µπορείτε να κάνετε όλους τους ελέγχους µέσα στις if. - Λείπει το \n στην τελική εκτύπωση. - Απαράδεκτα ονόµατα µεταβλητών! Ειδικά τα LA, LB είναι τραγικά (και τα κεφαλαία υπονοούν σταθερές). Οριακό pass γιατί σας έχουµε ξαναπεί να δίνετε καλύτερα ονόµατα. Περιµένουµε βελτίωση την επόµενη φορά. - Να ελέγχετε χωριστά για NULL σε κάθε malloc. Αν το p2 είναι NULL πρέπει να γίνει free το p1, κι αν το p3 είναι NULL πρέπει να γίνουν free τα p1, p2. Επίσης, σε κάθε περίπτωση πρέπει να εκτυπώνεται ένα µήνυµα ώστε να ξέρει ο χρήστης γιατί τερµάτισε το πρόγραµµα. - Στη scanf για το όνοµα δεν πρέπει να έχετε & γιατί διαβάζετε string. - Σωστά κατά τα άλλα.
- Σωστή υλοποίηση της checkpasswd - Προσοχή στη στοίχιση: οι δηλώσεις µεταβλητών στη main έπρεπε να ήταν ένα tab πιο δεξιά - Σωστή κατασκευή του format string. Θα ήταν καλύτερα η sprintf να βρισκόταν έξω από το loop ώστε να εκτελείται µόνο µια φορά κι όχι σε κάθε επανάληψη (άλλωστε το ίδιο format string κατασκευάζεται κάθε φορά) 1760 FAIL - Οι έλεγχοι του αποτελέσµατος της checkpasswd στη main θα µπορούσαν να είχαν γίνει και µε switch. - Γενικά καλά ονόµατα µεταβλητών, αλλά το πεδίο Onomata είναι παραπλανητικό. Το όνοµα ΕΝΟΣ χρήστης αποθηκεύεται σε αυτό. - Το τελευταίο else είναι λάθος. Σε εκείνο το σηµείο, µόλις έχετε οριστικοποιήσει το username και το password για ΕΝΑΝ χρήστη, και για την ακρίβεια για τον χρήστη στη θέση i. Εσείς τα αντιγράφετε σε όλες τις θέσεις του πίνακα χρηστών. Επιπλέον χρησιµοποιείτε πάλι i (παρόλο που το i ελέγχει και το εξωτερικό loop) κι έτσι "καταστρέφετε" την τιµή του. - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username. - Δεν έγινε - Να διαβάζετε πιο προσεκτικά την εκφώνηση και τα σχόλια: οι εκτυπώσεις των µηνυµάτων έπρεπε να γίνονται στη main. - Σωστή η checkpasswd αλλά θα ήταν πιο καθαρογραµµένος ο κώδικας αν κάνατε τις συγκρίσεις µέσα στις if. Δε χρειάζονταν τόσες "προσωρινές" µεταβλητές. 1761 PASS - Καλή δουλειά, µπράβο. - Αν το δεύτερο appointment είναι NULL, πρέπει να κάνετε free το πρώτο πριν τερµατίσετε τη main. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10).
- Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα σβήσατε? - Στην περίπτωση του @ είναι πιο κατάλληλη η χρήση strchr (αλλά δεν είναι λάθος αυτό που κάνατε). - Στην περίπτωση του dot έπρεπε να ελέγχετε αν εµφανίζεται τελεία οπουδήποτε µετά το @, Η χρήση strpbrk σε αυτή την περίπτωση είναι λάθος γιατί θα επιστρέψει non-null τιµή αν υπάρχει είτε @ είτε. σε κάποιο σηµείο του string. - Στην περίπτωση παράνοµων χαρακτήρων, θέλουµε να επιστραφεί ο κωδικός λάθος αν υπάρχουν αυτοί οι χαρακτήρες κι όχι αν δεν υπάρχουν. Εποµένως η σύγκριση έπρεπε να ήταν!= NULL 1762 FAIL - Το τελικό if στη συνάρτηση είναι περιττό. Αν δεν έχει ήδη επιστρέψει µέχρι αυτό το σηµείο, τότε προφανώς είναι όλα οκ και πρέπει να επιστραφεί VALID_ADDRESS - Παρόλο που δεν είναι λάθος το βασικό σας loop στη main, δέχεται αρκετές βελτιώσεις: -- Οι sprintf θα µπορούσαν να είναι εκτός του loop. Κάθε φορά κατασκευάζουν το ίδιο πράγµα, οπότε αρκεί να κληθούν µια φορά στην αρχή κι όχι σε κάθε µία επανάληψη. -- Αντί να κάνετε δύο φορές copy+paste τον κώδικα µε τους ελέγχους, θα µπορούσατε να είχατε χρησιµοποιήσει do-while (σκεφτείτε να είχαµε και περισσότερους από 3 ελέγχους) -- Αντί να καλείτε τέσσερις φορές την checkaddress µέσα στο for,θα έπρεπε να την καλείτε µια φορά, να αποθηκεύετε το αποτέλεσµά της σε µια µεταβλητή και µετά να κάνετε τους ελέγχους χρησιµοποιώντας τη µεταβλητή. Η κλήση συναρτήσεων έχει σχετικά µεγάλο κόστος στο χρόνο εκτέλεσης ενός προγράµµατος, οπότε δεν πρέπει να γίνεται άσκοπα. - Ο έλεγχος θα µπορούσε να γίνει και µε switch. - Δεν έγινε. - Πολύ καλή δουλειά, µπράβο. 1763 PASS - Στην checkpasswd θα ήταν πιο ευανάγνωστος ο κώδικας (ειδικά αν υπήρχαν περισσότερα είδη λαθών) αν κάνατε τους ελέγχους απευθείας στις if αντί να αποθηκεύετε το αποτέλεσµα σε µεταβλητές µε µη-περιγραφικά ονόµατα και µετά να ελέγχετε αυτές. Για παράδειγµα: if ( strstr(passwd, username)!= NULL) {... - Μετά από κάθε ένα malloc πρέπει να ελέγχετε αν επέστρεψε NULL - Πολύ καλή δουλειά κατά τα άλλα.
Όπως έχουµε αναφέρει ξανά, ΤΟ ΟΝΟΜΑ ΤΟΥ ΦΑΚΕΛΟΥ ΔΕΝ ΑΚΟΛΟΥΘΕΙ ΤΙΣ ΠΡΟΔΙΑΓΡΑΦΕΣ. - Καλή δουλειά γενικά. - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. 1764 PASS - Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνατε και το username. - Καλή δουλειά. - Σωστή χρήση malloc/free κι έλεγχος για NULL. Αν το datedetails2 είναι NULL, θα πρέπει να κάνετε free το datedetails1 πριν το return. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10). - Είναι καλύτερα να χρησιµοποιείτε -> αντί για *. 1765 οριακό PASS - Όταν δουλεύετε µε pointers να χρησιµοποιείτε NULL κι όχι 0. - Να διαβάζετε πιο προσεκτικά την εκφώνηση. Το πρόγραµµά σας δε διαβάζει σωστά τα δεδοµένα. Εσείς διαβάζετε πρώτα όλα τα ονόµατα και µετά όλες τις διευθύνσεις ενώ έπρεπε για κάθε ένα όνοµα να διαβάζετε και την αντίστοιχη διεύθυνση. Επίσης, οι εκτυπώσεις των µηνυµάτων λάθους έπρεπε να γίνονται στη main, όχι στην checkaddress. - Σωστή χρήση malloc, αλλά µετά από κάθε κλήση πρέπει να ελέγχετε αν επέστρεψε NULL. - Καλή δουλειά κατά τα άλλα.
- Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα έσβησες? Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. 1767 PASS - Δε διαβάσατε προσεκτικά την εκφώνηση και τα σχόλια: τα µηνύµατα λάθους έπρεπε να εκτυπώνονται στη main, όχι στη checkaddress. Επίσης, λείπει το \n από την τελική εκτύπωση. - Μετά από κάθε κλήση στη malloc πρέπει να ελέγχετε αν επέστρεψε NULL. - Μη χρησιµοποιείτε µεταβλητές µε όνοµα flag. Δεν είναι καθόλου περιγραφικό. Το κάνατε και στις δύο ασκήσεις. - Σωστή η άσκηση κατά τα άλλα.
- Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα αλλάξατε? Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. - Πολύ άσχηµη στοίχιση. Έχετε αλλού tabs κι αλλού κενά (spaces) και δεν είναι πάντα σωστά ευθυγραµµισµένες οι εντολές. - Σωστή υλοποίηση της checkaddress 1768 FAIL - Σωστή κατασκευή των format strings, και σωστά τα δηµιουργείτε µία µόνο φορά έξω από τη for. - Να διαβάζετε πιο προσεκτικά την εκφώνηση. Η εκτύπωση των περιεχοµένων του πίνακα έπρεπε να γίνεται µόνο αφού έχει ήδη γεµίσει ο πίνακας, κι όχι µετά από την ανάγνωση κάθε ονόµατος/email. - Λάθος στη συνθήκη της do-while. Έπρεπε να συνεχίζει όσο το αποτέλεσµα είναι διάφορο του VALID_ADDRESS, όχι όσο είναι ίσο. - Σωστός ο έλεγχος του αποτελέσµατος της συνάρτησης. Θα µπορούσατε να είχατε χρησιµοποιήσει και switch σε αυτό το σηµείο. Δεν έγινε.
Άσκηση 1 - Το πρόγραµµά σας έχει κάποια bugs τα οποία καταλήγουν στο να "σκάει" µε µήνυµα "pointer being freed was not allocated": ---Δεσµεύετε στην αρχή µνήµη για το database των χρηστών (το οποίο δεν ήταν απαραίτητο γιατί ξέρουµε το πλήθος τους από πριν, οπότε αρκούσε να χρησιµοποιήσετε στατικό πίνακα). Στη µνήµη αυτή δείχνουν δύο δείκτες, ο userdb και ο current. Μέσα στην additem καλείτε realloc στη µνήµη που δείχνει ο current, εποµένως δεσµεύετε νέα µνήµη και η παλιά απελευθερώνεται. Όταν τελειώσει το πρόγραµµα κάνετε free(userdb) το οποίο προσπαθεί να απελευθερώσει (για µια ακόµη φορά) την αρχική µνήµη. Γι αυτό βγαίνει το µήνυµα λάθους. Το σωστό θα ήταν να είχατε free(current) διότι ο current είναι αυτός που δείχνει πάντα στη σωστή µνήµη που έχετε τους χρήστες. --- Για τον ίδιο λόγο, θα έπρεπε στην τελική εκτύπωση να χρησιµοποιείτε current[i] και όχι userdb[i]. --- Όταν κάνετε realloc την πρώτη φορά, ζητάτε *count κελιά το οποίο είναι όσο το i, το οποίο είναι 0, εποµένως ζητάτε 0 bytes. Έπρεπε να είχατε (*count+1) 1769 PASS - Μη χρησιµοποιείτε "τυχαίες" τιµές για κωδικούς λάθους, γιατί µπερδεύουν τον αναγνώστη. Τι σηµαίνει -456 και τι διαφορά έχει από το -3409? Αρκούσε ένα exit(1) ή ένα #define για τον κωδικό MALLOC_ERROR και µετά να επιστρέφετε αυτό. - Σωστή χρήση sprintf για τη δηµιουργία format string. - Σωστή χρήση switch για τον έλεγχο του αποτελέσµατος της συνάρτησης. - Γενικά σωστή η τελική εκτύπωση, εκτός από το θέµα µε το userdb - Γενικά σωστή η additem εκτός από το θέµα µε το *count - Σωστή η checkspecial, αλλά θα ήταν πιο απλό να είχατε χρησιµοποιήσει την strpbrk. - Γενικά οκ, αλλά: --- Να κάνετε πάντα typecast το αποτέλεσµα της malloc --- Να ελέγχετε για NULL µετά από κάθε malloc --- Δεν καλύπτετε την περίπτωση που η διαφορά λεπτών είναι αρνητική (πχ 9:40 µε 10:10) --- Δεν κάνετε free
- Ο ορισµός του struct είναι κάπως κρυµµένος κάτω από το prototype. Τυπικά µπαίνει ανάµεσα στα #define και στα prototypes και έπρεπε να είναι ένα tab πιο αριστερά. - Σοβαρό λάθος στα loops: Βγαίνετε εκτός ορίων πίνακα γιατί το i πάει µέχρι και NUM_USERS Οµοίως, στη δηµιουργία του format string έπρεπε να είχατε STR_MAX_LEN-1 και όχι STR_MAX_LEN, για να υπάρχει και µία θέση για το \0. 1770 PASS - Η κλήση στην sprintf θα µπορούσε να ήταν έξω από το loop ώστε να εκτελείται µόνο µια φορά και όχι σε κάθε επανάληψη. Έτσι κι αλλιώς, το ίδιο πράγµα κατασκευάζεται κάθε φορά. - Να διαβάζετε πιο προσεκτικά την εκφώνηση και τα σχόλια. Οι εκτυπώσεις έπρεπε να γίνονται στη main κι όχι µέσα στη συνάρτηση. Σκοπός της συνάρτησης ήταν αποκλειστικά ο έλεγχος και η επιστροφή του κωδικού. - Να χρησιµοποιείτε NULL και όχι 0 όταν δουλεύετε µε pointers. - Να κάνετε πάντα typecast το αποτέλεσµα της malloc και να ελέγχετε για κάθε κλήση της malloc αν επεστράφη NULL - Ο υπολογισµός της διαφοράς ώρας δε γίνεται σωστά: δε λαµβάνετε υπόψη την περίπτωση που η diaflepta είναι αρνητική (πχ αν οι ώρες είναι 9:40, 10:10) - Κατά τα άλλα σωστά. - Πολύ καλή δουλειά, µπράβο. 1772 PASS - Στην checkpasswd θα ήταν πιο ευανάγνωστος ο κώδικας (ειδικά αν υπήρχαν περισσότερα είδη λαθών) αν κάνατε τους ελέγχους απευθείας στις if αντί να αποθηκεύετε το αποτέλεσµα σε µεταβλητές µε µη-περιγραφικά ονόµατα και µετά να ελέγχετε αυτές. Για παράδειγµα: if ( strstr(passwd, username)!= NULL) {... - Μετά από κάθε ένα malloc πρέπει να ελέγχετε αν επέστρεψε NULL - Πολύ καλή δουλειά κατά τα άλλα.
- Όταν ορίζετε ένα struct να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή για να είναι πιο ξεκάθαρος ο κώδικας. - Τυπικά, γράφουµε το πρότυπο (prototype) της συνάρτησης πάνω από τη main, και την υλοποίηση µετά τη main, ακριβώς όπως στον έτοιµο κώδικα που σας δώσαµε. - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα έσβησες? Τα σχόλια των συναρτήσεών σας πρέπει να είναι πάντα σαν αυτά που σας δώσαµε και όπως περιγράφονται στο φυλλάδιο για το σχολιασµό προγραµµάτων. 1774 PASS - Το µέγεθος του format string δεν έχει ΚΑΜΙΑ σχέση µε το MAX_NAME_LEN. Αντιθέτως, εξαρτάται από το τι θα περιέχει (το %, το πολύ 10 ψηφία για έναν ακέραιο, το s και το \0). - Σωστή η χρήση switch, αλλά οι εντολές για κάθε περίπτωση πρέπει να είναι σε ξεχωριστές γραµµές για να είναι ευανάγνωστος ο κώδικας. - Καλή δουλειά γενικά, αλλά θα έπρεπε να είχατε το 10 ορισµένο ως σταθερά. Επίσης, αν τα ptr2, ptr3 είναι NULL, τότε πρέπει να απελευθερωθεί η ήδη δεσµευµένη µνήµη πριν το return. - Πολύ καλή δουλειά, µπράβο. ο έλεγχος του αποτελέσµατος της συνάρτησης θα µπορούσε να γίνει και µε switch. 1775 PASS - Σας δώσαµε σωστά και πλήρη σχόλια για τη συνάρτηση. Γιατί τα σβήσατε? - Σωστή χρήση malloc κι έλεγχοι. Αν το point2 είναι NULL πρέπει να κάνετε free το point1 πριν το return. Αντίστοιχα και για το point3. - Καλή δουλειά
- Να διαβάζετε πιο προσεκτικά την εκφώνηση και τα σχόλια: οι εκτυπώσεις των µηνυµάτων έπρεπε να γίνονται στη main. - Σωστή η checkpasswd αλλά θα ήταν πιο καθαρογραµµένος ο κώδικας αν κάνατε τις συγκρίσεις µέσα στις if. Δε χρειάζονταν τόσες "προσωρινές" µεταβλητές. 1776 PASS - Καλή δουλειά, µπράβο. - Αν το δεύτερο appointment είναι NULL, πρέπει να κάνετε free το πρώτο πριν τερµατίσετε τη main. - Δεν καλύπτετε την περίπτωση η διαφορά λεπτών να είναι αρνητική (πχ να έχετε 9:40 και 10:10). - Όταν ορίζετε ένα struct να βάζετε κάθε πεδίο σε ξεχωριστή γραµµή για να είναι πιο ξεκάθαρος ο κώδικας. - Να διαβάζετε πιο προσεκτικά την εκφώνηση και τα σχόλια που σας δίνουµε. Η εκτύπωση των µηνυµάτων λάθους έπρεπε να γίνεται στη main κι όχι στην checkaddress. - Δεν εκτυπώνετε στο τέλος τα περιεχόµενα του πίνακα. 1777 PASS - Κάπως µπερδεµένη η λογική σας στην checkaddress. Θα ήταν πιο κατανοητός ο κώδικας αν είχατε κάθε έλεγχο χωριστά, κι όχι σε εµφωλευµένα if: if ((has_at = strchr(address, '@'))==NULL) return MISSING_AT; if (strchr(has_at, '.') == NULL) return MISSING_DOT; if (strpbrk(address, ILLEGAL_CHARS)!=NULL) return HAS_ILLEGAL_CHARS; return VALID_ADDRESS; - Όταν χρησιµοποιείτε malloc πρέπει πάντα να κάνετε το κατάλληλο typecast και οπωσδήποτε να ελέγχετε αν επεστράφη NULL. - Σωστά κατά τα άλλα.
- Σωστή λειτουργία. Καλή δουλειά γενικά. - Προσοχή στην έξοδο. Στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε και το username και στην τελική εκτύπωση ξεχάσατε το χαρακτήρα αλλαγής γραµµής.. 1781 PASS - Στη συνάρτηση θα µπορούσατε να είχατε κάνει τους ελέγχους απευθείας στην if αντί να αποθηκεύετε το αποτέλεσµα σε µεταβλητή (και µάλιστα µη-περιγραφική). Θα ήταν πιο καθαρός ο κώδικας έτσι, ειδικά αν υπήρχαν και περισσότεροι έλεγχοι. Για παράδειγµα: if (strstr(passwd, username)!= NULL) {... - Στον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει switch. - Αν η malloc επιστρέψει NULL, είναι καλό να εκτυπώνετε κι ένα µήνυµα λάθους προς τον χρήστη. - Πολύ σωστά, µπράβο. - Σωστή λειτουργία της checkpasswd, αλλά δεν είναι καλογραµµένη: έπρεπε για τις τιµές που επιστρέφει να είχατε χρησιµοποιήσει τις σταθερές για να είναι πιο κατανοητός ο κώδικας. Επίσης, γιατί σβήσατε τα σχόλια της συνάρτησης? - Πολύ άσχηµο όνοµα πίνακα στη main. Να µη χρησιµοποιείτε ποτέ ονόµατα του ενός γράµµατος για οτιδήποτε εκτός από µετρητές for. 1782 FAIL - Σωστή χρήση sprintf για την κατασκευή format string. Θα ήταν προτιµότερο να είχατε την sprintf έξω από το loop ώστε να εκτελείται µόνο µια φορά κι όχι σε κάθε επανάληψη (έτσι κι αλλιώς, πάντα το ίδιο πράγµα κατασκευάζει). Επίσης, αρκεί µια sprintf εφόσον τα format string είναι ίδια για όλα τα strings του προγράµµατος. - Για τον έλεγχο του αποτελέσµατος της συνάρτησης θα µπορούσατε να είχατε χρησιµοποιήσει και switch. - Δεν έγινε.
1784 οριακό PASS - Σωστή υλοποίηση της checkaddress - Σωστή δηµιουργία format string για την ανάγνωση των συµβολοσειρών. Καλό θα ήταν να είχατε δύο διαφορετικά format string (ένα για τα ονόµατα ένα για τις διευθύνσεις) και να βάζατε τις sprintf έξω από το for ώστε κάθε µία να εκτελείται µία φορά κι όχι σε κάθε επανάληψη. - Η συνθήκη τερµατισµού της while δεν είναι πολύ ξεκάθαρη. Εφόσον θέλουµε να εκτελείται όσο δεν είναι έγκυρη η διεύθυνση, θα ήταν πιο σωστό να είχατε χρησιµοποιήσει τη σταθερά VALID_ADDRESS κι όχι το 1. - Σωστός έλεγχος του αποτελέσµατος της checkaddress. Θα µπορούσατε να είχατε χρησιµοποιήσει και switch σε αυτό το σηµείο. - Σωστή εκτύπωση των περιεχοµένων του πίνακα - Δεν κάνει compile. Έπρεπε να είχατε χρησιµοποιήσει -> και όχι. για την προσπέλαση των πεδίων. Επίσης, όταν διαβάζετε ακεραίους (πχ. ptr_3->x) θα έπρεπε να είχατε %d στη scanf και φυσικά & πριν τις µεταβλητές (δηλαδή &(ptr_3->x). - Άσχηµα ονόµατα µεταβλητών. - Μετά από κάθε µία malloc θα έπρεπε να ελέγχατε αν απέτυχε (αν επέστρεψε NULL) και σε αυτή την περίπτωση να απελευθερώνετε ότι δυναµικά δεσµευµένη µνήµη υπάρχει και να τερµατίζετε. - Σωστή απελευθέρωση µνήµης στο τέλος.
- Σωστή λειτουργία, αλλά στο µήνυµα "Includes username" έπρεπε να εµφανίζεται το username στη θέση του s. - Στη συνάρτηση checkpasswd θα ήταν πιο κατανοητός ο κώδικας (και λιγότερο πιθανό να γίνει λάθος) αν είχατε τις κλήσεις στις strlen, κτλ κατευθείαν µέσα στις if και όχι πιο πριν και αποθηκευµένα τα αποτελέσµατα σε µη-περιγραφικά ονόµατα µεταβλητών (τι διαφορά έχει το found από το found1? Αν είχαµε κι άλλους ελέγχους, πόσα found θα φτιάχνατε?) - Να διαβάζετε προσεκτικά την εκφώνηση και τα σχόλια. Οι printf έπρεπε να είναι στη main. Σκοπός της συνάρτησης ήταν ΜΟΝΟ ο έλεγχος και η επιστροφή κατάλληλου κωδικού. 1785 PASS - Σωστή χρήση sprintf για τη δηµιουργία format string - Στη main έπρεπε να ελέγχετε το αποτέλεσµα της συνάρτησης χρησιµοποιώντας τον κατάλληλο κωδικό (VALID_PASSWD κι όχι 1) - Προσοχή στη στοίχιση. Το do-while έπρεπε να είναι ένα tab πιο µέσα. - Compile µε warnings - Όταν χρησιµοποιείτε malloc να κάνετε #include το stdlib.h - Μετά από κάθε µία malloc πρέπει να ελέγχετε πάντα αν επέστρεψς NULL. - Στη scanf, όταν διαβάζετε ακέραιες τιµές έπρεπε να είχατε και & πριν την αντίστοιχη µεταβλητή. - Δεν καλύπτετε την περίπτωση που η διαφορά λεπτών είναι αρνητική (πχ 9:40 µε 10:10) - Σωστό το free.
- Σωστή λειτουργία της checkpasswd, αλλά ως συνάρτηση δεν είναι πολύ καλογραµµένη. Αντί να χρησιµοποιείτε τις µεταβλητές prwto_lathos, deutero_lathos κτλ, τα ονόµατα των οποίων δε δίνουν καµία πληροφορία για το τι εννοούν, θα ήταν καλύτερα να έχετε απευθείας το κατάλληλο return µετά από κάθε έλεγχο. Έτσι, ο αναγνώστης θα έβλεπε άµεσα τι επιστρέφει η συνάρτηση σε κάθε περίπτωση, αντί να χρειάζεται να διαβάσει πιο κάτω. Για παράδειγµα, if (strstr(passwd, username)!= NULL) { return INCLUDES_USERNAME; } Επίσης, µε αυτές τις µεταβλητές είναι πολύ πιο εύκολο να γίνει λάθος από τον προγραµµατιστή (δηλαδή να µην επιστρέψει τη σωστή τιµή σε κάποια περίτπωση επειδή πχ µπέρδεψε πού αντιστοιχεί το deutero_lathos. - Σωστή δηµιουργία format string για την ανάγνωση συµβολοσειρών. 1790 PASS - Καλά ονόµατα µεταβλητών εκτός από το k. Θα µπορούσατε να το είχατε πει errorcode. Εναλλακτικά (και πιο κοµψά) θα µπορούσατε να είχατε χρησιµοποιήσει switch ως εξής: switch ( checkpasswd(elegxos_passwd, xrhstes[i].username) ) { case TOO_SHORT: printf(...) κτλ. - Στην τελική εκτύπωση των περιεχοµένων του πίνακα δεν έχετε χαρακτήρα αλλαγής γραµµής µετά από κάθε password. Επίσης, στην περίπτωση INCLUDES_USERNAME έπρεπε να εκτυπώνετε το username στη θέση του s κι όχι το γράµµα s. - Στην περίπτωση που αποτυγχάνει η malloc έπρεπε να εκτυπώνετε κι ένα µήνυµα προς τον χρήστη για να γνωρίζει γιατί τερµάτισε το πρόγραµµα. Επίσης, οι έλεγχοι για NULL έπρεπε να γίνονται χωριστά. Αν πετύχει το malloc για το radevou1 αλλά αποτύχει αυτό για το radevou2, τότε θα πρέπει να κάνετε πρώτα free το radevou1 πριν τερµατίσει το πρόγραµµα. - Αντί για *. είνα γενικά προτιµότερο (και πιο ξεκάθαρο) να χρησιµοποιείτε -> - Σωστός υπολογισµός διαφοράς ώρας.