ΚΕΝΤΡΟ ΠΛΗ.ΝΕ.Τ. Ν. ΦΛΩΡΙΝΑΣ

Η Γλώσσα Προγραμματισμού C
(Μέρος 2 - Οι Bασικές Εντολές της C)

 

Οι Βασικοί Τελεστές της C

Η C, όπως όλες οι γλώσσες προγραμμστισμού, χρησιμοποιεί τελεστές για να εκτελέσει τις αριθμητικές λειτουργίες. Το = είναι ένας τελεστής καταχώρησης τιμών. Πρέπει να έχουμε υπόψη μας ότι δεν μπορούμε να καταχωρήσουμε τιμή σε μια σταθερά και το μέρος στα αριστερά του συμβόλου = πρέπει να είναι το όνομα της μεταβλητής και αναφέρεται σε μία θέση αποθήκευσης.

Εφαρμογές της εντολής αυτής είναι οι εξής :

            year = 2006;

            i = i + 1;

            timi01 = timi02 = timi03 = 68;

Στην τελευταία εντολή οι καταχωρήσεις γίνονται από τα δεξιά προς τα αριστερά.

Υπάρχουν ακόμα και οι τελεστές πρόσθεσης +, αφαίρεσης -, πολλαπλασιασμού * και διαίρεσης /. Στη διαίρεση πρέπει να έχουμε υπόψη μας ότι η διαίρεση με αριθμούς κινητής υποδιαστολής δίνει αποτέλεσμα του ίδιου τύπου, ενώ η διαίρεση με ακεραίους δίνει μια ακέραια απάντηση.

Έτσι, αν η διαίρεση ακεραίων δεν είναι τέλεια, η C απορρίπτει το δεκαδικό μέρος του πηλίκου χωρίς να το στρογγυλοποιεί. Αυτή η διαδικασία λέγεται αποκοπή. Όταν ανακατεύουμε ακεραίους με αριθμούς κινητής υποδιαστολής, το αποτέλεσμα είναι αριθμός κινητής υποδιαστολής.

Ακολουθεί ένα ερμηνευτικό παράδειγμα :

/* prog13.c – οι διαιρέσεις στη C */

#include <stdio.h>

main()

{

            printf("ακέραια διαίρεση :   5/3 είναι %d \n", 5/3);

            printf("ακέραια διαίρεση :   8/4 είναι %d \n", 8/4);

            printf("ακέραια διαίρεση :   7/5 είναι %d \n", 7/5);

            printf("διαίρεση κινητής υποδιαστολής : 7./4. είναι %1.2f \n", 7./4.);

            printf("μικτή διαίρεση :                    7./4 είναι %1.2f \n", 7./4);

}

Το αποτέλεσμα θα είναι :

            ακέραια διαίρεση :                            5/3 είναι 1

            ακέραια διαίρεση :                            8/4 είναι 2

            ακέραια διαίρεση :                            7/5 είναι 1

            διαίρεση κινητής υποδιαστολής :    7./4. είναι 1.75

            μικτή διαίρεση :                                 7./4 είναι 1.75

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

 

Οι Προτεραιότητες των Τελεστών

Η C τοποθετεί κάθε τελεστή σε κάποιο επίπεδο προτεραιότητας. Ο πολλαπλασιασμός και η διαίρεση ανήκουν σε υψηλότερο επίπεδο προτεραιότητας από την πρόσθεση και την αφαίρεση, γι' αυτό και εκτελούνται πρώτα. Αν, όμως, τελεστές του ίδιου επιπέδου προτεραιότητας επιδρούν στον ίδιο τελεστέο, τότε εκτελούνται με τη σειρά εμφάνισής τους στην πρόταση. Για τους περισσότερους τελεστές, η σειρά εκτέλεσης είναι από αριστερά προς τα δεξιά και ο τελεστής = αποτελεί εξαίρεση.

Δηλαδή, στην πρόταση :

            a = 25.0 + 60.0 * b / c;

γίνεται πρώτα ο πολλαπλασιασμός 60.0 * b, μετά η διαίρεση αυτού με τη μεταβλητή c και τέλος προστίθεται το 25.0.

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

            a = (25.0 + 60.0 * b) / c;

 

Ο Τελεστής sizeof

Ο τελεστής αυτός επιστρέφει το μέγεθος σε bytes του τελεστέου του. Ο τελεστέος μπορεί να είναι το όνομα μιας μεταβλητής ή μπορεί να είναι ένας τύπος. Αν είναι τύπος ονόματος, τότε πρέπει ο τελεστέος να μπει μέσα σε παρενθέσεις, αλλιώς οι παρενθέσεις είναι προαιρετικές.

Ακολουθεί ένα παράδειγμα :

/* prog14.c - ο τελεστής sizeof */

#include <stdio.h>

main()

{

            int n=10;

            printf("Ο n έχει %d bytes, όλοι οι ακέραιοι έχουν %d bytes. \n", sizeof n, sizeof(int));

}

Το αποτέλεσμα θα είναι :

            Ο 10 έχει 2 bytes, όλοι οι ακέραιοι έχουν 2 bytes.

 

Ο Τελεστής Ακεραίου Υπολοίπου %

Ο τελεστής ακεραίου υπολοίπου (%) χρησιμοποιείται στην αριθμητική των ακεραίων και επιστρέφει το υπόλοιπο της ακέραιας διαίρεσης του ακεραίου στα αριστερά με τον ακέραιο στα δεξιά. Για παράδειγμα, η πράξη 13 % 5 δίνει σαν αποτέλεσμα την τιμή 3, αφού το 5 χωράει δύο φορές στο 13 και έχει υπόλοιπο 3.

Ακολουθεί ένα παράδειγμα :

/* prog15.c – μετατρέπει τα δευτερόλεπτα σε λεπτά και σε δευτερόλεπτα */

#include <stdio.h>

#define SEC_PER_MIN 60     /* 60 δευτερόλεπτα σένα λεπτό */

main()

{

            int sec, min, left;

            printf("Μετατροπή δευτερολέπτων σε λεπτά και δευτερόλεπτα \n");

            printf("Δώστε τον αριθμό των δευτερολέπτων : \n");

            scanf("%d", &sec);       /* διάβασμα του αριθμού των δευτερολέπτων */

            min = sec / SEC_PER_MIN;   /* αριθμός λεπτών */

            left = sec % SEC_PER_MIN; /*αριθμός δευτερολέπτων που έμειναν*/

            printf(" %d δευτερόλεπτα είναι %d λεπτά και %d δευτερόλεπτα.\n", sec, min, left);

}

Το αποτέλεσμα θα είναι :

            Μετατροπή δευτερολέπτων σε λεπτά και δευτερόλεπτα

            Δώστε τον αριθμό των δευτερολέπτων :

            152

            152 δευτερόλεπτα είναι 2 λεπτά και 32 δευτερόλεπτα.

