ΠΕΡΙΕΧΟΜΕΝΑ

 

§         TRUE ΚΑΙ FALSE

§         ΔΗΛΩΣΕΙΣ ΥΠΟ ΣΥΝΘΗΚΗ

o        ΕΝΤΟΛΗ if

-         NESTED Ifs

-         Η ΣΚΑΛΑ if-else-if

o        Ο ΤΕΛΕΣΤΗΣ ?

o        Η ΕΝΤΟΛΗ switch

-         ΕΜΦΩΛΙΑΣΜΕΝΑ switch

§         ΒΡΟΓΧΟΙ

o        Η ΕΝΤΟΛΗ for

-         ΠΑΡΑΛΛΑΓΕΣ ΤΩΝ ΒΡΟΓΧΩΝ ΤΥΠΟΥ for

-         Ο ΑΤΕΡΜΩΝ ΒΡΟΓΧΟΣ

-         for LOOPS WITH NO BODIES

o        Η ΕΝΤΟΛΗ while

o        Η ΕΝΤΟΛΗ do / while

o        Η ΕΝΤΟΛΗ break

o        Η ΣΥΝΑΡΤΗΣΗ exit()

o        Η ΕΝΤΟΛΗ continue

o        LABELS και goto

 

 

 

 

 

 

ΚΕΦΑΛΑΙΟ 3ο

 

PROGRAM CONTROL STATEMENTS (ΔΗΛΩΣΕΙΣ ΕΛΕΓΧΟΥ)

 

TRUE ΚΑΙ FALSE

 

            Οι περισσότερες εκφράσεις ελέγχου σ’ όλες τις γλώσσες προγραμματισμού (συμπεριλαμβανομένης και της C), εκτελούν ένα τεστ υπό συνθήκη το οποίο αποφασίζει ποια ενέργεια θα εκτελεστεί. Το τεστ αυτό παίρνει είτε αληθείς, είτε ψευδείς τιμές. Στη C true είναι κάθε nonzero τιμή (και αρνητική). Λάθος είναι το μηδέν.  Αυτή η προσέγγιση αληθείας και ψέματος υιοθετήθηκε πρωταρχικά από τη C και αυτό γιατί επιτρέπει σε ένα μεγάλο εύρος ρουτινών να κωδικοποιηθούν εύκολα.

 

Ι. ΔΗΛΩΣΕΙΣ ΥΠΟ ΣΥΝΘΗΚΗ

 

i)         Εντολή if

 

Η γενική σύνταξη της if είναι:

 

                        if  (expression) statement;

                        else statement;

 

όπου statement μπορεί να είναι μία απλή δήλωση ή ένα μπλοκ δηλώσεων (το οποίο περιλαμβάνεται σε { } ).

Το else είναι προαιρετικό.

 

Η γενική σύνταξη της if με χρήση μπλοκ είναι:

 

                                    if (expression)

                                    {

                                                statement sequence;

                                    }

                                    else

                                    {

                                                statement sequence;

                                    }

 

            Αν η expression είναι true (άλλο από 0),  τότε εκτελείται το μπλοκ του if, αλλιώς εκτελείται το μπλοκ του else αν υπάρχει.

 

ΠΡΟΣΟΧΗ:  Πάντα εκτελείται ο κώδικας του if ή ο κώδικας του else. Ποτέ και τα δύο μαζί.

 

Π.χ. (1) :          #include <stdio.h>

                        main ( )

                        {

                          int magic = 123;

                          int guess;

                          scanf (“d%”, &guess);

                          if (guess == magic) printf (“** Right**”);

                        }

                       

            Σ’ αυτό το παράδειγμα εισάγεται τιμή στη μεταβλητή guess και ελέγχουμε αν είναι ίση με την τιμή της μεταβλητής magic. Αν αυτό είναι αληθής τότε τυπώνεται **Right**.

 

 

Π.χ. (2) :          #include <stdio.h>

                        main ( )

                        {

                          int magic = 123;

                          int guess;

                          scanf (“d%”, &guess);

                          if (guess == magic) printf (“** Right**”);

                          else printf (“..Wrong..”);

                        }

 

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

 

Nested ifs

 

Μία από τις πιο πολύπλοκες χρήσεις της εντολής if σε όλες τις γλώσσες είναι τα nested ifs. Ένα nested if είναι μία δήλωση if που αποτελεί αντικείμενο είτε ενός if, είτε ενός else. Ο λόγος για τον οποίο η χρήση των nested ifs θεωρείται προβληματική, είναι ότι είναι δύσκολο να ξεχωριστεί πιο else συντάσσεται με ποιο if.

 

Π.χ. :               if (x)

                        {

                            if (y) printf (“1”);

                        }

                        else printf (“2”);

 

            Έτσι το else συντάσσεται με τη δήλωση if (x) επειδή δεν αποτελεί τμήμα του κώδικα της if (y).

 

            Το παραπάνω διαπιστώνεται από μία πιο εξελιγμένη μορφή του προγράμματος magic number (αν ο αριθμός δεν είναι ίσος με το μαγικό αριθμό, να τυπώνει ο αριθμός που δώσαμε είναι μεγαλύτερος ή μικρότερος ανάλογα).

 

