---
layout: chapter
chapter: 6
lecture: 6
title: "Εντολές και Ροή Ελέγχου"
date: 2025-10-20
part: B
slides: https://github.com/progintro/progintro.github.io/releases/download/2025/lec06.pdf
prev: 05-operators-statements
next: 07-problem-solving
topics: [statements, conditionals, loops, control-flow]
notes: [03-control-flow]
labs: [lab03]
---

# Κεφάλαιο 6: Εντολές και Ροή Ελέγχου

<!-- {% raw %} -->

> **Στόχοι:** μετά από αυτό το κεφάλαιο θα μπορείτε να κατατάσσετε κάθε εντολή της
> C σε μία από πέντε κατηγορίες, να γράφετε `if`, `if-else` και αλυσίδες `else if`,
> να αποφεύγετε το dangling `else`, να γράφετε βρόχους `while`, `for` και `do-while`,
> να προβλέπετε πόσες φορές εκτελείται το σώμα τους και να διαβάζετε το διάγραμμα
> ροής κάθε εντολής ελέγχου.
>
> **Προαπαιτούμενα:** [Κεφάλαιο 2](../02-memory-variables/), [Κεφάλαιο 5](../05-operators-statements/)
>
> **Χρόνος μελέτης:** ~2 ώρες

## Σύνοψη

Η διάλεξη κατατάσσει τις εντολές της C σε πέντε κατηγορίες (κενές,
έκφρασης, σύνθετες, συνθήκης, επανάληψης) και περνάει στη **ροή ελέγχου**: στις
εντολές που αποφασίζουν *ποια* εντολή θα εκτελεστεί και *πόσες φορές*. Βλέπουμε την
`if` και την `if-else`, τις εμφωλευμένες `if` και την παγίδα του dangling `else`, και
τους τρεις βρόχους `while`, `for` και `do-while`, ο καθένας με το διάγραμμα ροής του. Με αυτά γράφουμε
προγράμματα που παίρνουν αποφάσεις και επαναλαμβάνουν υπολογισμούς.

## Θεωρία

<a id="s6-1"></a><a id="κατηγορίες-εντολών"></a>

### §6.1 Κατηγορίες εντολών

Κάθε **εντολή (statement)** της C ανήκει σε μία από πέντε κατηγορίες:

| # | Κατηγορία | English | Παράδειγμα |
| --- | --- | --- | --- |
| 1 | Κενές εντολές | null / empty statements | `;` |
| 2 | Εντολές έκφρασης | expression statements | `x = 4;` |
| 3 | Σύνθετες εντολές | compound statements / blocks | `{ x = 4; y = 7; }` |
| 4 | Εντολές συνθήκης | conditional statements | `if (x > y) max = x;` |
| 5 | Εντολές επανάληψης | iteration statements / loops | `while (i < 42) i++;` |

Το semicolon (`;`) είναι το διαχωριστικό εντολών: δείχνει πού τελειώνει μια εντολή.
Οι κατηγορίες 4 και 5 είναι οι εντολές ροής ελέγχου.

<a id="s6-2"></a><a id="κενή-εντολή-εντολή-έκφρασης-σύνθετη-εντολή"></a>

### §6.2 Κενή εντολή, εντολή έκφρασης, σύνθετη εντολή

Η **κενή εντολή (empty / null statement)** είναι ένα σκέτο `;` και δεν κάνει τίποτα
(**no-op**)· το `;;;;;` είναι πέντε κενές εντολές. Χρησιμεύει (και κρύβει παγίδες)
όταν γίνεται σώμα μιας `if` ή ενός βρόχου.

**Εντολή έκφρασης (expression statement)** είναι μια έκφραση που τελειώνει με
semicolon, π.χ. οι αναθέσεις, οι αυξήσεις και οι κλήσεις συναρτήσεων: `x = 4;`, `z = ++y;`.

**Σύνθετη εντολή (compound statement)** ή **block** είναι μια σειρά εντολών μέσα σε
αγκύλες `{ }`. Συντακτικά ένα block μετράει ως **μία** εντολή, οπότε όπου η C ζητάει
«μια εντολή» (π.χ. ως σώμα μιας `if`) μπορούμε να βάλουμε όσες θέλουμε μέσα σε
αγκύλες. Μετά το `}` δεν χρειάζεται `;`, και το άδειο block `{ }` κάνει ό,τι η κενή
εντολή.

<a id="s6-3"></a><a id="ροή-ελέγχου"></a>

### §6.3 Ροή ελέγχου

**Ροή ελέγχου (control flow)** είναι η σειρά με την οποία εκτελούνται οι εντολές ενός
προγράμματος. Την καθορίζουν οι **εντολές ροής ελέγχου (control flow statements)**,
που παραλείπουν εντολές (συνθήκη) ή τις επαναλαμβάνουν (βρόχοι). Συνήθως την
οπτικοποιούμε με ένα **διάγραμμα ροής (flowchart)**: ένας ρόμβος είναι ο έλεγχος
μιας συνθήκης με δύο εξόδους, «αληθής» και «ψευδής», και ένα ορθογώνιο είναι μια
εντολή.

Μια συνθήκη στην C είναι απλώς μια έκφραση ([Κεφάλαιο 5](../05-operators-statements/)):
τιμή **μηδέν** σημαίνει **ψευδής**, **οποιαδήποτε άλλη** τιμή σημαίνει **αληθής**.
Γι' αυτό γράφουμε `while (1)` ή `if (n)`.

<a id="s6-4"></a><a id="η-εντολή-if"></a>

### §6.4 Η εντολή if

Η **εντολή `if`** εκτελεί μια εντολή μόνο αν μια λογική συνθήκη είναι αληθής:

```text
if ( συνθήκη )
    εντολή
```