Όπως είδαμε στο παραπάνω παράδειγμα, για να υπολογίσουμε πόσα λεπτά υπάρχουν σ’ έναν αριθμό δευτερολέπτων sec, παίρνουμε το πηλίκο της ακέραιας διαίρεσης του sec με το SEC_PER_MIN, που είναι ουσιαστικά το 60 και για να βρούμε πόσα δευτερόλεπτα περίσσευσαν που δεν χώρεσαν σ’ ένα λεπτό, παίρνουμε το υπόλοιπο της ακέραιας διαίρεσης του sec με το SEC_ PER_MIN.

 

Ο Τελεστής Αύξησης ++

Ο τελεστής αύξησης (++) αυξάνει κατά ένα την τιμή του τελεστέου. Ο τελεστής αυτός υπάρχει σε δύο μορφές : Το ++ μπορεί να βρίσκεται πριν από την επηρεαζόμενη μεταβλητή και ονομάζεται τελεστής προγενέστερης αύξησης ή μετά απ’ αυτήν, οπότε ονομάζεται τελεστής μεταγενέστερης αύξησης.

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

Ακολουθεί ένα παράδειγμα :

/* prog16.c – χρήση του τελεστή αύξησης ++ */

#include <stdio.h>

main()

{

            int a = 0, b = 0;

            while (a < 5)

            {

                        a++;

                        ++b;

                        printf("b = %d, a = %d \n", b, a);

            }

}

Το αποτέλεσμα θα είναι :

            b = 1, a = 1

            b = 2, a = 2

            b = 3, a = 3

            b = 4, a = 4

            b = 5, a = 5

Θα μπορούσαμε να πάρουμε το ίδιο αποτέλεσμα χρησιμοποιώντας τις εξής εντολές :

            b = a + 1;

            a = a + 1;

Ο λόγος που χρησιμοποιούμε αυτόν τον τελεστή αύξησης είναι ότι έχει κάποια πλεονεκτήματα που θα φανούν αργότερα. Και για να γίνουμε πιο σαφείς, ακολουθεί ένα παράδειγμα :

            euro = 2.0;

            while (++euro < 100.00)

            {

                        draxmes = 340.75 * euro;

                        printf("%10.2f  %20.2f \n", euro, draxmes);

            }

Εδώ έχουμε συνδυάσει τη διαδικασία αύξησης και σύγκρισης του βρόχου while σε μία μόνο έκφραση, δηλ. η τιμή της μεταβλητής euro πρώτα αυξάνεται κατά 1 και αμέσως μετά συγκρίνεται με το 100.00. Έτσι, έχουμε τον έλεγχο του βρόχου και την αύξηση της μεταβλητής στο ίδιο μέρος.

Ας δούμε ακόμα ένα παράδειγμα :

/* prog17.c – προγενέστεροι και μεταγενέστεροι */

#include <stdio.h>

main()

{

            int a =1, b = 1;

            int aplus, plusb;

            aplus = a++;   /* μεταγενέστερος */

            plusb = ++b;   /* προγενέστερος */

            printf("a  aplus  b  plusb \n");

            printf("%1d  %5d  %5d  %5d\n", a, aplus, b, plusb);

}

Το αποτέλεσμα θα είναι :

            a  aplus  b  plusb

            2    1      2    2

Τόσο η a όσο και η b αυξάνονται κατά ένα. Επομένως, η aplus έχει την τιμή της a πριν η a αλλάξει και η plusb έχει την τιμή της b μετά την αλλαγή της b.

            aplus = a++;

/* μεταγενέστερη : η a άλλαξε μετά τη χρήση της τιμής της */

plusb = ++b;

/* προγενέστερη : η b άλλαξε πριν τη χρήση της τιμής της */

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

Για να συνοψίσουμε, το n++ σημαίνει :

                        "κάνε χρήση του n και μετά αύξησέ το"

και το ++n σημαίνει :

                        "αύξησε το n και μετά χρησιμοποίησέ το".

 

Ο Τελεστής Μείωσης - -

Δεν θα ήταν δυνατόν φυσικά να μην υπήρχε και ο αντίστοιχος τελεστής μείωσης, δηλ. αντί για το ++ χρησιμοποιούμε το - -.

            - -count;         /* τελεστής προγενέστερης μείωσης */

            count- -;         /* τελεστής μεταγενέστερης μείωσης */

Ακολουθεί κι ένα παράδειγμα με την χρήση του τελεστή μείωσης :

/* prog18.c – χρήση του τελεστή μείωσης */

#include <stdio.h>

#define MAX 100

main()

{

            int count = MAX + 1;

 

            while (- -count > 0)

            {

                        printf("Υπάρχουν %d βιβλία στη βιβλιοθήκη \n", count);

                        printf("Πάρε ένα βιβλίο, \n");

                        printf("%d βιβλία έμειναν στη βιβλιοθήκη \n\n", count-1);

            }

}

Το αποτέλεσμα θα είναι :

            Υπάρχουν 100 βιβλία στη βιβλιοθήκη

            Πάρε ένα βιβλίο,

            99 βιβλία έμειναν στη βιβλιοθήκη

            Υπάρχουν 99 βιβλία στη βιβλιοθήκη

            Πάρε ένα βιβλίο,

            98 βιβλία έμειναν στη βιβλιοθήκη

            ...

Οι τελεστές αύξησης και μείωσης έχουν υψηλή προτεραιότητα και μόνο οι παρενθέσεις έχουν υψηλότερη. Πρέπει πάντως να αποκτήσει κανείς αρκετή εμπειρία με τους τελεστές αύξησης και μείωσης, να μάθει τις ιδιαιτερότητες της έκδοσης της C με την οποία δουλεύει και μετά να τους χρησιμοποιεί.

Πρέπει να έχουμε υπόψη μας τα εξής :

Δηλαδή, οι παρακάτω εκφράσεις μπορεί να μπερδέψουν τη C και πάντως κανείς δεν εγγυάται για το αποτέλεσμά τους :

            printf("%10d  %10d\n", num, num*num++);

            a = num/2 + 5*(1 + num++);

            b = n++ + n++;

 

Εκφράσεις και Προτάσεις

Μια έκφραση αποτελείται από έναν συνδυασμό τελεστών και τελεστέων (ο τελεστέος είναι αυτό, πάνω στο οποίο δρα ο τελεστής). Η απλούστερη έκφραση είναι ένας μόνο τελεστέος.

Ακολουθούν μερικές εκφράσεις :

            4

            4 + 21

            a*(b + c/d)/20

            q = 5*2

            x = ++q % 3

            q > 3

Οι τελεστέοι μπορεί να είναι σταθερές, μεταβλητές ή συνδυασμοί αυτών των δύο. Κάθε έκφραση στη C έχει μια τιμή και για να βρούμε την τιμή αυτή, εκτελούμε τις πράξεις με τη σειρά που υποδεικνύεται από την προτεραιότητα των τελεστών. Εκφράσεις σχέσεων, όπως η q > 3, έχουν τιμή 1 αν είναι αληθείς και 0 αν είναι ψευδείς.