Π.χ. :               # include <stdio.h>

                        main ( )

                        {

                          int magic = 123;

                          int guess;

                          scanf (“%d”, &guess);

                          if (guess == magic);

                          {

                            printf (“**Right**”);

                            printf (“%d” is the magic number”, magic);

                          }

                        else

                        {

                          printf (“..Wrong..”);

                          if (guess>magic) printf (“Too High”);

                          else printf (“Too Low”);

                          }

                        }

 

            Στο πρόγραμμα αυτό εισάγουμε μέσω της scanf ( ) μία τιμή για τη μεταβλητή guess. Ελέγχουμε αν αυτή ισούται με τη magic και αν ναι τυπώνουμε το ανάλογο μήνυμα καθώς επίσης και το μαγικό αριθμό. Αν δεν ισούται τυπώνουμε λάθος και ελέγχουμε αν η τιμή που δόθηκε είναι μεγαλύτερη από την τιμή της magic ή όχι και τυπώνουμε τα ανάλογα μηνύματα.

 

Η σκάλα ifelseif

 

            Μία άλλη κοινή προγραμματιστική δομή είναι η σκάλα ifelseif. Αυτή μοιάζει με :

 

                                    if (expression)

                                        statement;

                                    else

                                    if (expression)

                                        statement;

                                    else

                                    if (expression)

                                        statement;

 

            Οι συνθήκες ιεραρχούνται από πάνω προς τα κάτω. Από τη στιγμή που θα βρεθεί αληθής συνθήκη, εκτελείται το μπλοκ κώδικα που αναφέρεται σ’ αυτή και η υπόλοιπη «σκάλα» προσπερνάται. Αν καμία συνθήκη δεν είναι αληθής θα εκτελεστεί το τελευταίο else. Το τελευταίο else συνήθως αντιδρά σα μία εξορισμού συνθήκη που σημαίνει ότι αν όλες οι άλλες συνθήκες αποτύχουν τότε αυτό το else εκτελείται. Αν δεν υπάρχει τελικό else δεν έχουμε καμία δράση αν όλες οι άλλες συνθήκες είναι ψευδείς.

 

Π.χ. :               #include <stdio.h>

                        main ( )

                        {

                          int magic = 123;

                          int guess;

                          scanf (“%d”, &guess);

                          if (guess == magic)  {

                               printf (“**Right**”);

                               printf (“%d is the magic number”, magic);

                        }

                          else

                            if (guess > magic)

                            printf (“..Wrong.. Too High”);

                           else printf (“..Wrong.. Too Low);

                        }

 

i)                    Ο τελεστής ?

 

            Ο τριαδικός τελεστής μπορεί να χρησιμοποιηθεί για την αντικατάσταση if / else δομών. Έχει τη γενική μορφή:

 

                                    Exp1 ?  Exp2  :  Exp3

 

            Το θέμα είναι ότι εδώ τα αποτελέσματα και του if και του else είναι απλές εκφράσεις και όχι άλλες δηλώσεις της.

 

Π.χ.:


x = 10;

y = x > 9 ? 100 : 200;

x = 10;

if (x > 9 )  y = 100;


else  y = 200;

 

            Βλέπουμε ότι πρώτα εκτιμάται η έκφραση αριστερά του ? και ανάλογα παίρνει τιμή το y. Στην προκειμένη περίπτωση θα έχουμε y = 100.

 

            Υπενθυμίζουμε ότι όλες οι συναρτήσεις (εκτός αυτές που έχουν δηλωθεί σαν void) επιστρέφουν κάποια τιμή. Έτσι μπορούμε να χρησιμοποιήσουμε μία ή περισσότερες συναρτήσεις σε μία C έκφραση. Επίσης είναι δυνατό να εκτελέσουμε περισσότερες από μία συναρτήσεις χρησιμοποιώντας τον τελεστή ?.

 

Π.χ.:                     #include <stdio.h>

                            main ( )

                            {

                              int t;

                              scanf (“%d”, &t);

                              t ? f1(t) + f2(t) : printf ( “Zero entered”);

                            }

                            f1 (n);

                            int n;

                            {

                              printf (“%d“, n);

                            }

                            f2 ( );

                            {

                              printf (“entered“);

                            }

 

            Στο ανωτέρω παράδειγμα αν στη scanf( ) εισαχθεί ο (ψευδή τιμή) εκτελείται η printf ( ) στα δεξιά της έκφρασης. Αν εισαχθεί άλλος αριθμός εκτελούνται οι συναρτήσεις f1( ) και f2( ). Σημειώνουμε ότι η αξία της ? έκφρασης απορρίπτεται σ’ αυτό το παράδειγμα και δεν είναι απαραίτητο να καταχωρηθεί πουθενά.

 

            Το πρόγραμμα του magic number μπορεί να ξαναγραφεί ως εξής:

 

                            #include <stdio.h>

                            main( )

                            {

                            int magic = 123;

                            int guess;

                            scanf (“%d”, &guess);

                            if (guess == magic);

                            {

                              printf (“**Right**”);

                              printf (“The Magic Number is %d”, magic);

                            }

                            else

                              guess > magic ? printf (“Too High”) : printf (“Too Low”);

                            }

 

            Εδώ το αποτέλεσμα βασίζεται στη σχέση guess > magic.

 

