Στόχοι: μετά από αυτό το κεφάλαιο θα μπορείτε να
- σχεδιάζετε έναν βρόχο είτε «φιλτράροντας» όλες τις τιμές με
ifείτε διαλέγοντας κατάλληλη αρχή και βήμα·- αναγνωρίζετε πότε ένα γινόμενο ή άθροισμα σε βρόχο ξεπερνά τα όρια του
int·- σταματάτε έναν βρόχο νωρίς, με μεταβλητή-σημαία ή με
break·- παραλείπετε μια επανάληψη με
continue·- γράφετε μια
switchαντί για μια αλυσίδαelse if, μεcase,defaultκαιbreak, και ομαδοποιείτε πολλάcase·- εξηγείτε τι κάνει η
gotoκαι γιατί ο δομημένος προγραμματισμός την αποφεύγει.Προαπαιτούμενα: Κεφάλαιο 6, Κεφάλαιο 7
Χρόνος μελέτης: ~1,5 ώρα
Στο Κεφάλαιο 6 είδαμε την if και τους τρεις βρόχους της C.
Εδώ τους χρησιμοποιούμε σε μικρά προβλήματα με τριψήφιους αριθμούς και βλέπουμε τις
υπόλοιπες δομές ελέγχου της γλώσσας. Η break τερματίζει αμέσως έναν βρόχο και η
continue προχωρά στην επόμενη επανάληψη· και οι δύο αντικαθιστούν τις
μεταβλητές-σημαίες που θα χρειαζόμασταν αλλιώς. Η switch είναι ένας πιο καθαρός
τρόπος να γράψουμε μια αλυσίδα else if που συγκρίνει μια ακέραια τιμή με σταθερές.
Τέλος, η goto μεταφέρει την εκτέλεση σε μια ετικέτα· υπάρχει στη γλώσσα, αλλά ο
δομημένος προγραμματισμός (και αυτό το μάθημα) μας λέει να μην τη χρησιμοποιούμε.
Η διάλεξη ξεκίνησε με ένα ερώτημα: ένας βρόχος πολλαπλασιάζει στο prod όλους τους
τριψήφιους περιττούς που διαιρούνται με το 7 (105, 119, …, 987), και το πρόγραμμα
τυπώνει έναν αρνητικό αριθμό, -1187656959. Τι συμβαίνει;
Ο βρόχος πολλαπλασιάζει 64 αριθμούς, ο καθένας μεγαλύτερος από 100, άρα το σωστό
αποτέλεσμα ξεπερνά το \(10^{128}\). Ένας int των 32 bit χωράει μέχρι
\(2^{31} - 1 = 2147483647\) (περίπου \(2 \cdot 10^9\)), όριο που το γινόμενο ξεπερνά ήδη
στον πέμπτο παράγοντα. Αυτό λέγεται υπερχείλιση (overflow). Στην πράξη κρατιούνται
μόνο τα χαμηλά 32 bit, η τιμή «τυλίγεται» και μπορεί να βγει αρνητική· για
προσημασμένους ακεραίους όμως η C τη χαρακτηρίζει απροσδιόριστη συμπεριφορά
(undefined behavior), οπότε δεν βασιζόμαστε σε κανένα αποτέλεσμα. Όταν ένας βρόχος
συσσωρεύει γινόμενο ή μεγάλο άθροισμα, εκτιμήστε πρώτα πόσο μεγάλο θα βγει. Ο
long long (64 bit, περίπου έως \(9 \cdot 10^{18}\)) μεταθέτει το όριο, αλλά εδώ δεν
αρκεί ούτε αυτός. Για τους τύπους και τα όριά τους δείτε το
Κεφάλαιο 2.
Για το ίδιο πρόβλημα («το γινόμενο όλων των τριψήφιων περιττών που διαιρούνται με το 7») οι διαφάνειες δίνουν δύο λύσεις, που δείχνουν δύο γενικές στρατηγικές.
if μόνο
όσες ικανοποιούν τη συνθήκη (εδώ i % 7 == 0). Είναι απλό και δύσκολα κάνει
λάθος, αλλά ελέγχει πολλές τιμές που θα απορριφθούν.i = 105; i <= 999; i += 14, χωρίς καμία if.Η δεύτερη λύση κάνει 64 επαναλήψεις αντί για 450, αλλά απαιτεί σκέψη πριν από τον
κώδικα: αν η αρχή ή το βήμα είναι λάθος, ο βρόχος περνά από λάθος τιμές χωρίς
κανένα σημάδι. Π.χ. στην πρώτη λύση των διαφανειών το i ξεκινά από το 100 με
βήμα 2, οπότε περνά από τους άρτιους τριψήφιους (100, 102, …)· για τους
περιττούς η αρχή πρέπει να είναι 101. Ελέγχετε πάντα με το χέρι τις πρώτες τιμές
που παίρνει η μεταβλητή του βρόχου. Και οι δύο βρόχοι χρησιμοποιούν τον τελεστή
κόμμα στην αρχικοποίηση (prod = 1, i = 105) για να αρχικοποιήσουν δύο μεταβλητές.
Δεύτερο πρόβλημα: να τυπωθεί (αν υπάρχει) ο μικρότερος τριψήφιος που είναι
πολλαπλάσιο του 2 και του 5 αλλά όχι του 4. Ένας βρόχος από το 100 ως το 999 με
τη συνθήκη i % 2 == 0 && i % 5 == 0 && i % 4 != 0 βρίσκει τον σωστό αριθμό, αλλά
δεν σταματά εκεί: τυπώνει όλους όσους την ικανοποιούν (110, 130, 150, …). Το
ζητούμενο όμως είναι ένας μόνο αριθμός.
Η πρώτη λύση είναι μια μεταβλητή-σημαία (flag): μια ακέραια μεταβλητή found
που ξεκινά από 0 και γίνεται 1 όταν βρούμε τον αριθμό. Την προσθέτουμε στη συνθήκη
του βρόχου, i < 1000 && !found, οπότε μόλις γίνει 1 ο επόμενος έλεγχος αποτυγχάνει
και ο βρόχος τελειώνει. Η σημαία χρησιμεύει και μετά τον βρόχο: αν έμεινε 0, δεν
υπήρχε τέτοιος αριθμός (το «αν υπάρχει» της εκφώνησης). Το κόστος είναι μια επιπλέον
μεταβλητή και ένας έλεγχος ακόμα (αφού εκτελεστεί πρώτα το i++). Η C προσφέρει
έναν πιο άμεσο τρόπο για το ίδιο αποτέλεσμα.
Η εντολή break (break statement) τερματίζει αμέσως τον βρόχο μέσα στον οποίο
βρίσκεται. Η εκτέλεση συνεχίζει με την πρώτη εντολή μετά το σώμα του βρόχου·
ό,τι απομένει στο σώμα, το βήμα της for και ο έλεγχος της συνθήκης παραλείπονται.
Η break λειτουργεί με τον ίδιο τρόπο στη while, στη do-while και στη for.
flowchart TD
A(["αρχή βρόχου"]) --> C{"συνθήκη;"}
C -- "αληθής" --> S1["εντολές σώματος"]
S1 --> B{"if (...) break;"}
B -- "όχι" --> S2["υπόλοιπες εντολές"]
S2 --> C
B -- "ναι: break" --> E(["επόμενη εντολή μετά τον βρόχο"])
C -- "ψευδής" --> E
Σχήμα: η break βγάζει την εκτέλεση από τον βρόχο αμέσως, χωρίς νέο έλεγχο της συνθήκης.
Συνήθως η break βρίσκεται μέσα σε μια if: «αν βρήκαμε αυτό που ψάχνουμε, σταμάτα».
Έτσι ο βρόχος έχει δύο εξόδους: την κανονική (η συνθήκη έγινε ψευδής) και την
πρόωρη. Προσέξτε ότι η break βγαίνει μόνο από τον πιο εσωτερικό βρόχο (ή
switch) που την περιέχει· σε εμφωλευμένους βρόχους ο εξωτερικός συνεχίζει κανονικά.
Η εντολή continue (continue statement) διακόπτει την τρέχουσα επανάληψη του
βρόχου και προχωρά στην επόμενη. Οι εντολές του σώματος που ακολουθούν την
continue παραλείπονται, αλλά ο βρόχος δεν τελειώνει: στη while και στη
do-while η εκτέλεση πηγαίνει στον έλεγχο της συνθήκης, ενώ στη for εκτελείται
πρώτα το βήμα (π.χ. i++) και μετά ο έλεγχος. Όπως και η break, δουλεύει σε
while, do-while και for.
flowchart TD
I["i = 100"] --> C{"i #lt; 1000;"}
C -- "αληθής" --> T{"i % 5 == 0;"}
T -- "ναι: continue" --> U["i++"]
T -- "όχι" --> P["printf(i)"]
P --> U
U --> C
C -- "ψευδής" --> E(["τέλος βρόχου"])
Σχήμα: σε μια for, η continue πηγαίνει στο βήμα i++ και όχι έξω από τον βρόχο.
Η continue βοηθά να «πετάμε» νωρίς τις περιπτώσεις που δεν μας ενδιαφέρουν· το
ίδιο γίνεται και με μια if με την αντίθετη συνθήκη.
Ένα συχνό μοτίβο είναι μια αλυσίδα else if που συγκρίνει την ίδια έκφραση με
διαδοχικές σταθερές: «αν number == 0 τύπωσε zero, αλλιώς αν number == 1 τύπωσε
one, …». Η εντολή switch (switch statement) είναι η εναλλακτική της δομής
if-else-if γι’ αυτή την περίπτωση: ελέγχει μία έκφραση για τις δυνατές τιμές της
και χειρίζεται κάθε περίπτωση διαφορετικά. Η γενική μορφή:
switch (έκφραση) {
case σταθερά1:
εντολές
case σταθερά2:
εντολές
...
default:
εντολές
}
Υπολογίζεται μία φορά η τιμή της έκφρασης. Αν είναι ίση με τη σταθερά κάποιου
case, η εκτέλεση μεταπηδά στις εντολές μετά από αυτό το case· αλλιώς
μεταπηδά στο default. Το default είναι προαιρετικό: αν λείπει και δεν ταιριάζει
κανένα case, η εκτέλεση συνεχίζει μετά τη switch. Οι εντολές ενός case δεν
χρειάζονται αγκύλες.
Το κρίσιμο σημείο είναι ότι τα case είναι απλώς σημεία εισόδου, όχι χωριστά
blocks. Αφού η εκτέλεση μπει σε ένα case, συνεχίζει προς τα κάτω, περνώντας και
στις εντολές των επόμενων case, μέχρι να βρει break ή το τέλος της switch.
Αυτό λέγεται πτώση (fall-through). Γι’ αυτό κάθε ομάδα εντολών κλείνει με
break: η break ολοκληρώνει την εκτέλεση της switch και η ροή συνεχίζει μετά
την κλειστή αγκύλη της. Είναι η ίδια break με αυτή των βρόχων, με δεύτερη χρήση.
flowchart TD
S{"switch (number)"} -- "0" --> A["printf zero"]
S -- "1" --> B["printf one"]
S -- "άλλη τιμή" --> D["default: printf unknown"]
A --> BA["break"]
B --> BB["break"]
D --> BD["break"]
BA --> E(["μετά τη switch"])
BB --> E
BD --> E
A -. "χωρίς break: πτώση" .-> B
Σχήμα: η switch μεταπηδά στο case που ταιριάζει· χωρίς break η εκτέλεση «πέφτει» στο επόμενο.
Το break στο τελευταίο default δεν αλλάζει τίποτα, αλλά το βάζουμε για
ομοιομορφία και για ασφάλεια αν αργότερα προστεθεί case από κάτω.
Η πτώση έχει και μια χρήσιμη εφαρμογή: πολλά case μαζί. Γράφουμε τα case
το ένα κάτω από το άλλο, χωρίς εντολές ανάμεσα (case 12: case 1: case 2:), και
βάζουμε τις κοινές εντολές και ένα break μετά το τελευταίο. Για τιμή 12, 1 ή 2 η
εκτέλεση μπαίνει σε κάποιο από τα τρία σημεία και πέφτει στις κοινές εντολές. Εκτός
από αυτή την περίπτωση, οι σημειώσεις θεωρούν κακή πρακτική να πέφτει ένα case
στο επόμενο.
Η switch είναι λιγότερο γενική από την αλυσίδα else if:
case ελέγχεται μόνο ισότητα (==). Δεν γράφονται άλλες λογικές
συνθήκες (π.χ. >, <)· για διαστήματα τιμών χρειαζόμαστε if.switch και η σταθερά κάθε case πρέπει να είναι ακέραιες
(ένα double δεν επιτρέπεται, ένα char όπως 'a' επιτρέπεται). Οι σημειώσεις
προσθέτουν ότι στα case μπαίνουν σταθερές, όχι μεταβλητές, και ότι δύο case
δεν μπορούν να έχουν την ίδια σταθερά.Η εντολή goto (goto statement) μεταφέρει την εκτέλεση του προγράμματος σε άλλη
εντολή της ίδιας συνάρτησης, με την προϋπόθεση ότι η εντολή αυτή έχει μια
ετικέτα (label). Η ετικέτα είναι ένα όνομα ακολουθούμενο από άνω-κάτω τελεία,
μπροστά από μια εντολή:
goto label;
...
label:
Μετά την goto label; εκτελείται η εντολή μετά το label:, πιο πάνω ή πιο κάτω
στη συνάρτηση. Έτσι μπορούμε π.χ. να βγούμε από έναν βρόχο πηδώντας σε μια ετικέτα
αμέσως μετά από αυτόν. Οι σημειώσεις αναφέρουν ως εξειδικευμένη χρήση την έξοδο από
εμφωλευμένους βρόχους μονομιάς, που η break δεν κάνει. Μια ετικέτα πρέπει να
ακολουθείται από εντολή· στο τέλος ενός block βάζουμε την κενή εντολή ;.
Ο δομημένος προγραμματισμός (structured programming) φτιάχνει τα προγράμματα
μόνο από ακολουθία, επιλογή (if, switch) και επανάληψη (βρόχους). Η goto
σπάει αυτή την ιδέα: η εκτέλεση πηδά οπουδήποτε στη συνάρτηση, οπότε για να
καταλάβετε μια γραμμή πρέπει να ξέρετε κάθε goto που οδηγεί σε αυτήν. Το
αποτέλεσμα είναι δυσνόητος κώδικας-μακαρονάδα (spaghetti code), χρήσιμος μόνο σε
διαγωνισμούς δυσνόητου κώδικα (obfuscation contests, όπως ο IOCCC). Το επιχείρημα
έγινε γνωστό με το άρθρο του Edsger Dijkstra Go To Statement Considered Harmful.
Η απάντηση της διάλεξης στο «να χρησιμοποιήσω goto;» είναι σκέτο ΟΧΙ: μπορεί
κανείς να γράψει εκατομμύρια γραμμές κώδικα χωρίς να τη χρειαστεί. Στο πλαίσιο
αυτού του μαθήματος, σύμφωνα με τις σημειώσεις, η χρήση της απαγορεύεται.
Αναδιοργανώστε τη ροή με break, continue, μια σημαία ή μια συνάρτηση.
Εφαρμόζει: «Δύο τρόποι να διατρέξουμε τις τιμές», «Υπερχείλιση σε βρόχους που πολλαπλασιάζουν». Οι δύο βρόχοι των διαφανειών, σε ένα πρόγραμμα:
#include <stdio.h>
int main(int argc, char **argv) {
int product, prod, i;
// Τρόπος 1: φιλτράρισμα με if
// (με αρχή 100 και βήμα 2 περνάμε από τους άρτιους· για περιττούς: 101)
for (product = 1, i = 100; i <= 999; i += 2) {
if (i % 7 == 0)
product *= i;
}
// Τρόπος 2: αρχή 105 = 15 * 7, βήμα 14 = 2 * 7
for (prod = 1, i = 105; i <= 999; i += 14) {
prod *= i;
}
printf("%d\n", prod);
return 0;
}
Η έξοδος που έδειξε η διάλεξη:
$ ./prod
-1187656959
Ένας αρνητικός αριθμός από γινόμενο θετικών είναι το χαρακτηριστικό σύμπτωμα της
υπερχείλισης: το σωστό αποτέλεσμα έχει πάνω από 128 ψηφία. Δοκιμάστε να τυπώνετε το
prod σε κάθε επανάληψη για να δείτε σε ποιο βήμα «σπάει». (Ο τρόπος 1, όπως είναι
γραμμένος, πολλαπλασιάζει άρτιους αριθμούς και υπερχειλίζει κι αυτός.)
Εφαρμόζει: «Πρόωρος τερματισμός με μεταβλητή-σημαία», «Η εντολή break», «Η εντολή goto και οι ετικέτες». Το πρόβλημα είναι να τυπωθεί ο μικρότερος τριψήφιος που είναι πολλαπλάσιο του 2 και του 5 αλλά όχι του 4. Η πρώτη απόπειρα των διαφανειών:
for (i = 100; i < 1000; i++) {
if (i % 2 == 0 && i % 5 == 0 && i % 4 != 0) {
printf("%d\n", i);
}
}
«Υπάρχει κάποιο θέμα με αυτή την υλοποίηση;» Ναι: τυπώνει όλους τους 45 τέτοιους αριθμούς (110, 130, …, 990), όχι μόνο τον μικρότερο. Δύο διορθώσεις, σε ένα πρόγραμμα:
#include <stdio.h>
int main(int argc, char **argv) {
int i;
// 1. Με μεταβλητή-σημαία στη συνθήκη
int found = 0;
for (i = 100; i < 1000 && !found; i++) {
if (i % 2 == 0 && i % 5 == 0 && i % 4 != 0) {
printf("%d\n", i);
found = 1;
}
}
// 2. Με break
for (i = 100; i < 1000; i++) {
if (i % 2 == 0 && i % 5 == 0 && i % 4 != 0) {
printf("%d\n", i);
break;
}
}
return 0;
}
$ ./smallest
110
110
Η τρίτη εκδοχή των διαφανειών χρησιμοποιεί goto σε μια ετικέτα αμέσως μετά τον
βρόχο. Τη δείχνουμε μόνο για να την αναγνωρίζετε· στο μάθημα δεν επιτρέπεται:
for (i = 100; i < 1000; i++) {
if (i % 2 == 0 && i % 5 == 0 && i % 4 != 0) {
printf("%d\n", i);
goto exit_for;
}
}
exit_for:
;
Η έκδοση με break είναι η πιο σύντομη και λέει καθαρά την πρόθεση. Προσέξτε μια
λεπτή διαφορά: μετά τον βρόχο με σημαία το i είναι 111 (έγινε ένα i++ ακόμα),
ενώ μετά την break είναι 110.
Εφαρμόζει: «Η εντολή continue». Όταν το i διαιρείται με το 5, η continue
παραλείπει το printf και η for προχωρά στο i++:
for (i = 100; i < 1000; i++) {
if (i % 5 == 0) {
continue;
}
printf("%d\n", i);
}
Τυπώνονται 101, 102, 103, 104, 106, … : 720 αριθμοί συνολικά (900 τριψήφιοι μείον
180 πολλαπλάσια του 5). Ισοδύναμα θα γράφαμε if (i % 5 != 0) printf(...).
Εφαρμόζει: «Η εντολή switch». Με αλυσίδα else if, όπως στις διαφάνειες:
if (number == 0)
printf("zero\n");
else if (number == 1)
printf("one\n");
....
else if (number == 9)
printf("nine\n");
else
printf("unknown\n");
Όλες οι συνθήκες συγκρίνουν το ίδιο number με σταθερές, άρα ταιριάζει η switch.
Το πλήρες πρόγραμμα (οι διαφάνειες παραλείπουν τα case 2 ως 8):
#include <stdio.h>
int main(int argc, char **argv) {
for (int number = -1; number <= 10; number++) {
switch (number) {
case 0: printf("zero\n"); break;
case 1: printf("one\n"); break;
case 2: printf("two\n"); break;
case 3: printf("three\n"); break;
case 4: printf("four\n"); break;
case 5: printf("five\n"); break;
case 6: printf("six\n"); break;
case 7: printf("seven\n"); break;
case 8: printf("eight\n"); break;
case 9: printf("nine\n"); break;
default: printf("unknown\n"); break;
}
}
return 0;
}
Τυπώνει unknown, μετά zero ως nine και ξανά unknown για το 10. Αν σβήσετε το
break του case 8, για number == 8 θα τυπωθούν eight και nine: η εκτέλεση
πέφτει στο επόμενο case.
Εφαρμόζει: «Πολλά case μαζί και περιορισμοί της switch». Οι διαφάνειες δείχνουν χειμώνα, άνοιξη και καλοκαίρι· εδώ έχει προστεθεί και το φθινόπωρο:
switch (month) {
case 12: case 1: case 2:
printf("winter\n");
break;
case 3: case 4: case 5:
printf("spring\n");
break;
case 6: case 7: case 8:
printf("summer\n");
break;
case 9: case 10: case 11:
printf("autumn\n");
break;
default:
printf("unknown month\n");
break;
}
Εδώ η switch είναι φυσική επιλογή: ο μήνας είναι ακέραιος και κάθε περίπτωση είναι
ισότητα με σταθερά. Αν όμως θέλατε «χειμώνας αν month <= 2», η switch δεν
μπορεί να το εκφράσει· θα χρειαζόταν if.
Στο Εργαστήριο 3, η άσκηση
birthdate.c βρίσκει την ημέρα της εβδομάδας από το IDAY % 7 (0 για Saturday, 1
για Sunday, …, 6 για Friday): το ίδιο μοτίβο με το όνομα ψηφίου, άρα καλή ευκαιρία
για switch.
int· ένα
αρνητικό αποτέλεσμα από θετικούς παράγοντες είναι σύμπτωμα υπερχείλισης.if ή διαλέγοντας
αρχή και βήμα ώστε να περνά μόνο από τις τιμές που θέλουμε· στη δεύτερη
περίπτωση ελέγχουμε με το χέρι τις πρώτες τιμές.found) στη συνθήκη του βρόχου σταματά τον βρόχο και μας
λέει μετά αν βρέθηκε κάτι.break τερματίζει αμέσως τον πιο εσωτερικό βρόχο (while, do-while, for)
ή switch που την περιέχει.continue διακόπτει την τρέχουσα επανάληψη και συνεχίζει στην επόμενη· στη
for εκτελείται πρώτα το βήμα.switch είναι εναλλακτική της αλυσίδας if-else-if όταν ελέγχουμε μία έκφραση
για τις δυνατές τιμές της.case είναι σημεία εισόδου: χωρίς break η εκτέλεση συνεχίζει στο επόμενο
case· το break ολοκληρώνει την εκτέλεση της switch.case γραμμένα το ένα κάτω από το άλλο μοιράζονται τις ίδιες εντολές.case ελέγχεται μόνο ισότητα (όχι >, < κ.λπ.), και η έκφραση της
switch και οι σταθερές των case πρέπει να είναι ακέραιες.goto label; μεταφέρει την εκτέλεση στην εντολή με ετικέτα label: μέσα στην
ίδια συνάρτηση.goto: οδηγεί σε δυσνόητο κώδικα
(spaghetti code) και στο μάθημα δεν τη χρησιμοποιούμε.| Ελληνικά | English | Σύντομος ορισμός |
|---|---|---|
| υπερχείλιση | overflow | Αποτέλεσμα που δεν χωράει στον τύπο της μεταβλητής |
| απροσδιόριστη συμπεριφορά | undefined behavior | Περίπτωση όπου η C δεν ορίζει τι θα συμβεί |
| μεταβλητή-σημαία | flag | Μεταβλητή 0/1 που καταγράφει αν συνέβη κάτι |
| εντολή break | break statement | Τερματίζει αμέσως τον βρόχο ή τη switch |
| εντολή continue | continue statement | Προχωρά στην επόμενη επανάληψη του βρόχου |
| εντολή switch | switch statement | Επιλογή περίπτωσης με βάση μια ακέραια τιμή |
| περίπτωση | case | Σημείο εισόδου της switch για μια σταθερά |
| προεπιλογή | default | Η περίπτωση όταν δεν ταιριάζει κανένα case |
| πτώση | fall-through | Συνέχιση στο επόμενο case όταν λείπει το break |
| εντολή goto | goto statement | Άλμα σε εντολή με ετικέτα στην ίδια συνάρτηση |
| ετικέτα | label | Όνομα με : μπροστά από εντολή, στόχος της goto |
| δομημένος προγραμματισμός | structured programming | Προγράμματα μόνο από ακολουθία, επιλογή, επανάληψη |
| κώδικας-μακαρονάδα | spaghetti code | Κώδικας με μπερδεμένη ροή, δύσκολος στην ανάγνωση |
break: σελ. 9–10· continue: σελ. 11–12· switch: σελ. 13–18· goto και δομημένος προγραμματισμός: σελ. 19–22.switch», «Εντολές break και continue», «Εντολή goto και ετικέτες» (K04, σελ. 50–51 και 56–57). Οι διαφάνειες συνιστούν να έχετε καλύψει τις σημειώσεις του κ. Σταματόπουλου μέχρι και τη σελίδα 71, δηλαδή και το Κεφάλαιο 4: Συναρτήσεις μέχρι την ενότητα «Μετατροπές μεταξύ δεκαδικών και δυαδικών αριθμών».seq.c (βρόχοι), birthdate.c (αντιστοίχιση IDAY % 7 σε ημέρα, κατάλληλη για switch)break σε case. Για number == 0 τυπώνονται zero και one
(και ό,τι ακολουθεί μέχρι το επόμενο break). Διόρθωση: κάθε ομάδα εντολών κλείνει
με break, εκτός αν θέλετε σκόπιμα να ομαδοποιήσετε case.case. case month <= 2: δεν μεταγλωττίζεται, γιατί
το case θέλει σταθερά. Διόρθωση: απαριθμήστε τις
τιμές (case 1: case 2:) ή γράψτε if.switch σε double ή σε μεταβλητή στο case. Ο gcc απαντά switch quantity
not an integer ή case label does not reduce to an integer constant. Διόρθωση:
ακέραια έκφραση και σταθερές.break (ή σημαία) μόλις βρεθεί το πρώτο.break για έξοδο από δύο βρόχους. Η break βγαίνει μόνο από τον εσωτερικό·
ο εξωτερικός συνεχίζει. Διόρθωση: σημαία που ελέγχεται και στον εξωτερικό βρόχο, ή
μεταφορά των βρόχων σε συνάρτηση που κάνει return.continue σε while πριν από το βήμα. Σε while (i < N) { if (...) continue;
i++; } το i++ παραλείπεται και ο βρόχος γίνεται ατέρμονας. Διόρθωση: αυξήστε τον
μετρητή πριν από την continue, ή χρησιμοποιήστε for.long long).i = 100; i += 2 περνάτε από άρτιους αντί για
περιττούς. Διόρθωση: γράψτε στο χαρτί τις πρώτες τιμές του μετρητή.Από τα Kahoot των διαλέξεων: οι ερωτήσεις όπου μια λάθος απάντηση μάζεψε πολλές ψήφους, με το ποσοστό σωστών απαντήσεων.
; είναι η (κενή) εντολή του βρόχου και ότι το i κάποτε υπερχειλίζει και φτάνει ξανά στο 0.i δεν θα γίνει ποτέ 0· όμως μετά τη μέγιστη τιμή του ο ακέραιος υπερχειλίζει σε αρνητικούς και φτάνει ξανά στο 0.case δέχονται μόνο ακέραιες σταθερές· όμως μπορούμε να κάνουμε switch στην ίδια τη συνθήκη (switch (x > 3.5)), που είναι 0 ή 1.i στο for (i = 105; i <= 999; i += 14) και γιατί το βήμα είναι 14;2break και continue;3for, εκτελείται το βήμα (i++) μετά από continue; Μετά από break;4switch λείπουν όλα τα break και ταιριάξει το πρώτο case;5switch;6switch να χειριστεί τη συνθήκη x > 100; Γιατί;7goto, και γιατί την αποφεύγουμε;8found, πώς ξέρουμε αν βρέθηκε αριθμός;9Ερωτήσεις που παίχτηκαν στις διαλέξεις, με το ποσοστό των φοιτητών που απάντησαν σωστά.
slides-lec08-digit-namesslides-lec08-print-all-issueslides-lec08-product-multiples-of-7slides-lec08-product-overflowslides-lec08-seasonslides-lec08-smallest-three-digithw-2023-hw1-newtonhw-2023-hw2-coophw-2024-hw1-rsaexam-2023-fall-ex2-q2lab-lab08-argcalcexam-2023-fall-ex6-q3slides-lec16-palindrome-numberslides-lec16-reverse-digitsΕπειδή το γινόμενο ξεπερνά τη μέγιστη τιμή του int (υπερχείλιση)· στην πράξη κρατιούνται μόνο τα χαμηλά 32 bit και το bit του προσήμου μπορεί να γίνει 1. Για προσημασμένους ακεραίους είναι απροσδιόριστη συμπεριφορά. ↩
105, 119, 133, …, 987 (64 τιμές, η τελευταία το \(105 + 63 \cdot 14 = 987\)). Το 14 είναι \(2 \cdot 7\): κρατά τον αριθμό πολλαπλάσιο του 7 και περιττό. ↩
Η break τερματίζει ολόκληρο τον βρόχο· η continue τερματίζει μόνο την τρέχουσα επανάληψη και ο βρόχος συνεχίζει με την επόμενη. ↩
Μετά από continue ναι (μετά γίνεται ο έλεγχος της συνθήκης)· μετά από break όχι, ο βρόχος τελειώνει αμέσως. ↩
Οι εντολές όλων των case από εκεί και κάτω, μαζί με του default, μέχρι το τέλος της switch (fall-through). ↩
case 12: case 1: case 2: το ένα κάτω από το άλλο, και μετά τις κοινές εντολές με ένα break στο τέλος. ↩
Όχι. Κάθε case ελέγχει μόνο ισότητα με μια ακέραια σταθερά· για συγκρίσεις όπως > χρειάζεται if. ↩
Σε οποιαδήποτε εντολή με ετικέτα μέσα στην ίδια συνάρτηση. Την αποφεύγουμε γιατί κάνει τη ροή δυσνόητη (spaghetti code) και σπάει τον δομημένο προγραμματισμό· στο μάθημα απαγορεύεται. ↩
Από την τιμή της σημαίας: αν found == 1 βρέθηκε και τυπώθηκε, αν έμεινε 0 δεν υπάρχει τέτοιος αριθμός. ↩