Ακολουθούν μερικές εκφράσεις :

            Έκφραση      Τιμή

            -4+6                2

            c = 3 + 8         11

            5>3                 1

            6+(c=3+8)     17

Οι προτάσεις είναι τα πρωταρχικά δομικά στοιχεία ενός προγράμματος, δηλ. το πρόγραμμα είναι μια σειρά προτάσεων και σημείων στίξης. Στη C οι προτάσεις κλείνουν με το σύμβολο ;. Έτσι, η a = 4 είναι μια έκφραση, αλλά η a= 4; είναι μια πρόταση. Στο παράδειγμα : x = 6 + (y=5); η υποέκφραση y=5 είναι μια ολοκληρωμένη εντολή, αλλά απλά είναι μέρος μιας πρότασης. Επειδή συνεπώς μια ολοκληρωμένη εντολή δεν είναι και απαραίτητα μια πρόταση, το σύμβολο (;) χρειάζεται για να χαρακτηρίζει τις εντολές που είναι αληθινές προτάσεις.

Στο επόμενο παράδειγμα χρησιμοποιούμε τέσσερα είδη προτάσεων:

/* prog19.c – τα τέσσερα είδη προτάσεων */

#include <stdio.h>

main()             /* βρίσκει το άθροισμα των 20 πρώτων ακεραίων */

{

            int count, sum;                                              /* πρόταση δήλωσης */

            count = 0;                                          /* πρόταση καταχώρησης */

            sum = 0;                                             /* πρόταση καταχώρησης */

            while (count++ < 20)                                   /* πρόταση ελέγχου while */

                        sum = sum + count;             /* πρόταση */

            printf("άθροισμα = %d\n", sum);   /* πρόταση - συνάρτηση */

}

Μια σύνθετη πρόταση αποτελείται από δύο ή περισσότερες προτάσεις που περικλείονται από αγκύλες. Λέγεται επίσης και μπλοκ (block).

Ακολουθούν παραδείγματα : 

            /* τμήμα προγράμματος 1 */

            index = 0;

            while (index++ < 10)

                        sum = 10*index + 2;

            printf("sum = %d\n", sum);

 

            /* τμήμα προγράμματος 2 */

            index = 0;

            while (index++ < 10)

            {

                        sum = 10*index + 2;

                        printf("sum = %d\n", sum);

            }

Στο τμήμα προγράμματος 1, ο βρόχος while περιλαμβάνει μόνο μια πρόταση αντικατάστασης, δηλ. όταν λείπουν τα { και }, μια πρόταση while τρέχει από το while μέχρι το επόμενο σύμβολο ;.

Στο τμήμα προγράμματος 2, τα σύμβολα { και } δηλώνουν ότι και οι δύο προτάσεις αποτελούν μέρος του βρόχου while. Ολόκληρη η σύνθετη πρόταση θεωρείται σαν μια απλή πρόταση με την έννοια της δομής της πρότασης while.

 

Οι Μετατροπές Τύπου

Η C δεν γκρινιάζει τόσο εύκολα όσο η Pascal όταν ανακατεύουμε μεταβλητές και σταθερές διαφορετικών τύπων δεδομένων. Η C χρησιμοποιεί ορισμένους κανόνες για να μετατρέψει αυτόματα τους τύπους :

1. Όταν εμφανίζονται σε εκφράσεις, τόσο ο τύπος char όσο και ο τύπος short, με πρόσημο ή χωρίς, αυτόματα μετατρέπονται σε τύπο int. Επειδή αυτές είναι μετατροπές προς κάποιο μεγαλύτερο τύπο, λέγονται προαγωγές.

2. Σε κάθε πράξη όπου εμπλέκονται δύο τύποι, οι δύο τιμές μετατρέπονται στον τύπο αυτής με τον "υψηλότερο" βαθμό.

3. Η ιεραρχία των τύπων από τους υψηλότερους προς τους χαμηλότερους είναι η εξής : long double, double, float, unsigned long, long, unsigned int και int.

4. Σε μια πρόταση καταχώρησης, το τελικό αποτέλεσμα των υπολογισμών μετατρέπεται στον τύπο της μεταβλητής στην οποία καταχωρήθηκε η τιμή. Έτσι, όμως, μπορεί μια τιμή να μετατραπεί σε τύπο χαμηλότερου βαθμού, όταν π.χ. καταχωρούμε τύπο float σε τύπο int και γίνεται, όπως είδαμε, στρογγυλοποίηση του αριθμού.

Ακολουθεί ένα παράδειγμα :

/* prog20.c – αυτόματη μετατροπή τύπων */

#include <stdio.h>

main()

{

            char ch;

            int i;

            float fl;

            fl = i = ch = ‘A’;

            printf("ch = %c, i = %d, fl = %2.2f \n", ch, i, fl);

            ch = ch + 1;

            i = fl + 2 * ch;

            fl = 2.0 * ch + i;

            printf("ch = %c, i = %d, fl = %2.2f \n", ch, i, fl);

}

Το αποτέλεσμα θα είναι :

            ch = A,  i = 65,  fl = 65.00

            ch = B,  i = 197,  fl = 329.00

 

Ο Τελεστής Εκμαγείο

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

Ακολουθούν παραδείγματα, όπου η μεταβλητή m είναι τύπου int :

            m = 1.6 + 1.7;

            m = (int) 1.6 + (int) 1.7;

Το πρώτο παράδειγμα κάνει αυτόματη μετατροπή και η μεταβλητή m παίρνει την τιμή 3. Το δεύτερο παράδειγμα περιέχει δύο εκμαγεία τύπου int και οι μετατροπές σε ακεραίους γίνονται πριν από την πρόσθεση και έτσι η τιμή της μεταβλητής m είναι 2.

 

Ορίσματα Συναρτήσεων και Μετατροπές Τύπων

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

/* prog21.c – ορίζει μια συνάρτηση μ’ ένα όρισμα (argument) */

#include <stdio.h>

main()

{

            int times = 4;

            char ch = ‘!’;             /* o ASCII κώδικας είναι 33 */

            float f = 5.0;

            f(times);                      /* όρισμα τύπου int */

            f(ch);                           /* char αυτόματα ® int */

            f((int) f);                     /* το εκμαγείο αναγκάζει την f ® int */

}

            f(n)                  /* παλιός τρόπος επικεφαλίδας συνάρτησης */

            int n;               /* η συνάρτηση έχει ένα όρισμα τύπου int */

{

            while (n- - > 0)

                        printf("#");

            printf("\n");

}

Το αποτέλεσμα θα είναι :

            ####

            ################################

            #####

Εφόσον η συνάρτηση f() παίρνει ένα όρισμα, βάζουμε ένα όνομα μεταβλητής : n. Μετά δηλώνουμε τον τύπο της n. Αυτές οι δηλώσεις ορισμάτων βρίσκονται ανάμεσα στο όνομα της συνάρτησης και στην αρχική αγκύλη. Η δήλωση ενός ορίσματος δημιουργεί μια μεταβλητή που λέγεται τυπικό όρισμα ή τυπική παράμετρος.