ii)                   Η εντολή Switch

 

Αν και η σκάλα ifelseif μπορεί να εκτελέσει πολλά τεστ, είναι δύσκολο να ελεγχθεί. Ο κώδικας διαβάζεται δύσκολα ακόμη και από τον ίδιο τον συγγραφέα σε μετέπειτα χρονικά διαστήματα. Γι’ αυτό το λόγο η C διαθέτει ένα ενσωματωμένο πολύ-επιλογέα, ο οποίος λέγεται switch.

Η γενική σύνταξη της εντολής είναι:

                                   switch (variable)  {

                                       case const1;

                                           statement sequence;

                                           break;

                                       case const2;

                                            statement sequence;

                                            break;

                                               

                                               

                                          default:

                                             statement sequence;

                                   }

 

Η δομή αυτή είναι παρόμοια με τη δομή case, που χρησιμοποιούν οι άλλες high level γλώσσες.

 

Όταν η δήλωση default εκτελεστεί, σημαίνει ότι δεν έχει βρεθεί η συνθήκη. Το default είναι προαιρετικό και παίρνει τη θέση του case else.

 

Όταν βρεθεί ταίρι, εκτελείται η σειρά εντολών που έχει συνταχθεί με την ανάλογη case, έως ότου συναντηθεί η εντολή break (ή στην περίπτωση του default ή του last case, αν δεν υπάρχει default, το τέλος του switch).

 

Υπάρχουν τρία σημαντικά πράγματα γύρω από τη switch:

 

1.      Η switch διαφέρει από την if αφού μπορεί να ελέγξει μόνο για ισότητα, ενώ η if μπορεί να εκτιμήσει κάθε σχεσιακή ή λογική έκφραση.

2.      Δε μπορούν δύο case, μέσα στην ίδια switch, να έχουν την ίδια τιμή. Φυσικά αυτό μπορεί να γίνει στην περίπτωση των nested switch.

3.      Αν χρησιμοποιούνται χαρακτήρες στη switch, αυτοί αυτομάτως ανάγονται στις αριθμητικές τιμές τους.

 

Π.χ.                      main ( )

                            {

                              char ch;

                              printf ( “1. Check Spelling Errors\n”);

                              printf ( “2. Correct Spelling Errors \ n”);

                              printf ( “ 3. Display Spelling Errors \ n “);

                              printf ( “ Strike other key to skip \n”);

                              printf ( “… Enter Your Choice…”);

                              ch = getche ( ) ;

                              switch (ch)

                              {

                                 case ‘ 1 ‘ ;

                                        check_spelling ( ) ;

                                        break;

                                 case ‘ 2 ‘ ;

                                        correct_errors ( ) ;

                                 case ‘ 3 ‘ ;

                                        display_errors ( ) ;

                                        break;

                                 default :

                                        printf (“No Option Selected”);

                                 } 

                              } /* Ends Program */

 

            Τεχνικά η δήλωση break είναι προαιρετική μέσα στη switch. Αν δε χρησιμοποιηθεί, η ροή της εκτέλεσης θα μεταφερθεί στο αμέσως ανώτερο τμήμα κώδικα. Μπορούμε να φανταστούμε τα case σαν ετικέτες. Η εκτέλεση αρχίζει εφόσον η ετικέτα ταιριάζει με τη συνθήκη και συνεχίζεται έως ότου συναντηθεί break ή τέλος της switch.

 

Π.χ.:                          main ( )

                                 {

                                    int ch, flag;

                                    ch = read_device ( ) ;

                                    flag = -1;

                                    switch (ch)

                                    {

                                    case 1:    /*These cases have common statement*/

                                    case 2:     /* Sequences*/

                                    case 3:

                                        flag = 0;

                                        break;

                                    case 4:

                                        flag = 1;

                                    case 5:

                                        error (flag);

                                        break;

                                    default:

                                        process (ch);

                                    }

                                 }   / * End of Code * /

 

            Στην περίπτωση αυτή οι 3 πρώτες επιλογές ( οι 2 πρώτες είναι άδειες, γιατί περιέχουν μόνο σχόλια) εκτελούν το ίδιο πράγμα :          

flag = 0 ;