Οι παρενθέσεις γύρω από τη συνθήκη είναι **υποχρεωτικές**. Η εντολή μπορεί να είναι
οποιασδήποτε κατηγορίας: κενή (`if (year > 1) ;`, που δεν κάνει τίποτα), εντολή
έκφρασης (`if (year > 1) year++;`) ή block (`if (year > 1) { year++; }`). Οι δύο
τελευταίες κάνουν το ίδιο, αλλά με αγκύλες μια δεύτερη εντολή που θα προσθέσετε
αργότερα μπαίνει σίγουρα μέσα στην `if`.

```mermaid
flowchart TD
  S(["execution"]) --> C{"( συνθήκη )"}
  C -- "αληθής" --> E["εντολή"]
  C -- "ψευδής" --> N(["επόμενη εντολή"])
  E --> N
```

*Σχήμα: διάγραμμα ροής της `if`.*

<a id="s6-5"></a><a id="η-εντολή-if-else"></a>

### §6.5 Η εντολή if-else

Η **εντολή `if-else`** εκτελεί μια *άλλη* εντολή όταν η συνθήκη είναι ψευδής. Εκτελείται
ακριβώς μία από τις δύο, ποτέ και οι δύο και ποτέ καμία:

```text
if ( συνθήκη )
    εντολή1
else
    εντολή2
```

```mermaid
flowchart TD
  S(["execution"]) --> C{"( συνθήκη )"}
  C -- "αληθής" --> E1["εντολή1"]
  C -- "ψευδής" --> E2["εντολή2"]
  E1 --> N(["επόμενη εντολή"])
  E2 --> N
```

*Σχήμα: διάγραμμα ροής της `if-else`.*