Στο πρόγραμμά μας, η κλήση f(times) καταχωρεί την τιμή της μεταβλητής times, δηλ. το 4 στην n. Λέμε ότι η κλήση μιας συνάρτησης περνά (μεταβιβάζει) μια τιμή και αυτή η τιμή λέγεται ενεργό όρισμα ή ενεργή παράμετρος.

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

Η τελευταία κλήση f((int) f) χρησιμοποιεί ένα εκμαγείο τύπου για να μετατρέψει το f στον κατάλληλο τύπο γι' αυτό το όρισμα. Αν δεν χρησιμοποιούσαμε αυτήν την μετατροπή, τότε η συνάρτηση θα περίμενε να βρει τιμή τύπου int και θα διάβαζε έτσι μόνο τα 2 bytes από τα 8 bytes της τιμής τύπου float. Έτσι, προσαρμόσαμε τον τύπο της μεταβλητής με τον τύπο του ορίσματος της συνάρτησης.

 

Η Εντολή While

Η γενική μορφή (σύνταξη) της εντολής while είναι η εξής :

            while (έκφραση)

                        πρόταση

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

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

Ακολουθεί ένα παράδειγμα με μια εντολή while :

            while (scanf(“%d“, &num) == 1)

            ;   /* παραλείπει την είσοδο που είναι ακέραιος */

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

 

Ένα Παράδειγμα με την While

Θα δούμε τώρα τον βρόχο while σ’ ένα πρόγραμμα που αθροίζει ακέραιες τιμές που εισάγονται από το πληκτρολόγιο.

/* prog22.c – αθροίζει ακεραίους που δίνονται διαλογικά */

#include <stdio.h>

main()