break;

 

            Είναι σημαντικό να κατανοηθεί ότι οι δηλώσεις που συνοδεύουν κάθε ετικέτα, δεν είναι code blocks (τμήμα εντολών = {………}), αλλά statement sequences. Φυσικά η όλη δήλωση της switch αποτελεί code block. Αυτή η διαφοροποίηση γίνεται κατανοητή σε ειδικές περιπτώσεις. Για παράδειγμα αποτελεί λάθος να πούμε :

                                   

                                    / * Αυτό είναι Λάθος * /

                                    switch (c)  {

                                       case 1:

                                           auto int t ;

                                                :

γιατί δεν είναι δυνατό να δηλώσουμε μία auto (local) variable μέσα σε statement sequence.

 

            Παρ’ όλ’ αυτά, μία auto μεταβλητή μπορεί να προστεθεί όπως φαίνεται παρακάτω:

 

                                 / * Αυτόε είναι Λάθος * /

                                 switch ( c )

                                 {

                                   auto int t;

                                   case 1:

                                        :

ή μέσα σε code block ως εξής:

                                 / * Αυτό είναι Σωστό * /

                                 switch ( c )

                                 {

                                 case 1:

                                      if ( 1 )

                                      {

                                      / * Η συνθήκη είναι μονίμως αληθής * /

                                      auto int t;

                                      :

                                    }

                                    :

                                 }     / * Ends Switch * /

 

 

Nested Switch Statements

 

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

Π.χ.

            switch (x)   {

              case 1:

                switch (y)  {

                        case 0: printf (“divide by zero error”);

                                     break;

                        case 1: process (x, y);

                      }

                      break;

                case 2:

                     :

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

 

 

ΙΙ. ΒΡΟΓΧΟΙ

 

Στην C, όπως και στις άλλες μοντέρνες γλώσσες προγραμματισμού, τα loops αποτελούν ένα σετ εντολών, που εκτελείται έως ότου συναντηθεί μία βέβαια συνθήκη.

 

1.      Η εντολή For

Ο γενικός τρόπος σύνταξης του βρόγχου For είναι λίγο – πολύ γνωστός σ’ όλους τους προγραμματιστές μιας και χρησιμοποιείται σ’ όλες τις δομημένες γλώσσες. Πάντως στη C έχει πολύ μεγάλη ισχύ και δύναμη. Η σύνταξη της εντολής είναι:

 

                          For (initialization; condition; increment)

                          {

                            statement;

                          }

 

όπου: Α) initialization, είναι συνήθως μία δήλωση, που χρησιμοποιείται για να αρχικοποιήσει (δηλ. για να δώσει αρχική τιμή) την loop control variable (δείκτη της for).

          Β) condition, είναι μία οποιαδήποτε λογική ή σχεσιακή έκφραση, η οποία ορίζει πότε το loop θα τελειώσει.

          Γ) increment, δείχνει το βήμα μεταβολής του δείκτη (loop control variable) της for σε κάθε εκτέλεσή του.

 

Οι τρεις αυτοί τομείς πρέπει να διαχωρίζονται με ερωτηματικά (ελληνικά). Ο βρόγχος for συνεχίζει να εκτελείται όσο η συνθήκη είναι αληθής.

Π.χ.:                   main ( )

                          {

                             knt x;

                             for (x=1;x<=100; x++) printf (“%d”, x);

                          }

 

Σ’ αυτό το παράδειγμα το x τοποθετείται αρχικά στο 1. Εφόσον το x είναι μικρότερο ή ίσο του 100, καλείται η συνάρτηση printf( ) και το x αυξάνεται κατά 1. Η διαδικασία αυτή επαναλαμβάνεται έως ότου το x πάρει τιμή μεγαλύτερη του 100. Στην περίπτωση αυτή το x αποτελεί loop control variable (δείκτη της for), η οποία αυξάνεται και ελέγχεται σε όλες τις εκτελέσεις της for.

 

Π.χ.:                for (x=100; x!=65; x-=65)

                        {

                          z = sqrt (x);

                          printf (“The square root of %d, %f, x, z);

                        }

           

            Οι συναρτήσεις sqrt( ) και printf( ) εκτελούνται έως ότου το x να γίνει ίσο με 65. Σημειώνεται ότι αυτό το loop έχει αρνητικό βήμα (ξεκινάει από το 100 και μειώνει κατά 5 κάθε φορά που εκτελείται).

 

            Είναι σημαντικό να σημειώσουμε στα for loops, ότι τα τεστ εκτελούνται πάντα στην αρχή του loop. Αυτό σημαίνει ότι ο κώδικας μέσα στο loop δε θα εκτελεστεί αν η συνθήκη είναι ψευδής από την αρχή του τεστ.

 

Π.χ.:                x=10;

                        for (y=10; y!=x ; ++y) printf ( “%d”, y) ;

                        printf (“%d”, y);

 

            Ο βρόγχος αυτός δεν εκτελείται ποτέ γιατί x και y είναι ίσα στην αρχή του βρόγχου. Επειδή η συνθήκη είναι ψευδής, ούτε το σώμα του loop, ούτε και η αύξηση της μεταβλητής εκτελούνται. Άρα θα τυπωθεί y = 10 από το δεύτερο printf( ).

 

 

(i)                  ΠΑΡΑΛΛΑΓΕΣ ΤΩΝ ΒΡΟΓΧΩΝ ΤΥΠΟΥ FOR (FOR LOOP VARIATIONS)

 