Το `else` δεν είναι απαραίτητο (το ίδιο αποτέλεσμα βγαίνει με μια αρχική ανάθεση
και μια απλή `if`), αλλά δείχνει καθαρά ότι οι δύο περιπτώσεις αποκλείονται. Για
απλές επιλογές τιμής υπάρχει και ο τελεστής συνθήκης `? :` του
[Κεφαλαίου 5](../05-operators-statements/). Βλ. το παράδειγμα
[Μέγιστο δύο αριθμών](#μέγιστο-δύο-αριθμών).

<a id="s6-6"></a><a id="εμφωλευμένες-if-και-η-αλυσίδα-else-if"></a>

### §6.6 Εμφωλευμένες if και η αλυσίδα else if

Όταν έχουμε πάνω από δύο περιπτώσεις, χρησιμοποιούμε **εμφωλευμένες εντολές `if`
(nested if)**: το σώμα μιας `if` ή ενός `else` είναι άλλη `if`. Το `else if` δεν είναι
ξεχωριστή λέξη-κλειδί· είναι ένα `else` του οποίου η εντολή είναι μια νέα `if`. Στο
παράδειγμα των διαφανειών:

```c
lab = -1;
if (year < 1)
    { /* empty block */ }
else if (year == 1)
    lab = 20;
else
    lab = 0;
```

Οι συνθήκες ελέγχονται με τη σειρά και εκτελείται το σώμα της *πρώτης* αληθούς: για
`year < 1` το `lab` μένει `-1` (άδειο block), για `year == 1` γίνεται `20`, αλλιώς `0`.

```mermaid
flowchart TD
  S(["execution"]) --> C1{"year #lt; 1"}
  C1 -- "αληθής" --> B0["{ } (τίποτα)"]
  C1 -- "ψευδής" --> C2{"year == 1"}
  C2 -- "αληθής" --> B1["lab = 20;"]
  C2 -- "ψευδής" --> B2["lab = 0;"]
  B0 --> N(["επόμενη εντολή"])
  B1 --> N
  B2 --> N
```

*Σχήμα: η αλυσίδα `else if` ως δύο εμφωλευμένες `if-else`.*

<a id="s6-7"></a><a id="το-πρόβλημα-του-dangling-else"></a>

### §6.7 Το πρόβλημα του dangling else

Οι εμφωλευμένες `if` χωρίς αγκύλες μπορεί να είναι **αμφίσημες (ambiguous)**: σε ποια
`if` ανήκει ένα `else`; Ο μεταγλωττιστής **αγνοεί τη στοίχιση** και ακολουθεί έναν
κανόνα: **κάθε `else` ανήκει στην πλησιέστερη προηγούμενη `if` που δεν έχει ήδη
`else`.** Έτσι, στο

```c
if (year <= 1)
    if (year == 1)
        lab = 20;
else
    lab = 0;
```

το `else` ανήκει στην εσωτερική `if (year == 1)`, παρόλο που η στοίχιση λέει το
αντίθετο. Αυτό είναι το πρόβλημα του **dangling else**. Η λύση των διαφανειών: **αν
δεν είμαστε σίγουροι, χρησιμοποιούμε αγκύλες `{ }` για να υποδείξουμε τα όρια των
σύνθετων εντολών.** Ο gcc με `-Wall` προειδοποιεί: `suggest explicit braces to avoid
ambiguous 'else' [-Wdangling-else]`. Βλ. το παράδειγμα
[Είναι τα δύο προγράμματα ισοδύναμα;](#είναι-τα-δύο-προγράμματα-ισοδύναμα).

<a id="s6-8"></a><a id="βρόχοι-η-εντολή-while"></a>

### §6.8 Βρόχοι: η εντολή while

Οι **βρόχοι (loops)** ή δομές επανάληψης επαναλαμβάνουν μια εντολή, το **σώμα** του
βρόχου· κάθε εκτέλεσή του λέγεται **επανάληψη (iteration)**. Η **εντολή `while`**
επαναλαμβάνει το σώμα **όσο** η συνθήκη είναι αληθής:

```text
while ( συνθήκη )
    εντολή
```

Η συνθήκη ελέγχεται **πριν** από κάθε επανάληψη, οπότε αν είναι ψευδής από την αρχή το
σώμα δεν εκτελείται **καμία** φορά. Για να τελειώσει ο βρόχος, το σώμα πρέπει να
αλλάζει κάτι από το οποίο εξαρτάται η συνθήκη· αλλιώς έχουμε **ατέρμονα βρόχο
(infinite loop)**.

```mermaid
flowchart TD
  S(["execution"]) --> C{"( συνθήκη )"}
  C -- "αληθής" --> E["εντολή"]
  E --> C
  C -- "ψευδής" --> N(["επόμενη εντολή"])
```

*Σχήμα: διάγραμμα ροής της `while`· ο έλεγχος γίνεται πριν από το σώμα.*

<a id="s6-9"></a><a id="η-εντολή-for"></a>

### §6.9 Η εντολή for

Η **εντολή `for`** αρχικοποιεί μεταβλητές, επαναλαμβάνει μια εντολή όσο η συνθήκη
είναι αληθής, και στο τέλος κάθε επανάληψης εκτελεί το **βήμα**:

```text
for ( αρχικοποίηση ; συνθήκη ; βήμα )     αρχικοποίηση;
    εντολή                                while ( συνθήκη ) {
                                              εντολή
                                              βήμα;
                                          }
```

Η αρχικοποίηση εκτελείται **μία φορά**· μετά ελέγχεται η συνθήκη, εκτελείται το σώμα,
εκτελείται το βήμα, και ξανά από τον έλεγχο. Όπως δείχνει η δεξιά στήλη, η `for` είναι
απλώς πιο συμπαγής γραφή της `while`.

```mermaid
flowchart TD
  S(["execution"]) --> I["αρχικοποίηση"]
  I --> C{"( συνθήκη )"}
  C -- "αληθής" --> E["εντολή"]
  E --> B["βήμα"]
  B --> C
  C -- "ψευδής" --> N(["επόμενη εντολή"])
```

*Σχήμα: διάγραμμα ροής της `for`.*

Και τα τρία μέρη είναι προαιρετικά, αλλά τα δύο `;` μένουν πάντα. Συνθήκη που λείπει
θεωρείται πάντα αληθής, άρα το `for (;;)` είναι η κλασική γραφή του ατέρμονα βρόχου.
Ο βρόχος `for (i = 0; i < N; i++)` εκτελείται ακριβώς `N` φορές, για
`i = 0, 1, …, N-1`.

<a id="s6-10"></a><a id="η-εντολή-do-while"></a>

### §6.10 Η εντολή do-while

Η **εντολή `do-while`** εκτελεί πρώτα μία φορά την εντολή και μετά ελέγχει τη συνθήκη
για το αν χρειάζεται άλλη επανάληψη:

```text
do
    εντολή
while ( συνθήκη );
```

Επειδή ο έλεγχος γίνεται στο τέλος, το σώμα εκτελείται **τουλάχιστον μία φορά** (π.χ.
ζητάμε μια τιμή από τον χρήστη μέχρι να είναι έγκυρη). Το τελικό `;` είναι **υποχρεωτικό**.

```mermaid
flowchart TD
  S(["execution"]) --> E["εντολή"]
  E --> C{"( συνθήκη )"}
  C -- "αληθής" --> E
  C -- "ψευδής" --> N(["επόμενη εντολή"])
```

*Σχήμα: διάγραμμα ροής της `do-while`· το σώμα προηγείται του ελέγχου.*

<a id="s6-11"></a><a id="σύγκριση-των-τριών-βρόχων"></a>

### §6.11 Σύγκριση των τριών βρόχων

| | `while` | `for` | `do-while` |
| --- | --- | --- | --- |
| Έλεγχος συνθήκης | πριν από κάθε επανάληψη | πριν από κάθε επανάληψη | μετά από κάθε επανάληψη |
| Ελάχιστες εκτελέσεις σώματος | 0 | 0 | 1 |
| Αρχικοποίηση / βήμα | χωριστά | στην επικεφαλίδα | χωριστά |
| `;` μετά τη συνθήκη | λάθος (κενό σώμα) | λάθος (κενό σώμα) | υποχρεωτικό |
| Ατέρμονας βρόχος | `while (1)` | `for (;;)` | `do … while (1);` |

Μετρητής με γνωστό εύρος: `for`· «όσο ισχύει κάτι»: `while`· «τουλάχιστον μία φορά»:
`do-while`. Οι `switch`, `break`, `continue` έρχονται στο [Κεφάλαιο 8](../08-control-flow-2/).

## Παραδείγματα

<a id="s6-12"></a><a id="ιχνηλάτηση-εντολών-έκφρασης"></a>

### §6.12 Ιχνηλάτηση εντολών έκφρασης

*Εφαρμόζει: εντολή έκφρασης, `++`/`--` από το [Κεφάλαιο 5](../05-operators-statements/).*
Ποια η τιμή των `x`, `y`, `z` μετά από αυτές τις εντολές;

```c
x = 4;
y = 7;
z = ++y;
y = z - (x++);
z = x - (--y);
```

Το `++y` αλλάζει πρώτα και δίνει τη νέα τιμή· το `x++` δίνει την παλιά και αλλάζει μετά:

| Εντολή | `x` | `y` | `z` |
| --- | --- | --- | --- |
| `x = 4; y = 7;` | 4 | 7 | ? |
| `z = ++y;` | 4 | 8 | 8 |
| `y = z - (x++);` | 5 | 4 | 8 |
| `z = x - (--y);` | 5 | 3 | 2 |

<a id="s6-13"></a><a id="μέγιστο-δύο-αριθμών"></a>

### §6.13 Μέγιστο δύο αριθμών

*Εφαρμόζει: `if-else`.* Οι διαφάνειες ρωτούν αν μπορούμε χωρίς `else`, αν υπάρχει
άλλος τρόπος, και τι κάνουμε με πάνω από δύο συνθήκες. Τρεις ισοδύναμες γραφές:

```c
if (x > y) max = x; else max = y;   /* 1: if-else */
max = y; if (x > y) max = x;        /* 2: χωρίς else */
max = (x > y) ? x : y;              /* 3: τελεστής συνθήκης */
```

Για περισσότερες από δύο συνθήκες: εμφωλευμένες `if`.

<a id="s6-14"></a><a id="είναι-τα-δύο-προγράμματα-ισοδύναμα"></a>

### §6.14 Είναι τα δύο προγράμματα ισοδύναμα;

*Εφαρμόζει: εμφωλευμένες `if`, dangling else.* Το πρώτο είναι η αλυσίδα `else if` της
Θεωρίας· το δεύτερο είναι:

```c
lab = -1;
if (year <= 1)
    if (year == 1)
        lab = 20;
else
    lab = 0;
```

Αν το `else` ανήκε στην εξωτερική `if`, όπως υπονοεί η στοίχιση, θα ήταν ισοδύναμα.
Ανήκει όμως στην εσωτερική, άρα:

| `year` | 1ο πρόγραμμα | 2ο πρόγραμμα |
| --- | --- | --- |
| `0` (ή αρνητικό) | `lab = -1` | `lab = 0` |
| `1` | `lab = 20` | `lab = 20` |
| `2` (ή μεγαλύτερο) | `lab = 0` | `lab = -1` |

**Δεν** είναι ισοδύναμα. Για να ανήκει το `else` στην εξωτερική `if`, κλείστε την
εσωτερική `if` σε αγκύλες: `if (year <= 1) { if (year == 1) lab = 20; } else lab = 0;`.

<a id="s6-15"></a><a id="άθροισμα-με-while"></a>

### §6.15 Άθροισμα με while

*Εφαρμόζει: `while`.* Τι κάνει το παρακάτω πρόγραμμα;

```c
#include <stdio.h>

int main() {
    int i = 0;
    int sum = 0;
    while (i < 42) {
        sum += i;
        i++;
    }
    printf("%d %d\n", i, sum);
    return 0;
}
```

Ο βρόχος σταματάει όταν `i == 42`, αφού έχει προσθέσει $0 + \dots + 41 = 861$:

```text
$ ./a.out
42 861
```

Μετά τον βρόχο το `i` έχει την τιμή που *έκανε* τη συνθήκη ψευδή (42), όχι την
τελευταία για την οποία εκτελέστηκε το σώμα (41).

<a id="s6-16"></a><a id="ατέρμονες-βρόχοι-while-1-και-for-"></a>

### §6.16 Ατέρμονες βρόχοι: while (1) και for (;;)

*Εφαρμόζει: κενή εντολή, `while`, `for`.*

```c
while (1);
for (;;) ;
```

Ατέρμονες βρόχοι με κενό σώμα (στις διαφάνειες το `for (;;)` δεν έχει σώμα· εδώ
πήρε την κενή εντολή): το πρόγραμμα «κολλάει» μέχρι το Ctrl-C. Μια πάντα αληθής
συνθήκη έχει νόημα σε προγράμματα που τρέχουν συνεχώς (ένας server, ένα παιχνίδι) ή
που τερματίζουν από μέσα, π.χ. με `return` ή με την `break` μιας επόμενης διάλεξης.

<a id="s6-17"></a><a id="το-ερωτηματικό-μετά-το-while"></a>

### §6.17 Το ερωτηματικό μετά το while

*Εφαρμόζει: κενή εντολή, `while`.* Τι κάνει το παρακάτω;

```c
i = 0;
while (i < 42);
    printf("%d\n", i++);
```

Το `;` μετά το `while (i < 42)` είναι κενή εντολή και *αυτή* είναι το σώμα. Το `i`
δεν αλλάζει ποτέ και το πρόγραμμα κολλάει χωρίς έξοδο· η `printf` βρίσκεται μετά τον
βρόχο και δεν εκτελείται ποτέ. Ο κώδικας μεταγλωττίζεται, αφού είναι συντακτικά σωστός.

<a id="s6-18"></a><a id="μέτρηση-με-for"></a>

### §6.18 Μέτρηση με for

*Εφαρμόζει: `for`.* Ο πρώτος βρόχος τυπώνει 100 φορές `Hello world`· ο δεύτερος
είναι το γενικό παράδειγμα των διαφανειών:

```c
int i;
for ( i = 0 ; i < 100 ; i++ )
    printf("Hello world\n");

for ( i = 0 ; i < N ; i++ ) {
    printf("%d\n", i);
}
```

- *Πόσες φορές εκτελείται το block;* `N` φορές (αν `N > 0`), για `i = 0, …, N-1`· αν
  `N <= 0`, καμία.
- *Θα τυπωθεί το `N`;* Όχι: με `i == N` η συνθήκη είναι ψευδής πριν από την `printf`.
- *Τι γίνεται αν αλλάξω αρχικοποίηση ή βήμα;* Με `i = 1` το σώμα εκτελείται `N-1`
  φορές· με βήμα `i += 2` τυπώνονται μόνο οι ζυγοί κάτω από `N`· με `i--` το `i`
  απομακρύνεται από το `N` και ο βρόχος (θεωρητικά) δεν τελειώνει ποτέ.

<a id="s6-19"></a><a id="do-while-μέχρι-το-42"></a>

### §6.19 do-while μέχρι το 42

*Εφαρμόζει: `do-while`.* Τι κάνει το παρακάτω;

```c
i = 0;
do
    i++;
while (i < 42);
printf("%d\n", i);
```

Το `i` αυξάνεται και μετά ελέγχεται· όταν γίνει `42` ο έλεγχος αποτυγχάνει και
τυπώνεται `42`. Με `i = 100;` στην αρχή, η `do-while` εκτελεί το σώμα μία φορά και τυπώνει `101`, ενώ
ένα `while (i < 42) i++;` δεν θα το εκτελούσε καθόλου και θα έμενε `100`.

<a id="s6-20"></a><a id="γρήγορος-έλεγχος-της-λύσης-με-pipes-και-time"></a>

### §6.20 Γρήγορος έλεγχος της λύσης με pipes και time

*Συμβουλή για την άσκηση `aliquot` της hw0.* Αντί να πληκτρολογείτε κάθε φορά την
είσοδο, στείλτε τη στο πρόγραμμα με pipe ([Κεφάλαιο 1](../01-command-line/)):

```sh
echo -e "138\n0\nf\n" | ./aliquot
```

Η `echo -e` ερμηνεύει κάθε `\n` ως αλλαγή γραμμής, οπότε το `./aliquot` διαβάζει τρεις
γραμμές: `138`, `0` και `f`. Με `time` μετράτε και τον χρόνο εκτέλεσης, και με
`ttyplot` (ίσως χρειαστεί να το εγκαταστήσετε) σχεδιάζετε την έξοδο στο τερματικό:

```sh
echo -e "138\n0\nf\n" | time ./aliquot
echo -e "2856\n0\nf\n" | ./aliquot | ttyplot
```

## Κύρια σημεία

1. Κάθε εντολή της C είναι κενή, έκφρασης, σύνθετη, συνθήκης ή επανάληψης.
2. Η κενή εντολή `;` δεν κάνει τίποτα· μετράει όταν γίνεται σώμα `if` ή βρόχου.
3. Μια έκφραση που τελειώνει σε `;` είναι εντολή έκφρασης.
4. Ένα block `{ }` μετράει ως μία εντολή και μπορεί να γίνει σώμα κάθε εντολής ελέγχου.
5. Ροή ελέγχου είναι η σειρά εκτέλεσης των εντολών· τη δείχνει ένα διάγραμμα ροής.
6. Η `if` εκτελεί μια εντολή μόνο αν η συνθήκη είναι μη μηδενική· οι παρενθέσεις είναι υποχρεωτικές.
7. Η `if-else` εκτελεί ακριβώς μία από δύο εντολές.
8. Για πάνω από δύο περιπτώσεις γράφουμε εμφωλευμένες `if`, συνήθως ως αλυσίδα `else if`.
9. Κάθε `else` ανήκει στην πλησιέστερη προηγούμενη `if` χωρίς `else`· η στοίχιση δεν μετράει.
10. Αν δεν είμαστε σίγουροι, χρησιμοποιούμε αγκύλες `{ }` για τα όρια των σύνθετων εντολών.
11. Η `while` ελέγχει πριν από κάθε επανάληψη, οπότε το σώμα της μπορεί να μην εκτελεστεί.
12. Ένα `;` αμέσως μετά από `while (...)` ή `for (...)` γίνεται το σώμα του βρόχου.
13. Οι `while (1)` και `for (;;)` χρησιμεύουν σε προγράμματα που τρέχουν συνεχώς.
14. Η `for` ισοδυναμεί με μια `while`· το `for (i = 0; i < N; i++)` εκτελείται `N` φορές.
15. Η `do-while` εκτελεί το σώμα τουλάχιστον μία φορά· το `;` στο τέλος είναι υποχρεωτικό.
16. Με `echo -e "..." | ./prog` δοκιμάζετε γρήγορα ένα πρόγραμμα, και με `time` το χρονομετράτε.

## Ορολογία

| Ελληνικά | English | Σύντομος ορισμός |
| --- | --- | --- |
| εντολή | statement | Η μονάδα εκτέλεσης ενός προγράμματος C |
| κενή εντολή | empty / null statement | Το σκέτο `;`, που δεν κάνει τίποτα (no-op) |
| εντολή έκφρασης | expression statement | Μια έκφραση που τελειώνει με `;` |
| σύνθετη εντολή | compound statement / block | Εντολές μέσα σε `{ }`, που μετράνε ως μία |
| ροή ελέγχου | control flow | Η σειρά με την οποία εκτελούνται οι εντολές |
| διάγραμμα ροής | flowchart | Σχήμα με ρόμβους (συνθήκες) και ορθογώνια (εντολές) |
| εμφωλευμένες if | nested if | `if` μέσα στο σώμα άλλης `if` ή `else` |
| κρεμασμένο else | dangling else | Αμφισημία για το σε ποια `if` ανήκει ένα `else` |
| βρόχος | loop | Εντολή που επαναλαμβάνει ένα σώμα |
| επανάληψη | iteration | Μία εκτέλεση του σώματος του βρόχου |
| ατέρμονας βρόχος | infinite loop | Βρόχος που δεν τερματίζει ποτέ |
| αρχικοποίηση / βήμα | initialization / step | Το πρώτο και το τρίτο μέρος της `for` |

## Διάβασμα

- **Διαφάνειες:** [Διάλεξη 6](https://github.com/progintro/progintro.github.io/releases/download/2025/lec06.pdf), σελ. 1–29. Pipes και `time`: σελ. 2· κατηγορίες εντολών: σελ. 5–8· ροή ελέγχου, `if`, `if-else`: σελ. 9–13· εμφωλευμένες `if` και dangling else: σελ. 14–16· `while`: σελ. 17–21· `for`: σελ. 22–24· `do-while`: σελ. 25–26.
- **Σημειώσεις:** [Κεφάλαιο 3: Η ροή του ελέγχου](https://progintro.github.io/notes/chapters/03-control-flow/), ενότητες «Η ροή του ελέγχου στην C», «Εντολή `if`», «Εντολές βρόχου `while`», «Εντολή βρόχου `for`» (K04, σελ. 46–49 και 52–55). Οι διαφάνειες συνιστούν να έχετε καλύψει τις σημειώσεις του κ. Σταματόπουλου μέχρι και τη σελίδα 62, δηλαδή και το [Κεφάλαιο 4: Συναρτήσεις](https://progintro.github.io/notes/chapters/04-functions/) μέχρι την ενότητα «Συνάρτηση υπολογισμού παραγοντικού».
- **Εργαστήριο:** [Εργαστήριο 3](https://progintro.github.io/lab-material/labs/lab03/): εισαγωγή για τους τρεις βρόχους και τα διαγράμματα ροής τους, ασκήσεις `seq.c` (`while`, `for`, `do...while`), `root.c` (`if...else`), `birthdate.c`, `limit.c`
- **Βιβλίο:** K&R, κεφ. 3 (σελ. 85–100), όπως προτείνουν οι σημειώσεις.
- **Άλλα:**
  - Wikipedia: [Control flow](https://en.wikipedia.org/wiki/Control_flow), [Conditional (computer programming)](https://en.wikipedia.org/wiki/Conditional_(computer_programming)), [While loop](https://en.wikipedia.org/wiki/While_loop), [For loop](https://en.wikipedia.org/wiki/For_loop), [Dangling else](https://en.wikipedia.org/wiki/Dangling_else)
  - Για τις ακολουθίες aliquot: [σχετικό άρθρο (PDF)](https://math.dartmouth.edu/~carlp/upintconf.pdf)

## Συχνά λάθη

- **`;` μετά τη συνθήκη βρόχου.** `while (i < 42); printf(...);` κολλάει χωρίς έξοδο·
  `for (i = 0; i < N; i++);` εκτελεί το «σώμα» μία φορά, μετά τον βρόχο. Διόρθωση:
  σβήστε το `;`, βάλτε το σώμα σε `{ }`. Το ίδιο με `if (x > y); max = x;`.
- **Εμπιστοσύνη στη στοίχιση.** Δύο εντολές με εσοχή κάτω από `if` χωρίς αγκύλες: μόνο
  η πρώτη ανήκει στην `if`. Διόρθωση: `{ }`.
- **Dangling else.** Το `else` πάει στην εσωτερική `if` και βγαίνουν λάθος τιμές· ο
  gcc με `-Wall` λέει `suggest explicit braces to avoid ambiguous 'else'`.
- **Χωρίς παρενθέσεις.** `if x > 1` δεν μεταγλωττίζεται (`expected '(' before 'x'`).
- **Ξεχασμένο βήμα σε `while`:** ο βρόχος δεν τελειώνει. **Off-by-one:** `for (i = 0; i <= N; i++)` εκτελείται `N+1` φορές, όχι `N`.
- **Χωρίς `;` στο τέλος της `do-while`.** `do i++; while (i < 42)` δίνει `expected ';'`.
- **Ο μετρητής μετά τον βρόχο.** Μετά το `while (i < 42) { … i++; }` το `i` είναι `42`.

<!-- misconceptions -->

### Τι δυσκόλεψε την τάξη

Από τα Kahoot των διαλέξεων: οι ερωτήσεις όπου μια λάθος απάντηση μάζεψε πολλές ψήφους, με το ποσοστό σωστών απαντήσεων.

- **[Κ6.9](../../questions/kahoot/kahoot-while-not-42.md)** while(!42) (17% σωστές): Το 53% απάντησε ότι δεν είναι έγκυρη C, πιστεύοντας ότι η συνθήκη πρέπει να είναι σύγκριση· στην C κάθε ακέραια έκφραση είναι συνθήκη, και το `!42` κάνει 0.
- **[Κ6.8](../../questions/kahoot/kahoot-for-n-times-trap.md)** Πόσες φορές εκτελείται ένα for μέχρι N (23% σωστές): Το 34% απάντησε N, υποθέτοντας σιωπηρά ότι το `N` είναι θετικό· αν το `N` είναι 0 ή αρνητικό, το σώμα δεν εκτελείται καθόλου.
- **[Κ6.7](../../questions/kahoot/kahoot-while-as-for.md)** while γραμμένο ως for (24% σωστές): Το 34% επέλεξε `for(; condition ; statement);`· αυτό δουλεύει μόνο αν το `statement` είναι απλή έκφραση, αφού το τρίτο μέρος της `for` δέχεται έκφραση και όχι οποιαδήποτε εντολή (π.χ. ένα μπλοκ `{…}` ή ένα `if`).
- **[Κ6.6](../../questions/kahoot/kahoot-if-without-parens.md)** if χωρίς παρενθέσεις (42% σωστές): Το 53% απάντησε True, ίσως από γλώσσες όπως η Python· στην C η συνθήκη της `if` πρέπει να είναι σε παρενθέσεις.
- **[Κ6.4](../../questions/kahoot/kahoot-for-step-two.md)** Επαναλήψεις με βήμα 2 (57% σωστές): Το 27% επέλεξε 49 φορές, ένα κλασικό λάθος «κατά ένα» (off-by-one): ξεχνά ότι μετράει και η επανάληψη με `i = 0`.
- **[Κ6.3](../../questions/kahoot/kahoot-for-empty-init.md)** Η σύνταξη του for (59% σωστές): Το 27% επέλεξε `for(i < 100; i++;)`, βάζοντας τη συνθήκη στη θέση της αρχικοποίησης. Τα τρία μέρη του `for` είναι πάντα αρχικοποίηση; συνθήκη; βήμα, και ένα κενό μέρος αφήνει μόνο το ερωτηματικό του.

<!-- /misconceptions -->

## Ερωτήσεις κατανόησης

- <a id="e6-1"></a>**[Ε6.1](#e6-1)** Πόσες εντολές περιέχει η γραμμή `;;;;;` και τι κάνουν;[^q1]
- <a id="e6-2"></a>**[Ε6.2](#e6-2)** Γιατί ένα block `{ … }` μπορεί να σταθεί ως σώμα μιας `if`, ενώ δύο σκέτες εντολές όχι;[^q2]
- <a id="e6-3"></a>**[Ε6.3](#e6-3)** Σε ποια `if` ανήκει ένα `else` όταν υπάρχουν δύο υποψήφιες και δεν υπάρχουν αγκύλες;[^q3]
- <a id="e6-4"></a>**[Ε6.4](#e6-4)** Ποια είναι η διαφορά ανάμεσα σε `while` και `do-while`; Δώστε μια περίπτωση όπου δίνουν διαφορετικό αποτέλεσμα.[^q4]
- <a id="e6-5"></a>**[Ε6.5](#e6-5)** Γράψτε έναν βρόχο `while` ισοδύναμο με το `for (i = 0; i < 100; i++) printf("Hello world\n");`.[^q5]
- <a id="e6-6"></a>**[Ε6.6](#e6-6)** Πόσες φορές εκτελείται το σώμα του `for (i = 0; i <= N; i++)`;[^q6]

<!-- kahoot -->

### Kahoot από το αμφιθέατρο (Κ6.1–Κ6.9)

Ερωτήσεις που παίχτηκαν στις διαλέξεις, με το ποσοστό των φοιτητών που απάντησαν σωστά.

- <a id="k6-1"></a>**[Κ6.1](../../questions/kahoot/kahoot-if-else-trace.md)** Απλό if-else: 91% σωστές απαντήσεις
- <a id="k6-2"></a>**[Κ6.2](../../questions/kahoot/kahoot-while-vs-do-while.md)** while και do-while: 85% σωστές απαντήσεις
- <a id="k6-3"></a>**[Κ6.3](../../questions/kahoot/kahoot-for-empty-init.md)** Η σύνταξη του for: 59% σωστές απαντήσεις
- <a id="k6-4"></a>**[Κ6.4](../../questions/kahoot/kahoot-for-step-two.md)** Επαναλήψεις με βήμα 2: 57% σωστές απαντήσεις
- <a id="k6-5"></a>**[Κ6.5](../../questions/kahoot/kahoot-for-missing-increment.md)** Ένα for χωρίς βήμα: 56% σωστές απαντήσεις
- <a id="k6-6"></a>**[Κ6.6](../../questions/kahoot/kahoot-if-without-parens.md)** if χωρίς παρενθέσεις: 42% σωστές απαντήσεις
- <a id="k6-7"></a>**[Κ6.7](../../questions/kahoot/kahoot-while-as-for.md)** while γραμμένο ως for: 24% σωστές απαντήσεις
- <a id="k6-8"></a>**[Κ6.8](../../questions/kahoot/kahoot-for-n-times-trap.md)** Πόσες φορές εκτελείται ένα for μέχρι N: 23% σωστές απαντήσεις
- <a id="k6-9"></a>**[Κ6.9](../../questions/kahoot/kahoot-while-not-42.md)** while(!42): 17% σωστές απαντήσεις

<!-- /kahoot -->

## Ασκήσεις

<!-- exercises -->

### Ζέσταμα: από τις διαφάνειες (Α6.1–Α6.9)

- <a id="a6-1"></a>**[Α6.1](../../questions/slides/slides-lec06-do-while.md)** Τι τυπώνει η do-while: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 26 · ★☆☆ · trace · `slides-lec06-do-while`
- <a id="a6-2"></a>**[Α6.2](../../questions/slides/slides-lec06-expression-statements.md)** Τιμές μετά από εντολές έκφρασης: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 7 · ★☆☆ · trace · `slides-lec06-expression-statements`
- <a id="a6-3"></a>**[Α6.3](../../questions/slides/slides-lec06-for-count.md)** Πόσες φορές εκτελείται μια for: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 24 · ★☆☆ · short-answer · `slides-lec06-for-count`
- <a id="a6-4"></a>**[Α6.4](../../questions/slides/slides-lec06-for-empty.md)** Ο βρόχος for (;;): Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 23 · ★☆☆ · short-answer · `slides-lec06-for-empty`
- <a id="a6-5"></a>**[Α6.5](../../questions/slides/slides-lec06-if-else-max.md)** Μέγιστο με if-else και εναλλακτικές: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 13 · ★☆☆ · short-answer · `slides-lec06-if-else-max`
- <a id="a6-6"></a>**[Α6.6](../../questions/slides/slides-lec06-while-forever.md)** Ο βρόχος while (1): Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 20 · ★☆☆ · short-answer · `slides-lec06-while-forever`
- <a id="a6-7"></a>**[Α6.7](../../questions/slides/slides-lec06-while-sum.md)** Άθροισμα με while: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 19 · ★☆☆ · trace · `slides-lec06-while-sum`
- <a id="a6-8"></a>**[Α6.8](../../questions/slides/slides-lec06-dangling-else.md)** Το πρόβλημα του dangling else: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 15 · ★★☆ · trace · `slides-lec06-dangling-else`
- <a id="a6-9"></a>**[Α6.9](../../questions/slides/slides-lec06-while-semicolon.md)** Το ερωτηματικό μετά το while: Διάλεξη 6: Εντολές και Ροή Ελέγχου, διαφάνεια 21 · ★★☆ · trace · `slides-lec06-while-semicolon`

### Εργαστήριο (Α6.10–Α6.13)

- <a id="a6-10"></a>**[Α6.10](../../questions/labs/lab-lab03-limit.md)** Αποσφαλμάτωση αθροίσματος με όριο: Εργαστήριο 3, Άσκηση 4 · ★☆☆ · debug · `lab-lab03-limit`
- <a id="a6-11"></a>**[Α6.11](../../questions/labs/lab-lab04-pyramid.md)** Κατασκευή πυραμίδας: Εργαστήριο 4, Άσκηση 2 · ★☆☆ · programming · `lab-lab04-pyramid`
- <a id="a6-12"></a>**[Α6.12](../../questions/labs/lab-lab03-root.md)** Υπολογισμός ριζών τριωνύμου: Εργαστήριο 3, Άσκηση 2 · ★★☆ · programming · `lab-lab03-root`
- <a id="a6-13"></a>**[Α6.13](../../questions/labs/lab-lab03-seq.md)** Υπολογισμός αθροίσματος σειράς: Εργαστήριο 3, Άσκηση 1 · ★★☆ · programming · `lab-lab03-seq`

### Εργασίες (Α6.14–Α6.15)

- <a id="a6-14"></a>**[Α6.14](../../questions/homework/hw-2023-hw0-collatz.md)** Η εικασία Collatz: Εργασία 0 (2023-24), Άσκηση 3 · ★★☆ · programming · `hw-2023-hw0-collatz`
- <a id="a6-15"></a>**[Α6.15](../../questions/homework/hw-2025-hw0-aliquot.md)** Οι Ακολουθίες Aliquot: Εργασία 0 (2025-26), Άσκηση 3 · ★★☆ · programming · `hw-2025-hw0-aliquot`

### Θέματα εξετάσεων (Α6.16–Α6.25)

- <a id="a6-16"></a>**[Α6.16](../../questions/exams/exam-2023-fall-ex6-q1.md)** Μέγιστος Κοινός Διαιρέτης: Online τελική εξέταση Δεκεμβρίου 2023, Εξέταση #6 (Crypto Themed), Θέμα 1 · ★☆☆ · programming · `exam-2023-fall-ex6-q1`
- <a id="a6-17"></a>**[Α6.17](../../questions/exams/exam-2024-dec-q1.md)** Προσεγγίζοντας το π: Κατατακτήριες Δεκεμβρίου 2024, Θέμα 1 · ★☆☆ · programming · `exam-2024-dec-q1`
- <a id="a6-18"></a>**[Α6.18](../../questions/exams/exam-2025-sep-q1.md)** Mystery: Εξέταση Σεπτεμβρίου 2025, Θέμα 1 · ★☆☆ · trace · `exam-2025-sep-q1`
- <a id="a6-19"></a>**[Α6.19](../../questions/exams/exam-2026-sep-q1.md)** Mystery: Εξέταση Σεπτεμβρίου 2026, Θέμα 1 · ★☆☆ · trace · `exam-2026-sep-q1`
- <a id="a6-20"></a>**[Α6.20](../../questions/exams/exam-2023-dec-q1.md)** Κάντο όπως ο Βιετά: Κατατακτήριες Δεκεμβρίου 2023, Θέμα 1 · ★★☆ · programming · `exam-2023-dec-q1`
- <a id="a6-21"></a>**[Α6.21](../../questions/exams/exam-2023-fall-ex10-q2.md)** Ασημένιο Κλάσμα: Online τελική εξέταση Δεκεμβρίου 2023, Εξέταση #10, Θέμα 2 · ★★☆ · programming · `exam-2023-fall-ex10-q2`
- <a id="a6-22"></a>**[Α6.22](../../questions/exams/exam-2023-fall-ex13-q1.md)** Κάντο όπως ο Βιετά: Online τελική εξέταση Δεκεμβρίου 2023, Εξέταση #13, Θέμα 1 · ★★☆ · programming · `exam-2023-fall-ex13-q1`
- <a id="a6-23"></a>**[Α6.23](../../questions/exams/exam-2023-fall-ex15-q2.md)** Τυπώνοντας τον Πίνακα ASCII: Online τελική εξέταση Δεκεμβρίου 2023, Εξέταση #15, Θέμα 2 · ★★☆ · programming · `exam-2023-fall-ex15-q2`
- <a id="a6-24"></a>**[Α6.24](../../questions/exams/exam-2023-fall-ex9-q2.md)** Πετυχαίνοντας τον Στόχο: Online τελική εξέταση Δεκεμβρίου 2023, Εξέταση #9, Θέμα 2 · ★★☆ · programming · `exam-2023-fall-ex9-q2`
- <a id="a6-25"></a>**[Α6.25](../../questions/exams/exam-2026-jan-q3.md)** Εύρεση Πρώτων Παραγόντων - factor: Εξέταση Ιανουαρίου 2026, Θέμα 3 · ★★☆ · programming · `exam-2026-jan-q3`

### Σχετικές ασκήσεις από άλλα κεφάλαια

- **[Α2.11](../../questions/labs/lab-lab04-printchar.md)** Εκτύπωση χαρακτήρων: Εργαστήριο 4, Άσκηση 1 · ★☆☆ · programming · `lab-lab04-printchar`
- **[Α3.5](../../questions/slides/slides-lec03-leibniz-pi.md)** Προσέγγιση του π με τη σειρά Leibniz: Διάλεξη 3: Συναρτήσεις, διαφάνεια 43 · ★★☆ · programming · `slides-lec03-leibniz-pi`
- **[Α5.9](../../questions/exams/exam-2025-jan-q1.md)** Mystery: Εξέταση Ιανουαρίου 2025, Θέμα 1 · ★☆☆ · trace · `exam-2025-jan-q1`
- **[Α5.10](../../questions/exams/exam-2026-jan-q1.md)** Mystery: Εξέταση Ιανουαρίου 2026, Θέμα 1 · ★☆☆ · trace · `exam-2026-jan-q1`
- **[Α5.11](../../questions/exams/exam-2026-jun-q1.md)** Η συνάρτηση mystery: Εξέταση Ιουνίου 2026, Θέμα 1 · ★☆☆ · trace · `exam-2026-jun-q1`
- **[Α5.8](../../questions/labs/lab-lab03-birthdate.md)** Υπολογισμός ημέρας μίας δεδομένης ημερομηνίας: Εργαστήριο 3, Άσκηση 3 · ★☆☆ · programming · `lab-lab03-birthdate`
- **[Α9.16](../../questions/homework/hw-2024-hw0-trolley.md)** Το Πρόβλημα του Τρόλεϊ (trolley): Εργασία 0 (2024-25), Άσκηση 3 · ★★☆ · programming · `hw-2024-hw0-trolley`

<!-- /exercises -->

[^q1]: Πέντε κενές εντολές· καμία δεν κάνει τίποτα (no-op).
[^q2]: Η `if` δέχεται ως σώμα μία εντολή. Ένα block είναι συντακτικά μία (σύνθετη) εντολή, ενώ δύο σκέτες εντολές είναι δύο: μόνο η πρώτη ανήκει στην `if`.
[^q3]: Στην πλησιέστερη προηγούμενη `if` που δεν έχει ήδη `else`, ανεξάρτητα από τη στοίχιση.
[^q4]: Η `while` ελέγχει πριν από το σώμα (0 ή περισσότερες εκτελέσεις), η `do-while` μετά (τουλάχιστον μία). Με `i = 100`, το `do i++; while (i < 42);` αφήνει `i = 101`, ενώ το `while (i < 42) i++;` αφήνει `i = 100`.
[^q5]: `i = 0; while (i < 100) { printf("Hello world\n"); i++; }`
[^q6]: `N + 1` φορές (για `i = 0, …, N`), αν `N >= 0`.

<!-- {% endraw %} -->