{

            long num;

            long sum = 0L;                     /* αρχική τιμή της sum = 0 */

            int status;

            printf("Δώστε έναν ακέραιο. ");

            printf("Δώστε q για να σταματήσετε. \n ");

            status = scanf(" %ld", &num);

            while (status == 1)    /* το == σημαίνει ‘ίσο με‘ */

            {

                        sum = sum + num;

                        printf("Δώστε τον επόμενο ακέραιο. ");

                        printf("Δώστε q για να σταματήσετε. \n");

                        status = scanf(“ %ld“, &num);

            }

            printf("Οι ακέραιοι αριθμοί έχουν άθροισμα %ld. \n“, sum);

}

Το αποτέλεσμα θα είναι :

            Δώστε έναν ακέραιο. Δώστε q για να σταματήσετε. 20

            Δώστε τον επόμενον ακέραιο. Δώστε q για να σταματήσετε. 5

            Δώστε τον επόμενον ακέραιο. Δώστε q για να σταματήσετε. 30

            Δώστε τον επόμενον ακέραιο. Δώστε q για να σταματήσετε. Q

            Οι ακέραιοι αριθμοί έχουν άθροισμα 55.

Ας δούμε λίγες ενδιαφέρουσες λεπτομέρειες του προγράμματος. Κατ’ αρχήν, ο τελεστής == είναι ο τελεστής ισότητας της C, ενώ η εντολή status=1 θα καταχωρούσε το 1 στη μεταβλητή status. Το πρόγραμμα τελειώνει όταν η status πάρει μια τιμή διαφορετική από το 1, οπότε σταματάει ο βρόχος και το πρόγραμμα εμφανίζει την τελική τιμή του αθροίσματος.

Βλέπουμε, όμως, ότι με την χρήση της scanf() πετύχαμε δύο πράγματα : διαβάζουμε μια καινούργια τιμή για την μεταβλητή num και ταυτόχρονα κάνουμε χρήση της επιστρεφόμενης τιμής της scanf(). Η scanf() επιστρέφει τον αριθμό των στοιχείων που διάβασε με επιτυχία.

Αν, δηλ., διαβάσει έναν ακέραιο, τότε επιστρέφει την τιμή 1, η οποία και καταχωρείται στην μεταβλητή status, αλλιώς αν δώσουμε μια μη αριθμητική είσοδο, όπως το q, τότε κανένα στοιχείο δεν διαβάζεται και η επιστρεφόμενη τιμή της status γίνεται ίση με 0.

Έτσι, με την χρήση της scanf() πετύχαμε μαζί με το διάβασμα μιας τιμής και τον έλεγχο της εξόδου από τον βρόχο. Βλέπουμε ακόμη ότι έχουμε μια εντολή scanf() πριν μπούμε στον βρόχο while, για να μπορέσει έτσι να γίνει ο αρχικός έλεγχος της συνθήκης και επίσης μια εντολή scanf() στο τέλος του βρόχου για να μπορούν να συνεχίζονται οι επαναλήψεις.

Θα μπορούσαμε να γράψουμε την εντολή while και ως εξής :

                        while (scanf(“%ld”, &num)==1)

 

Οι Αληθείς και οι Ψευδείς Τιμές

Ακολουθεί ένα παράδειγμα :

/* prog23.c – οι αληθείς και οι ψευδείς τιμές στη C */

#include <stdio.h>

main()

{

            int true, false;

            true = (5>2);             /* τιμή μιας αληθούς σχέσης */

            false = (5==2);         /* τιμή μιας ψευδούς σχέσης */

            printf("αληθής = %d; ψευδής = %d \n", true, false);

}

Το αποτέλεσμα του προγράμματος θα είναι :

            αληθής = 1; ψευδής = 0

Δηλαδή, στη C μια αληθής έκφραση έχει τιμή 1 και μια ψευδής έκφραση έχει τιμή 0.

Ο παρακάτω βρόχος δεν σταματάει ποτέ :

            while (1)

            {

                        ...

}

Από το επόμενο παράδειγμα συμπεραίνουμε ότι στη C αληθείς θεωρούνται όλες οι μη μηδενικές τιμές και μόνο το 0 αναγνωρίζεται σαν ψευδές. Έτσι, ουσιαστικά στη C γίνεται αριθμητικός έλεγχος και όχι έλεγχος αληθούς/ψευδούς.

/* prog24.c – οι αληθείς και οι ψευδείς τιμές */

#include <stdio.h>

main()

{

            int n = 3;

 

            while (n)

                        printf(%d\n, n- -);

            n = -3;

            while (n)

                        printf(%2d\n, n++);

}

Το αποτέλεσμα θα είναι :

            3

            2

            1

            -3

            -2

            -1

Έτσι, στη C η έκφραση while (a!=0) θα μπορεί να γραφεί και ως εξής :

            while (a)

 

Ο Βρόχος For

Ο βρόχος for αποφεύγει τα τρία βήματα ενός βρόχου while, δηλ. την απόδοση αρχική τιμής, τον έλεγχο της συνθήκης τερματισμού και την αλλαγή της τιμής, όταν, όπως ξέρουμε από τις άλλες γλώσσες προγραμματισμού, οι επαναλήψεις που πρέπει να κάνουμε είναι ορισμένες σε αριθμό. Στη C, όμως, αυτό δεν είναι υποχρεωτικό. Η εντολή for χρησιμοποιεί τρεις εκφράσεις ελέγχου, χωρισμένες με αγγλικές άνω-τελείες (;), για να ελέγχουν τη διαδικασία της ανακύκλωσης. Η πρόταση αρχικών τιμών εκτελείται μόνο μία φορά πριν κάποια από τις προτάσεις του βρόχου εκτελεστεί.

Αν η έκφραση ελέγχου είναι αληθής (ή μη-μηδενική), ο βρόχος εκτελείται μία φορά. Μετά, υπολογίζεται η έκφραση ανανέωσης και η έκφραση ελέγχου ελέγχεται μια φορά ακόμα. Η πρόταση for είναι ένας βρόχος συνθήκης εισόδου, που σημαίνει, όπως αναφέρθηκε προηγουμένως, ότι η απόφαση για μια ακόμα εκτέλεση του βρόχου, παίρνεται πριν την εκτέλεση αυτή. Έτσι, είναι πιθανό ο βρόχος να μην εκτελεστεί ποτέ. Το μέρος των προτάσεων μπορεί να αποτελείται από μια απλή πρόταση ή από μια σύνθετη πρόταση.

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

            for (αρχική τιμή; Έλεγχος; Ανανέωση)

                        πρόταση

Ο βρόχος επαναλαμβάνεται μέχρι ο έλεγχος να γίνει ψευδής ή μηδέν.

Ακολουθεί ένα παράδειγμα :

/* prog25.c – ένας βρόχος με χρήση της for */

#include <stdio.h>

#define NUMBER 10

main()

{

            int count;

 

            for (count=1; count<=NUMBER; count++)

                        printf("Florina per sempre!\n");

}

Οι παρενθέσεις που ακολουθούν τη λέξη-κλειδί for περιέχουν τρεις εκφράσεις χωρισμένες με το σύμβολο ;. Η πρώτη έκφραση δίνει αρχική τιμή και εκτελείται μία φορά μόνο στην αρχή. Η δεύτερη έκφραση είναι μια συνθήκη ελέγχου και υπολογίζεται πριν από κάθε δυναμική εκτέλεση του βρόχου. Ο βρόχος τελειώνει όταν η έκφραση γίνει ψευδής. Η τρίτη έκφραση υπολογίζεται στο τέλος κάθε βρόχου. Η πρόταση for ακολουθείται από μια απλή ή σύνθετη πρόταση.

Μπορούμε να καθυστερήσουμε για λίγο το τρέξιμο ενός προγράμματος, ως εξής :

            for (n=1; N<=10000; N++)

            ;

Η ANSI C διαθέτει και τη συνάρτηση clock(), που μπορεί να χρησιμοποιηθεί για να δημιουργήσουμε χρονικές καθυστέρησης.

 

Ευέλικτες Χρήσεις της Εντολής For

            for (n=0; N<60; N=n+10)

            for (ch=’a’; ch<=’z’; ch++)

            for (num=1; num*num*num<=216; num++)

            for (d=100.0; d<150.0; d=d*1.1)

            for (x=1; Y<=75; Y=++x*5+50)

            for (printf(…); num!=6; scanf(“%d”, &num))

            for (x=1, y=2; X<=16; X++, y=y+3)

Συμπεραίνουμε ότι πρόταση for δεν χρησιμοποιείται μόνο για ένα αυστηρά συγκεκριμένο πλήθος επαναλήψεων, αλλά μπορεί να κάνει πολλά περισσότερα πράγματα.

 

Περισσότεροι Τελεστές Καταχώρησης

Έχουμε ήδη διαπιστώσει ότι η C έχει αρκετούς τελεστές κατχώρησης. Ο πιο βασικός είναι ο =, ο οποίος απλά καταχωρεί την τιμή της έκφρασης που βρίσκεται στα δεξιά του στην μεταβλητή που βρίσκεται στα αριστερά του. Οι άλλοι τελεστές καταχώρησης ανανεώνουν μεταβλητές : +=, –=, *=, /=, %=.

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

a += 20                      είναι το ίδιο όπως     a = a + 20

b –= 2                         είναι το ίδιο όπως     b = b – 2

c *= 2                         είναι το ίδιο όπως     c = c * 2

d /= 2.5                      είναι το ίδιο όπως     d = d / 2.5

e %= 3                        είναι το ίδιο όπως     e = e % 3

x *= 3 * y +12          είναι το ίδιο όπως     x = x * (3 * y + 12)

 

Ο Βρόχος Do While

Είδαμε ότι ο βρόχος while και ο βρόχος for είναι και οι δύο βρόχοι συνθήκης εισόδου. Η C έχει και έναν βρόχο συνθήκης εξόδου, στον οποίο η συνθήκη ελέγχεται μετά από κάθε επανάληψη του βρόχου. Αυτός είναι ο βρόχος do while.

Η πρόταση do while  δημιουργεί έναν βρόχο που επαναλαμβάνεται μέχρι η συνθήκη ελέγχου να γίνει ψευδής ή μηδέν. Ο βρόχος do while είναι ένας βρόχος συνθήκης εξόδου, δηλ. η απόφαση για μια ακόμα επανάληψη παίρνεται μετά από κάθε εκτέλεση του βρόχου.

Έτσι, ο βρόχος πρέπει να εκτελεστεί τουλάχιστον μία φορά. Το μέρος των προτάσεων μπορεί να αποτελείται είτε από μία απλή πρόταση ή από μία σύνθετη.

            do

                        scanf(“%d”, &number)

            while (number != 20);

Ακολουθεί ένα παράδειγμα :

/* prog26.c – βρόχος συνθήκης εξόδου */

#include <stdio.h>

main()

{

            char ch;

 

            do

            {

                        scanf("%c", &ch);

                        printf("%c", ch);

            } while (ch!=’#’);

}

Βλέπουμε ότι το πρόγραμμα διαβάζει χαρακτήρες και τους τυπώνει μέχρι να εμφανιστεί ο χαρακτήρας #. Θα τυπώσει, όμως, και τον χαρακτήρα #, όταν αυτός εμφανιστεί. Για να αποφύγουμε αυτή την περίπτωση, μπορούμε να χρησιμοποιήσουμε την εντολή if, ως εξής :

            if (ch<>’#’)

printf("%c", ch);

Η γενική μορφή του βρόχου do while είναι η εξής :

            do

                        πρόταση

            while (έκφραση);

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

Ένας βρόχος do while εκτελείται πάντα τουλάχιστον μία φορά, αφού ο έλεγχος γίνεται μετά την εκτέλεση του σώματος του βρόχου. Από την άλλη μεριά, ένας βρόχος for ή ένας βρόχος while μπορεί να μην εκτελεστεί καμία φορά, αφού ο έλεγχος γίνεται πριν από την εκτέλεση της εντολής.

Το φαινομενικό αυτό ελάττωμα που έχει ο βρόχος do while, ότι δηλ. εκτελείται τουλάχιστον μία φορά και ίσως και όταν δεν χρειάζεται, είδαμε ότι πολύ εύκολα μπορεί να διορθωθεί με χρήση της εντολής if μέσα στον βρόχο.

 

Οι Εσωτερικοί Βρόχοι

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

Ακολουθεί ένα παράδειγμα :

/* prog27.c – χρήση εσωτερικών βρόχων */

#include <stdio.h>

#define GRAMMES 5

#define STILES 5

main()

{

            int row;

            char ch;

            for (row=0; row<GRAMMES; row++)

            {

                        for (ch=’A’; ch<’A’+STILES; ch++)

                                    printf(" %c", ch);

            printf("\n");

            }

}

Το αποτέλεσμα θα είναι :

            ABCDE

            ABCDE

            ABCDE

            ABCDE

            ABCDE

Ο πρώτος βρόχος for λέγεται έξω βρόχος και ο άλλος βρόχος for λέγεται μέσα βρόχος. Ο έξω βρόχος αρχίζει με τη row να έχει τιμή 0 και τελειώνει όταν η row γίνει ίση και με το 4. Άρα, κάνει 5 επαναλήψεις. Η πρώτη πρόταση σε κάθε επανάληψη είναι ο άλλος βρόχος for. Αυτός ο βρόχος κάνει επίσης 5 κύκλους, τυπώνοντας τους χαρακτήρες από το Α μέχρι το E στην ίδια γραμμή.

Μόλις τελειώσει ο μέσα βρόχος, ακολουθεί μια πρόταση printf("\n"), που όπως ξέρουμε αλλάζει γραμμή. Βλέπουμε συνεπώς, ότι ο μέσα βρόχος τυπώνει 5 χαρακτήρες σε μια γραμμή και ο έξω βρόχος δημιουργεί 5 γραμμές. Μπορεί, όμως, ο μέσα βρόχος να εξαρτάται από τον έξω βρόχο και να συμπεριφέρεται έτσι διαφορετικά σε κάθε επανάληψη.

Ακολουθεί το προηγούμενο παράδειγμα τροποποιημένο :

/* prog28.c – χρήση εξαρτημένων εσωτερικών βρόχων */

#include <stdio.h>

#define GRAMMES 5

#define STILES 5

main()

{

            int row;

            char ch;

            for (row=0; row<GRAMMES; row++)

            {

                        for (ch=’A’+row; ch<’A’+STILES; ch++)

                                    printf(" %c", ch);

            printf("\n");

            }

}

Το αποτέλεσμα θα είναι :

            ABCDE

            BCDE

            CDE

            DE

            E

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

 

Οι Πίνακες

Γνωρίζουμε την μεγάλη σημασία που έχουν οι πίνακες για τον προγραμματισμό. Μπορούμε να αποθηκεύουμε αρκετά στοιχεία για παρόμοιες πληροφορίες μ’ έναν πολύ βολικό τρόπο. Ένας πίνακας είναι μια σειρά δεδομένων του ίδιου τύπου, όπως π.χ. 15 στοιχεία τύπου char ή 10 στοιχεία τύπου int, αποθηκευμένα ακολουθιακά. Ολόκληρος ο πίνακας έχει ένα απλό όνομα και τα δεδομένα του, που λέγονται στοιχεία του πίνακα, μπορούν να προσπελαστούν με χρήση μιας κατάστασης ακεραίων.

Για παράδειγμα, η παρακάτω δήλωση : float pin[20];, δηλώνει ότι ο pin είναι ένας πίνακας με 20 στοιχεία, με πρώτο στοιχείο το pin[0], δεύτερο στοιχείο το pin[1], κοκ μέχρι και το pin[19]. Βλέπουμε ότι η αρίθμηση των στοιχείων του πίνακα αρχίζει από το 0 και όχι από το 1. Σε κάθε στοιχείο του παραπάνω πίνακα μπορούμε να καταχωρήσουμε μια τιμή τύπου float, ως εξής :

            pin[5] = 20.16;

            pin[6] = 1.3e+12;

Μπορούμε να ορίσουμε και πίνακες άλλων τύπων :

            int numbers[10];

            char alpha[26];

            long bignumbers[100];

Οι αριθμοί που χρησιμοποιούνται για να χαρακτηρίζουν τα στοιχεία του πίνακα καλούνται δείκτες του πίνακα, οι οποίοι πρέπει να είναι ακέραιοι και να αρχίζουν από το 0. Τα στοιχεία του πίνακα είναι αποθηκευμένα στην μνήμη, το ένα δίπλα στο άλλο.

Ακολουθεί ένα πρόγραμμα με πίνακες και με χρήση της εντολής for, το οποίο διαβάζει 10 βαθμούς, τους εμφανίζει στην οθόνη και μετά υπολογίζει το άθροισμά τους και τον μέσο όρο τους :

/* prog29.c – χρήση βρόχων για επεξεργασία πινάκων */

#include <stdio.h>

#define SIZE 10

main()

{

            int i, sum, b[SIZE];

            float average;

            printf("Δώστε %d βαθμούς \n", SIZE);

            for (i = 0; i < SIZE; i++)

                        scanf("%d", &b[i]);  /* διάβασμα των 10 βαθμών */

            printf("Οι βαθμοί που διαβάστηκαν είναι οι εξής : \n");

            for (i = 0; i < SIZE; i++)

                        printf("%5d", b[i]);  /* επιβεβαίωση της καταχώρησης */

printf("\n");

            for (i = 0; i < SIZE; i++)

                        sum += b[i];             /* άθροιση των βαθμών */

            average = (float) sum / SIZE;         /* υπολογισμός μέσους όρου */

            printf("Άθροισμα βαθμών = %d, Μέσος Όρος = %.2f \n",

sum, average);

}

Βλέπουμε ότι ο βρόχος for μάς δίνει την δυνατότητα για έναν απλό, εύκολο και ευθύ τρόπο χειρισμού των δεικτών του πίνακα. Η παρακάτω εντολή είναι πολύ βολική για την επεξεργασία των στοιχείων ενός πίνακα μεγέθους SIZE :

            for (i=0; i<SIZE; i++)

 

Βρόχοι και Συναρτήσεις

Ακολουθεί ένα πρόγραμμα :

/* prog30.c – ύψωση αριθμού σε δύναμη */

#include <stdio.h>

main()

{

            double x, xpow;

            double power();                    /* δήλωση της συνάρτησης */

            int n;

            printf("Δώστε έναν αριθμό και μια ακέραια δύναμη ");

            printf("Δώστε q για να σταματήσετε.");

            while (scanf("%lf%d", &x, &n) == 2)

            {

                        xpow = power(x, n); /* κλήση της συνάρτησης */

                        printf("Το %.3e εις την %d είναι %.3e \n", x, n, xpow);

            }

}

double power(a, b)                           /* ορισμός της συνάρτησης */

double a;

int b;

{

            double pow = 1;

            int i;

 

            for (i = 1;  i <= b;  i++)

                        pow *= a;

            return pow;                           /* επιστρέφει την τιμή της pow */

}

Εδώ υπολογίζουμε το αποτέλεσμα της ύψωσης ενός αριθμού σε μια ακέραια δύναμη με τη χρήση μιας συνάρτησης. Η συνάρτηση δέχεται δύο τιμές και επιστρέφει μία. Χρησιμοποιούμε ένα όρισμα τύπου double και ένα όρισμα τύπου int, που καθορίζουν ποιος αριθμός θα υψωθεί σε ποια δύναμη.

Δηλώνουμε την συνάρτηση μέσα στην main() με τον τύπο της τιμής που επιστρέφει και με την χρήση της λέξης-κλειδί return δείχνουμε την τιμή που θα επιστρέψει η συνάρτηση. Τη συνάρτηση την καλούμε μέσα από το πρόγραμμα με την εξής εντολή :

            xpow = power(x,n);.

 

Η Εντολή If

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

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

            if (έκφραση)

                        πρόταση

Εάν η έκφραση είναι αληθής (δηλ. όχι μηδέν), τότε εκτελείται η πρόταση. Αλλιώς, αγνοείται. Η πρόταση μπορεί να είναι μια απλή πρόταση ή μια σύνθετη πρόταση.

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

Η γενική μορφή (σύνταξη) της εντολής if else είναι η εξής :

            if (έκφραση)

                        πρόταση1

            else

                        πρόταση2

Ένα else συνδυάζεται με το πιο κοντινό του if, εκτός κι αν υπάρχουν αγκύλες, που δηλώνουν κάτι άλλο. Υπάρχει η δυνατότητα να χρησιμοποιήσουμε και την εντολή else if, ως εξής :

            if (έκφραση1)

                        πρόταση1

            else if (έκφραση2)

                        πρόταση2

            else
                        πρόταση3

Αν η έκφραση1 είναι αληθής, τότε εκτελείται η πρόταση1. Αν η έκφραση1 είναι ψευδής, αλλά η έκφραση2 είναι αληθής, τότε εκτελείται η πρόταση2. Τέλος, αν και οι δύο εκφράσεις είναι ψευδείς, τότε εκτελείται η πρόταση3.

 

Οι Συναρτήσεις getchar() και putchar()

Ας δούμε τώρα κάτι άλλο. Η C έχει ένα ζευγάρι συναρτήσεων, ειδικά σχεδιασμένων για την είσοδο/έξοδο χαρακτήρων, τις getchar() και  putchar(). Η συνάρτηση getchar() δεν έχει ορίσματα και επιστρέφει τον επόμενο χαρακτήρα που δίνεται ως δεδομένο, ως εξής :

            ch = getchar();

Η συνάρτηση putchar() εκτυπώνει το όρισμά της, ως εξής :

            putchar(ch);

Ακολουθούν δύο παραδείγματα :

/* prog31.c – μετατροπή εισόδου, διατηρώντας τα κενά */

#include <stdio.h>

#define SPACE ‘ ‘

main()

{

            char ch;

            ch = getchar();                      /* διάβασε έναν χαρακτήρα */

            while (ch != ‘\n’)                   /* αν δεν είναι το τέλος μιας γραμμής */

            {

                        if (ch == SPACE)                  /* άφησε το κενό */

                                    putchar(ch);              /* αμετάβλητος χαρακτήρας */

                        else

                                    putchar(ch + 1);       /* άλλαξε τους άλλους χαρακτήρες*/

                        ch = getchar();                      /* επόμενος χαρακτήρας */

            }

}

 

/* prog32.c – μετατροπή εισόδου, διατηρώντας τα κενά */

#include <stdio.h>

#define SPACE ‘ ‘

main()

{

            char ch;

 

            while ((ch = getchar()) != ‘\n’) /* αν δεν είναι το τέλος μιας γραμμής */

            {

                        if (ch == SPACE)                  /* άφησε το κενό */

                                    putchar(ch);              /* αμετάβλητος χαρακτήρας */

                        else

                                    putchar(ch + 1);       /* άλλαξε τους άλλους χαρακτήρες*/

            }

}

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

            FLORINA PER SEMPRE.

            GMPSJOB QFS TFNQSF/

Η ευελιξία της C μάς επιτρέπει να συνδυάσουμε την ανάγνωση και τον έλεγχο των δεδομένων εισόδου σε μία μόνο έκφραση. Και αυτό το βλέπουμε στο δεύτερο πρόγραμμα και στην εντολή while ((ch=getchar())!='\n’), όπου έχουμε σε μια έκφραση την καταχώρηση μιας τιμής στη ch και σύγκριση αυτής της τιμής με τον χαρακτήρα νέας γραμμής \n. Αν δεν βάζαμε τις παρενθέσεις, τότε η πρώτη έκφραση που θα εκτελείτο, θα ήταν η getchar()!='\n'.

 

Οι Λογικοί Τελεστές

Στο παρακάτω παράδειγμα συνδυάζουμε τρεις σχεσιακές εκφράσεις με τον λογικό τελεστή &&, που είναι το γνωστό μας AND στην C. Το πρόγραμμα μετρά τους μη-λευκούς χαρακτήρες, δηλ. τους χαρακτήρες που δεν είναι  κενό, enter και tab.

/* prog33.c – μετρά τους μη-λευκούς χαρακτήρες */

#include <stdio.h>

#define PERIOD ‘.’

main()

{

            int ch;

            int charcount = 0;

 

            while ((ch = getchar()) != PERIOD)

                        if (ch != ‘ ‘ && ch != ‘\n’ && ch != ‘\t’)

                                    charcount++;

            printf("Υπάρχουν %d μη-λευκοί χαρακτήρες. \n", charcount);

}

Οι λογικοί τελεστές έχουν μικρότερη προτεραιότητα από τους σχεσιακούς τελεστές και υπάρχουν τρεις απ' αυτούς στην C :

            Τελεστής        Σημασία

            &&                  And (και)

            ||                       Or (ή)

            !                       Not (όχι)

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

 

Ο Τελεστής υπό Συνθήκη ?

Ένας άλλος τρόπος για να εκφράσουμε την πρόταση if else ονομάζεται έκφραση υπό συνθήκη και χρησιμοποιεί τον τελεστή υπό συνθήκη ? : που έχει τρεις τελεστέους. Το παρακάτω παράδειγμα βρίσκει την απόλυτη τιμή ενός αριθμού :

            x = (y<0) ? -y : y;

Η πρόταση λέει τα εξής : «αν το y είναι μικρότερο από το 0, τότε x=-y, αλλιώς x=y».

Η γενική μορφή (σύνταξη) της έκφρασης υπό συνθήκη είναι η εξής :

            έκφραση1 ? έκφραση2 : έκφραση3

Αν η έκφραση1 είναι αληθής (δηλ. όχι μηδέν), τότε ολόκληρη η έκφραση υπό συνθήκη έχει την τιμή της έκφρασης2, αν όμως η έκφραση1 είναι ψευδής (μηδέν), τότε ολόκληρη η έκφραση υπό συνθήκη έχει την τιμή της έκφρασης3.

Πώς βρίσκουμε τον μέγιστο από δύο αριθμούς :

            max = (a>b) ? a : b

Ακολουθούν παραδείγματα :

            (5>2) ? 1 : 2   έχει τιμή 1

            (3>5) ? 1 : 2   έχει τιμή 2

            (a>b) ? a : b    έχει την τιμή του μεγαλύτερου μεταξύ των a και b

 

Η Εντολή Switch

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

Ακολουθεί ένα πρόγραμμα, στο οποίο διαβάζουμε ένα γράμμα και μετά μας δίνει το όνομα μιας πόλης που ν' αρχίζει μ' αυτό το γράμμα.

/* prog34.c – χρήση της εντολής switch */

#include <stdio.h>

main()

{

            char ch;

            printf("Δώστε ένα γράμμα του αλφαβήτου.");

            printf("Πατήστε # για να τελειώσει το πρόγραμμα : \n");

            while ((ch = getchar()) != ‘#’)

            {

                        if (ch >= ‘a’ && ch <= ‘z’) /* δέχεται μόνο */

                                    switch (ch)                              /* μικρά γράμματα */

                                    {

                                                case ‘a’ :

                                                            printf("Αθήνα \n");

                                                            break;

                                                case ‘b’ :

                                                            printf("Βόλος \n");

                                                            break;

                                                case ‘c’ :

                                                            printf("Γρεβενά \n");

                                                            break;

                                                case ‘d’ :

                                                            printf("Δράμα \n");

                                                            break;

                                                case ‘e’ :

                                                            printf("Έδεσσα \n");

                                                            break;

                                                default :

                                                            printf("Δεν υπάρχει πόλη\n");

                                    }          /* τέλος της switch */

                        else

                                    printf("Αναγνωρίζω μόνο μικρά γράμματα \n");

                        while (getchar() != ‘\n’)

                        ;                       /* παρέλειψε το υπόλοιπο της γραμμής εισόδου */

                        printf("Παρακαλώ, δώστε ένα άλλο γράμμα ή #.\n");

            }                      /* τέλος βρόχου while */

}

Η εντολή switch δουλεύει ως εξής :

Πρώτα, υπολογίζεται η έκφραση μέσα στις παρενθέσεις, που ακολουθεί την switch. Μετά, το πρόγραμμα σαρώνει τον κατάλογο με τις ετικέττες case μέχρι να βρει μια που να ταιριάζει μ’ αυτήν την τιμή. Τότε, το πρόγραμμα πηγαίνει σ' αυτήν την γραμμή και εκτελεί τις εντολές που περιέχονται σ' αυτήν. Αν δεν ταιριάζει με καμία επιλογή, τότε το πρόγραμμα πηγαίνει στην γραμμή με την ετικέττα default, αν υπάρχει αυτή βέβαια. Αν δεν υπάρχει η επιλογή default, τότε το πρόγραμμα συνεχίζει κανονικά στην επόμενη εντολή μετά την switch.

Αν δεν υπήρχε η πρόταση break, τότε το πρόγραμμα θα εκτελούσε κάθε πρόταση από την ετικέττα ταύτισης μέχρι και το τέλος της πρότασης switch. Δεν μπορούμε να χρησιμοποιήσουμε μια μεταβλητή για ετικέττα στην πρόταση switch, αλλά μόνο εκφράσεις σταθερών τύπου int ή char.

Η δομή της εντολής switch είναι η εξής :

switch (ακέραια έκφραση)

{

            case (σταθερά 1 :

                        προτάσεις; (προεραιτικά)

            case (σταθερά 2 :

                        προτάσεις; (προεραιτικά)

            ...

            default : (προεραιτικά)

                        προτάσεις; (προεραιτικά)

}

 

Η Εντολή Break

Η εντολή αυτή μπορεί να χρησιμοποιηθεί με τη switch, όπως είδαμε νωρίτερα, αλλά και με τις υπόλοιπες τρεις δομές βρόχου και έχει ως αποτέλεσμα την διακοπή της εκτέλεσης των εντολών switch, for, while και do while και την μετάβαση στο επόμενο στάδιο του προγράμματος. Ακολουθεί ένα κομμάτι προγράμματος που σταματά έναν βρόχο όταν διαβαστεί είτε ένα πλήκτρο enter ή ένα πλήκτρο tab :

            while ((ch=getchar()) != '\n')

            {

                        if (ch == '\t')

                                    break;

                        putchar(ch);

            }

Το παραπάνω κομμάτι προγράμματος θα μπορούσε να δουλέψει και ως εξής :

            while ((ch=getchar()) != '\n' && ch != '\t')

                        putchar(ch);

 

Η Εντολή Continue

Αυτή η εντολή μπορεί να χρησιμοποιηθεί και στα τρία είδη βρόχων, αλλά όχι με την πρόταση switch. Και η continue διακόπτει την ροή ενός προγράμματος, αλλά αντί να τερματίζει ολόκληρο τον βρόχο, έχει ως αποτέλεσμα την μη εκτέλεση του υπόλοιπου τμήματος του βρόχου και την επανάληψή του από την αρχή.

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

            while ((ch=getchar()) != '\n')

            {

                        if (ch == '\t')

                                    continue;

                        putchar(ch);

            }

Δηλαδή ο βρόχος σταματάει τώρα μόνο με το πλήκτρο enter και όχι και με το tab. Το παραπάνω κομμάτι προγράμματος θα μπορούσε να δουλέψει κι έτσι :

            while ((ch=getchar()) != '\n')

                        if (ch != '\t')

                                    putchar(ch);

 

Αποφυγή Χαρακτήρων Κατά το Διάβασμα

Επειδή υπάρχει πάντα ο κίνδυνος ο χαρακτήρας νέας γραμμής <enter> να διαβαστεί ως ξεχωριστός χαρακτήρας και να δημιουργηθούν έτσι προβλήματα σε διαλογικά προγράμματα, μια λύση στο πρόβλημα αυτό είναι με τη χρήση της εντολής while :

            while (getchar() != '\n')  /* αγνοεί το υπόλοιπο της γραμμής εισόδου */

              ;

Πρέπει να έχουμε υπόψη μας ότι η getchar() διαβάζει κάθε χαρακτήρα, συμπεριλαμβανομένων και των χαρακτήρων κενού διαστήματος (space), στηλοθέτησης (tab) και νέας γραμμής (enter), ενώ η scanf(), όταν διαβάζει αριθμούς, αγνοεί αυτούς τους χαρακτήρες. Μόνο όταν διαβάζουμε χαρακτήρες χρησιμοποιώντας τον προσδιοριστή %c, η scanf() συμπεριφέρεται όπως η getchar().

Για να αποφύγουμε τυχόν προβλήματα με το διάβασμα των χαρακτήρων που προαναφέραμε, μπορούμε να χρησιμοποιήσουμε την εξής εντολή if μέσα στο πρόγραμμά μας :

            if (ch != '\n' && ch != ' ' && ch != '\t')

για να αποφύγουμε έτσι αυτούς τους χαρακτήρες.

 

back.gif (9867 bytes)

Επιστροφή