Μία από τις κυριότερες παραλλαγές της for είναι η χρήση του τελεστή, ο οποίος επιτρέπει σε δύο ή περισσότερες μεταβλητές να ελέγχουν το βρόγχο (Υπενθυμίζεται ότι ο τελεστής ενώνει μαζί δύο ή περισσότερες εκφράσεις με τη μορφή του «κάνει αυτό κι αυτό»). Για παράδειγμα το παρακάτω loop χρησιμοποιεί τις μεταβλητές x και y για έλεγχο ενός βρόγχου, όπου και οι δύο μεταβλητές αρχικοποιούνται μέσα στο for.

Π.χ.:          for (x=0, y=0; x + y <10; ++x) 

                  {

                    y = getchar( ) ;

                    y = y – ‘0’ ;

                  }

 

            Εδώ το κόμμα διαχωρίζει τις δύο δηλώσεις αρχικοποίησης. Κάθε φορά που το x αυξάνει, ο βρόγχος εκτελείται, ενώ η τιμή της y τοποθετείται από μία τιμή από το πληκτρολόγιο. Είναι απαραίτητο το y να λαμβάνει αρχική τιμή μέσα στο βρόγχο, έτσι ώστε να μη γίνεται να αλλάξει τιμή έξω από αυτόν με απρόβλεπτες συνέπειες.

 

            Άλλη παραλλαγή περιλαμβάνει πολλές loop control variables.

            Π.χ.:                 for (i = 1, j = 0; i> 0; j++, i--)

 

            Η σχεσιακή έκφραση δεν είναι απαραίτητο να περιέχει μόνο απλό τεστ σε κάποια τιμή μιας μεταβλητής. Στην πραγματικότητα η συνθήκη μπορεί να είναι κάθε λογική ή σχεσιακή δήλωση. Αυτό σημαίνει ότι μπορούμε να ελέγξουμε για αρκετές πιθανές συνθήκες τέλους.

 

Π.χ.:                            #include <stdio.h>

                                    #include <string.h>

                                    main( )

                                    {

                                      char str[20];

                                      int x;

                                      printf( “Enter Password Please : “);

                                      gets(str);

                                      for (x=0; x<3 && strcmp (str, “AB-314-AZ”) ++ x )

                                      {

                                        printf (“Enter Password Please : “);

                                        gets (str);

                                      }

                                      if (x==3) hang_up( );

                                    }

           

            Υπενθυμίζεται ότι η strcmp( ) είναι συνάρτηση βιβλιοθήκης της C, η οποία βρίσκεται στο string.h. Η συνάρτηση αυτή συγκρίνει λεξικογραφικά δύο strings και επιστρέφει έναν ακέραιο βασισμένο στο αποτέλεσμα όπως παρακάτω:

 

Τιμή

-1

0

1

Έννοια

str1 is less than str2

str1 is equal to str2

str1 is greater to str2


 

Το πρωτότυπό της είναι : int strcmp (char *str1, char *str2);

 

            Μία ακόμη ενδιαφέρουσα παραλλαγή του for loop προκύπτει με την υπενθύμιση ότι κάθε ένα από τα τρία τμήματα της for μπορεί να αποτελείται από κάθε σωστή έκφραση C. Έτσι στη συνθήκη όπως ήδη είδαμε, μπορεί να εμπεριέχεται ακόμη και κλήση συνάρτησης. Π.χ.:

                        main ( )

                        {

                          int t;

                          for (prompt( ); t= readnum( ); prompt( ) )

                          sqrnum (t);

                        }

                        prompt ( )

                        {

                           printf( “:  “);

                        }

                        readnum ( )

                        {

                          int t;

                          scanf ( “%d”, &t);

                          return t ;

                        }

                        sqrnum (num)

                        int num ;

                        {

                           printf (“%d” \ n, num * num);

                        }

 

            Εδώ ένα for εκτελείται, ενώ το σώμα του for αποτελείται από κλήσεις συναρτήσεων. Στην προκειμένη περίπτωση κάθε κομμάτι της for καλεί μία συνάρτηση, η οποία ζητά από το χρήστη να δώσει έναν αριθμό. Αν αυτός είναι μηδέν (0), τότε σταματά γιατί η συνθήκη γίνεται ψευδής, αλλιώς ο αριθμός τετραγωνίζεται. Εδώ βέβαια το πρώτο και το τρίτο τμήμα της for χρησιμοποιούνται με τρόπο παράξενο αλλά σωστό.

 

            Είδαμε ότι η for αποτελείται από τρία τμήματα. Το τμήμα αρχικοποίησης, το τμήμα συνθήκης και το τμήμα αύξησης. Στην πραγματικότητα δεν υπάρχει καμία ανάγκη ύπαρξης κανενός από αυτά τα τμήματα, είναι όλα προαιρετικά.

 

Π.χ.:    Το παρακάτω loop «τρέχει» έως ότου εισαχθεί τιμή 123.

            for (x = 0; x!=123;) scanf (“%d”, &x);

 

            Σημειώνεται ότι εδώ δεν υπάρχει τμήμα αύξησης στη for. Αυτό σημαίνει ότι κάθε φορά που το loop επαναλαμβάνεται, το x εξετάζεται αν είναι ίσο με 123, αλλά καμία άλλη ενέργεια δεν εκτελείται. Αν όμως εισαχθεί 123 η συνθήκη ικανοποιείται και το loop τερματίζεται.

 

            Επίσης είναι συνηθισμένο το τμήμα αρχικοποίησης να βρίσκεται έξω από το for. Αυτό μπορεί να είναι απαραίτητο για διάφορους πολύπλοκους λόγους.

Π.χ.:                gets (s);

                        if (*s) x=strlen(s);

                        for (; x<10 ; ) {

                          printf(“%d”, x);

                          ++x;

                        }

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

 

(ii)                Ο ΑΤΕΡΜΩΝ ΒΡΟΓΧΟΣ (The Infinite Loop)

 

Mία από τις πιο ενδιαφέρουσες χρήσεις του for είναι η χρήση του για δημιουργία ατέρμωνος βρόγχου. Εφόσον δεν υπάρχει καμία από τις τρεις εκφράσεις που χρειάζεται το loop, είναι δυνατό να δημιουργήσουμε ένα βρόγχο χωρίς τέλος. Βασικά αυτό που χρειάζεται είναι να μην υπάρχει τμήμα συνθήκης.

 

Π.χ.:  for(;;) printf (“ This loop will run forever.\n”);

 

Σημ.: Πολλοί προγραμματιστές χρησιμοποιούν τη while (1) για τη δημιουργία ενός infinite loop. Και οι δύο μέθοδοι δουλεύουν το ίδιο σωστά. Πάντως το for(;;) συνίσταται επειδή το χρησιμοποιούν περισσότεροι.

 

Ο τρόπος εξόδου από έναν ατέρμωνα βρόγχο είναι η χρήση της break. Με τη χρήση της, ο έλεγχος της ροής του προγράμματος περνά στο αμέσως επόμενο τμήμα κώδικα έξω από το loop.

 

Π.χ.:         for (;;)

                {

                  ch=getchar ( );

                  if ( ch ==’A’) break;

                }

                printf( “ You typed an A”);

 

O βρόγχος θα εκτελείται έως ότου πατηθεί Α από το πληκτρολόγιο.

 

(iii)               FOR LOOPS WITH NO BODIES

 

Μία δήλωση στη C μπορεί να είναι κενή. Έτσι, μπορούμε να έχουμε κενά σώματα σε βρόγχους for. Αυτό χρησιμοποιείται για την αύξηση της αποτελεσματικότητας πολλών αλγορίθμων, αλλά κυρίως το συναντούμε στη δημιουργία time-delay loops.

 

Π.χ.:           for (t=0; t<=10000; t++);

 

Εδώ θα εκτελεστεί ένας βρόγχος, ο οποίος δεν εκτελεί καμία ενέργεια για 10000 φορές.

 

 

 

2.      Η εντολή while

 

Το δεύτερο loop, που είναι διαθέσιμο στη C είναι το while. Η γενική σύνταξή του είναι:        while (condition) statement;

 

όπου statement μπορεί να είναι ένα: α) empty statement

                                                            β) single statement

                                                            γ) block statement

 

και condition μπορεί να είναι κάθε έκφραση με αληθή τιμή, κάθε μη μηδενική τιμή.

            Το while loop εκτελείται εφόσον η συνθήκη είναι αληθής. Όταν αυτή γίνει ψευδής ο έλεγχος του προγράμματος περνά στη γραμμή μετά το τέλος του loop.

 

Π.χ.:                main( )

                        {

                          char ch;

                          ch=’\0’;

                          while (ch!=’A’) ch=getchar ( );

                        }

 

            Πρώτα το ch αρχικοποιείται στο null. Το while ελέγχει τη συνθήκη, η οποία είναι αληθής (αφού το ch έχει αρχικοποιηθεί έτσι). Κάθε φορά που ένα πλήκτρο πατιέται στο πληκτρολόγιο, ο βρόγχος επαναλαμβάνεται και το τεστ εκτελείται ξανά. Εφόσον καταχωρηθεί ‘Α’ η συνθήκη γίνεται ψευδής και το loop σταματά.

            Όπως στα for loops, έτσι και στο while, ο έλεγχος γίνεται στην αρχή της συνθήκης, που σημαίνει ότι ενδέχεται ο κώδικας μέσα στο loop να μην εκτελεστεί καθόλου.

            Φυσικά μέσα στο loop μπορούν να εκτελούνται διάφορες εργασίες. Π.χ.:

 

                        void funk1( )

                        {

                          int working;

                          working=1;

                          while (working)

                          {

                            working = process1( );

                            if (working) working = process2( );

                            if (working) working = process3( );

                          }   /* End of loop */

                        }     /* End of program  */

 

            Φυσικά ενδέχεται το while loop να μην έχει καθόλου «σώμα». Π.χ.:

                        while ( ( ch =getchar ( ) ) ! = ‘A’ );

            Έτσι απλά το loop τελειώνει αν πατηθεί Α από το πληκτρολόγιο.

 

 

3. Η εντολή Do / While

 

            Αντίθετα με τα loop for και while, που ελέγχουν τη συνθήκη στην αρχή του loop, το do / while ελέγχει τη συνθήκη στο τέλος του loop. Αυτό σημαίνει ότι το «σώμα» του βρόγχου θα εκτελεστεί τουλάχιστον μία φορά. Ο γενικός τύπος σύνταξης είναι:

                                                            do

                                                            {

                                                              statement;

                                                            } while (συνθήκη);

 

            Παρ’ όλ’ αυτά τα { } δεν είναι απαραίτητα αν υπάρχει μόνο ένα statement και χρησιμοποιούνται για να αυξάνουν την αναγνωσιμότητα του κώδικα.

 

Π.χ.:                do {

                            scanf (“%d”, &num);

                        } while (num>100) ;

 

            Εδώ η scanf( ) εκτελείται έως ότου εισαχθεί τιμή μικρότερη ή ίση από 100.

 

            Κυρίως η do / while εκτελείται σε ρουτίνες επιλογής μενού.

Π.χ.:                menu ( )

                        {

                          char ch ;

                          printf ( “1. Check spelling\n”);

                          printf ( “2. Correct spelling Errors\n”);

                          printf ( “1. Display spelling Errors\n”);

                          do

                          {

                            ch=getche( );

                            switch (ch)

                            {

                               case ‘1’ :

                                    check_spelling( );

                                    break :

                               case ‘2’ :

                                    correct_spelling( );

                                    break :

                               case ‘3’ :

                                    display_errors( );

                                    break :

                               }

                            }

                          while (ch!=’1’ && ch!=’2’ &&ch!=’3’);

                        }

 

            Στην περίπτωση του μενού (menu) θέλουμε το loop να εκτελείται τουλάχιστον μία φορά. Έπειτα ο βρόγχος εκτελείται συνεχώς, έως ότου εισαχθεί αποδεκτή τιμή.

 

4.      Η εντολή Break

 

Η δήλωση break έχει δύο χρήσεις. Η πρώτη είναι να τελειώνει μία case μέσα στο switch. Η δεύτερη χρήση είναι να οδηγεί σε άμεσο τερματισμό ενός loop, προσπερνώντας τον κανονικό έλεγχο του loop. Αυτή η εκδοχή εξετάζεται εδώ.

 

Όταν μία break συναντάται μέσα σε ένα loop do / while, αυτό σταματά αμέσως και ο έλεγχος της ροής περνά στη συνθήκη, την οποία και θα μετατρέψει σε ψευδή. Όταν συναντάται μέσα σε ένα loop for ή while, αυτό σταματά αμέσως και ο έλεγχος της ροής περνά στην αμέσως επόμενη εντολή έξω από το loop.

Π.χ.:       main( )

              {

                 int t;

                 for (t=0; t<100; t++)

                 {

                   printf (“%d”, t);

                   if  (t==10) break;

                    }

                 }

 

Αυτό εμφανίζει τους αριθμούς από το 0 ως το 10 στην οθόνη και κατόπιν τερματίζεται από την break, υπερπηδώντας τον έλεγχο t<100, που βρίσκεται στο loop.

Σε περίπτωση nested βρόγχων η χρήση της break θα προκαλέσει έξοδο από τον εσωτερικό βρόγχο μόνο.

Π.χ.:     for (t=0;t<100; +=t)  {

                          count = 1;

                            for (;;)  {

                              printf (“%d”, count);

                              count++;

                              if (count ==10) break;

                          } /* Ends Inner Loop */

                        }   /* Ends Outer Loop */

 

Αυτό το παράδειγμα θα εμφανίσει στην οθόνη τους αριθμούς 1 έως 10 εκατό φορές. Κάθε φορά που το break εκτελείται η ροή περνά στον εξωτερικό βρόγχο.

 

Ένα break, που χρησιμοποιείται μέσα σε switch, θα προκαλέσει έξοδο από το switch και όχι από το loop, που αυτό βρίσκεται.  Π.χ.:

           

            for (x=0; x<=100; x++)

            {

              scanf (“%d”, &num);

              switch (num)

                 {

                   case 1 :

                     function1( ) :

                     break ;

                   case 2 :

                     function2( ) :

                     break ;

                   }  /* Ends switch */

                 }    /* Ends for  */

 

            Στο ανωτέρω παράδειγμα, όταν η break συναντάται τότε η ροή περνά στον βρόγχο που βρίσκεται εξωτερικά του switch.

 

5.      Η συνάρτηση exit ( )

 

Η συνάρτηση exit( ) είναι συνάρτηση βιβλιοθήκης και το πρωτότυπό της βρίσκεται δηλωμένο στο <process.h>  :

 

                                    void exit (int status);

 

            Η κλήση αυτής της συνάρτησης προκαλεί τον άμεσο ομαλό τερματισμό ενός προγράμματος. Η τιμή του status περνιέται κατά τη διάρκεια της κλήσης. Αν η τιμή του status είναι 0, τότε προκαλείται ομαλός τερματισμός του προγράμματος. Μια μη μηδενική τιμή στην κλήση της exit( ) θα προκαλέσει τον μη ομαλό τερματισμό του προγράμματος.

            Η κλήση της exit( ) κλείνει όλα τα ανοιχτά αρχεία, γράφει όλα τα δεδομένα που βρίσκονται στον buffer, και προκαλεί τον τερματισμό όλων των συναρτήσεων και προγραμμάτων.

Π.χ.:

                         main( )

                        {

                          char ch;

                          printf (“1. Check Spelling \n”);

                          printf (“2. Correct Spelling Errors \n”);

                          printf (“3. Display Spelling Errors \n”);

                          printf (“4. Quit\n”);

                          printf (” … Enter Your Choice:…”);

                          do

                          {

                            ch= getchar ( );

                            switch(ch)  {

                               case ‘1’:

                                 check_spelling();

                                 break;

                               case ‘2’:

                                 correct_errors();

                                 break;

                               case ‘3’:

                                 display_errors( );

                                 break;

                               case ‘4’:

                                 exit (0);               /* return to O.S.  */

                               }                /*Ends switch */

                            }   while (ch!=’1’ && ch!=’2’ && ch!=’3’);

                        }     /* End of main function  */

 

6.      H εντολή Continue

 

Η εντολή continue λειτουργεί περίπου σαν την break. Αντί όμως να σταματά τη διαδικασία εκτέλεσης του βρόγχου, η continue στέλνει τη ροή της εκτέλεσης στην αρχή του loop, αναγκάζοντάς το να εκτελεστεί ξανά, περνώντας όλο τον κώδικα που τυχόν υπάρχει ενδιάμεσα.

Π.χ.:     do

                        {

                          scanf(“%d”, &x);

                          if (x<0) continue ;

                          printf (“%d”, x);

                        }

                        while (x!=100);

 

            Ο κώδικας αυτός θα τυπώσει μόνο τους θετικούς αριθμούς προσπερνώντας το υπόλοιπο του loop σε αντίθετη περίπτωση. Φυσικά το loop θα σταματήσει αν δοθεί x = 100.

            Στις περιπτώσεις while και do/ while η δήλωση continue θα στείλει τον έλεγχο κατευθείαν στο conditional test (τεστ συνθήκης) και κατόπιν θα συνεχίσει την εκτέλεση του βρόγχου. Στην περίπτωση της for πρώτα το τμήμα της αύξησης θα εκτελεστεί, έπειτα η συνθήκη και τέλος το loop θα συνεχίσει.

 

            Π.χ.:     for (t=0; t<100; ++t)

                        {

                          scanf (“%d”, &x);

                          if (x<0) continue ;

                          printf (“%d”, x);

                        }

            Ο βρόγχος αυτός θα εμφανίσει μόνο 100 αριθμούς κι όχι 101.

 

            Π.χ.      void code( )

                        {

                          char done, ch ;

                          done=0;

                          while (!done)

                          {

                            ch= getchar( );

                            if (ch==’$’)

                            {

                              done =1;

                              continue;

                            }

                            putchar (‘\n’);           /* Εκτύπωση new line  */

                          }         /* End of while  */

                        }           /*  End of function  */

 

            Η continue εδώ στέλνει τη ροή στον έλεγχο και φυσικά ο βρόγχος τερματίζεται, αφού η συνθήκη γίνεται ψευδής.

 

 

7.      Labels και Goto

 

Η C είναι μία γλώσσα αρκετά πλούσια σε δομές ελέγχου, οπότε μία εντολή σαν τη goto δε χρειάζεται να χρησιμοποιείται πολύ. Σε ορισμένες (λίγες) πάντως περιπτώσεις αν χρησιμοποιηθεί σωστά μπορεί να δώσει λύσεις σε ορισμένα προγραμματιστικά προβλήματα. Ο λόγος που δε χρησιμοποιείται είναι ότι δημιουργεί σύγχυση σε ένα πρόγραμμα (όσον αφορά την αναγνωσιμότητά του) και οδηγεί στη συγγραφή προγραμμάτων «μακαρονάδων».

 

Η goto απαιτεί, για να λειτουργήσει, ένα label. Ένα label είναι μία αποδεκτή από τη C ταυτότητα, ακολουθούμενη από “:”. Σημειώνεται ότι το label θα πρέπει να βρίσκεται μέσα στην ίδια συνάρτηση με τη goto που το καλεί.

 

Π.χ.:

                        x = 1;

                        loop1:

                        x++;

                        if (x<100) goto loop1;

 

Στο παράδειγμα αυτό ο κώδικας θα μετρήσει από το 1 ως το 100 και στο τέλος, όταν ικανοποιηθεί η συνθήκη του if (x=100), ο βρόγχος θα τελειώσει.

 

Π.χ.:

            #include<stdio.h>

            main( )

            {

              int x;

              int y=1;

              label1:

              scanf (“%d”, &x);

              printf (”%d”, x);

              y++;

              if (y<10) exit (0);

              goto label1;

            }

 

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