next up previous contents
Next: 2.4 Το πρόγραμμα cond.c Up: 2. Προγραμματισμός στη γλώσσα Previous: 2.2 Το πρόγραμμα hello.c   Contents

Subsections

2.3 Το πρόγραμμα mean.c

Το παρακάτω πρόγραμμα mean.c διαβάζει από το πληκτρολόγιο δύο ακεραίους a και b, υπολογίζει το μέσο όρο τους και τον τυπώνει στην οθόνη.



   1 #include        <stdio.h>
   2 
   3 main()
   4 {
   5         int     a, b;
   6         double  mean;
   7 
   8         printf("Give the integer a: ");
   9         scanf("%d", &a);
  10         printf("Give the integer b: ");
  11         scanf("%d", &b);
  12         mean = 0.5*(a+b);
  13         printf("The mean of %d and %d is %g\n", a, b, mean);
  14 }

Το αρχείο mean.c

Τα νέα στοιχεία που συναντά κανείς στο mean.c είναι τα ακόλουθα:

  1. Δηλώσεις μεταβλητών στις γραμμές 5 και 6.
  2. Ανάγνωση τιμών από το πληκτρολόγιο στις γραμμές 9 και 11.
  3. Αριθμητικές πράξεις και εκχώρηση του αποτελέσματος σε μεταβλητή.
  4. Πιο περίπλοκη χρήση της printf στη γραμμή 13.
  5. Τα σύμβολα &a και &b στις γραμμές 9 και 11.

2.3.1 Τύποι μεταβλητών

Οι βασικοί (και όχι παραγόμενοι) τύποι μεταβλητών στη C είναι οι εξής
Όνομα τύπου Περιγραφή Μέγεθος σε bytes
char Χαρακτήρας 1
int Προσημασμένος Ακέραιος 4
float Αριθμός Κινητής Υποδιαστολής (πραγματικός αριθμός) 4
double Αριθμός Κινητής Υποδιαστολής (πραγματικός αριθμός) 8
void Κενός τύπος -
Πρέπει να τονίσουμε εδώ ότι αν και τα παραπάνω μεγέθη σε bytes2.7είναι σχεδόν standard σήμερα, δεν είναι σε καμιά περίπτωση σωστά σε όλα τα υπολογιστικά συστήματα. Το ``16-bito'' MS-DOS είναι ίσως η πιο κοινή περίπτωση όπου, π.χ., ένας int έχει μέγεθος 2 και όχι 4 bytes. Γι' αυτό και δεν πρέπει κανείς να παίρνει τα μεγέθη αυτά ως απολύτως δεδομένα, αν δεν ξέρει που τρέχει το πρόγραμμα που γράφει.

Για το ξεκαθάρισμα τυχόν τέτοιων αμφιβολιών υπάρχει ο τελεστής sizeof στη C, που συντάσσεται ως

sizeof(type)
και επιστρέφει το μέγεθος του τύπου type σε bytes. (Αυτό γίνεται φυσικά at compilation time κι όχι at run time.) Έτσι sizeof(int) είναι συνήθως 4, sizeof(double) είναι συνήθως 8, sizeof(char) είναι 1, κλπ.

Ο τύπος int παίρνει τις ακέραιες τιμές από -2147483648 ( = -231) έως 2147483647 ( = 231 - 1), ο τύπος char παίρνει τις ακέραιες τιμές από -128 ( = -27) έως 127 ( = 27 - 1), ενώ οι τύποι float και double παριστάνουν πραγματικούς αριθμούς, με ακρίβεια η οποία είναι μεταβλητή ανάλογα με το μέγεθος των αριθμών αυτών, οπότε δεν έχει νόημα να προσδιορίσουμε κάποιο έυρος τιμών τους. Βέβαια, επειδή ο τύπος double έχει 64 bits (= 8 bytes) στη διάθεσή του για να παραστήσει ένα πραγματικό αριθμό ενώ ο float χρησιμοποιεί μόνο 32 bits ( = 4 bytes), είναι ευνόητο ότι οι πράξεις με double είναι ακριβέστερες απ' ότι με float και συνιστάται να χρησιμοποιείται ο τύπος double και όχι ο float, παρά μόνο αν υπάρχει πραγματική ανάγκη εξοικονόμησης χώρου.

Υπάρχει επίσης και ο τύπος short int ο οποίος είναι προσημασμένος ακέραιος με 2 bytes μόνο, και εύρος τιμών από -32768 (= -215) έως 32767 (= 215 - 1).

Τέλος σε όλους τους ακέραιους τύπους (δηλ. char, int και short int) μπορεί να προστεθεί το πρόθεμα unsigned, που υποδηλώνει ότι ο τύπος δεν παίρνει αρνητικές τιμές και παριστά λοιπόν όλους τους ακεραίους από 0 έως 2n - 1, όπου n είναι το πλήθος των bits που χρησιμοποιεί ο τύπος. Για παράδειγμα, ο unsigned char παριστά τους ακεραίους από 0 έως 255.

Τέλος, ο τύπος void πρέπει προς το παρόν να θεωρείται σαν ο πιο γενικός τύπος: ονομάζουμε κάτι void αν δεν έχει νόημα να προσδιορίσουμε τον τύπο του. Παραδείγματα της χρήσης τους είναι ουσιαστικά δύο: (α) δίνουμε τύπο void σε μια συναρτηση που δε θέλουμε να επιστρέφει τίποτα, και (β) δίνουμε τύπο void * σε μια τελείως γενική διεύθυνση μνήμης, που δεν ξέρουμε δηλ. σε τι τύπο αντικειμένου ``δείχνει'' (αυτό θα γίνει πιο καθαρό παρακάτω).

2.3.2 Απουσία λογικού τύπου

Μια σημαντική παρατήρηση είναι ότι η C δεν έχει λογικό τύπο, κάποιο τύπο δηλ. του οποίου οι τιμές να είναι είτε true (αληθής) είτε false (ψευδής). Στη C η σύμβαση είναι ότι οποιαδήποτε μη μηδενική ακέραια τιμή (και συνηθέστατα το 1) θεωρείται αληθής και το 0 μόνο ψευδής. Όταν αργότερα θα δούμε την εντολή if, για παράδειγμα, θα δούμε ότι αυτή συντάσσεται με μια λογική συνθήκη και κάποιες εντολές που εκτελούνται αν και μόνο αν η λογική αυτή συνθήκη είναι αληθής. Αυτό σημαίνει ότι η συνθήκη αυτή δεν είναι τίποτε άλλο από μια έκφραση ακέραιου τύπου (δηλ. int ή short ή char κλπ) και για να εκτελεστούν οι εντολές που ακολουθούν πρέπει η έκφραση αυτή να μην είναι ίση με 0.

Για παράδειγμα, θα δούμε αργότερα, ο δυαδικός τελεστής && είναι το λογικό και. Αυτό σημαίνει ότι η τιμή του expr1&& expr2 είναι 1 αν και μόνο αν δεν είναι και οι δυο εκφράσεις expr1 και expr2 ίσες με 0, και είναι ίση με 0 αλλιώς. Έτσι, η έκφραση 5 && 3 είναι απολύτως θεμιτή στη C και είναι ίση με 1.

2.3.3 Δηλώσεις μεταβλητών

Πώς δηλώνεται τώρα μια μεταβλητή; (Όλες οι μεταβλητές στη C πρέπει να δηλωθούν προτού χρησιμοποιηθούν, ώστε ο compiler να γνωρίζει τον τύπο τους όταν τις πρωτοσυναντήσει.) Ο κανόνας είναι πως μια δήλωση μεταβλητών συνίσταται από ένα όνομα τύπου ακολουθούμενο από ένα ή περισσότερα (χωριζόμενα με κόμμα) ονόματα μεταβλητών. Η λίστα των μεταβλητών που δηλώνονται τερματίζεται με το σύμβολο ; (semicolon) όπως σχεδόν και όλες οι άλλες εντολές στη C.

Που μπορούν να γραφτούν οι δηλώσεις μεταβλητών; Κατ' αρχήν μπορούν να γραφτούν στο χώρο του κειμένου εκτός συναρτήσεων. Π.χ. ένα πρόγραμμα που είναι λειτουργικά ισοδύναμο με το mean.c είναι το ακόλουθο:

#include	<stdio.h>

int	a;
double	mean;

main() {
	int	b;
	double	useless_variable_1;

	printf("Give the integer a: ");
	scanf("%d", &a);
	printf("Give the integer b: ");
	scanf("%d", &b);
	mean = 0.5*(a+b);
	printf("The mean of %d and %d is %g\n", a, b, mean);
}
Επίσης μπορεί μια δήλωση μεταβλητών να υπάρχει στην αρχή ενός block εντολών. Ένα block εντολών είναι μια λίστα εντολών στη C η οποία βρίσκεται μέσα σε άγκιστρα <λίστα εντολών> . Για παράδειγμα, η δήλωση της συνάρτησης main αποτελείται από το όνομα της συνάρτησης και τα ονόματα και τύπους των παραμέτρων της κι ένα block. Blocks εντολών όμως μπορούν να υπάρχουν και σε άλλα σημεία μέσα στο κείμενο της συνάρτησης, όπως θα δούμε παρακάτω, και σε κάθε τέτοιο μπορεί κανείς να δηλώσει μεταβλητές, οι οποίες όμως πρέπει να θεωρούνται ότι υπάρχουν μόνο μέσα στο block στο οποίο είναι δηλωμένες. Το παρακάτω σύντομο πρόγραμμα δείχνει μια τέτοια δήλωση μέσα σε block:
#include <stdio.h>

main()
{
	int	t=1;

	{int t=2; printf("t=%d\n", t);}
	printf("t=%d\n", t);
}
Το ouput του προγράμματος αυτού είναι
% a.out
2
1
Υπάρχουν σε αυτό δυο δηλώσεις μεταβλητής int t, μια στο block της συνάρτησης main και άλλη μια μέσα σε ένα block εσωτερικό της main. Η δήλωση της μεταβλητής που γίνεται μέσα σ' ένα block έχει εμβέλεια (scope) μόνο μέσα σε αυτό το block. Έτσι, κάθε αναφορά στην t μέσα στο εσωτερικό block αναφέρεται στη μεταβλητή που ορίστηκε μέσα στο block αυτό, η οποία επισκιάζει κάθε άλλο πρότερο ορισμό μεταβλητής με το ίδιο όνομα. Μόλις βγούμε από το block, η δήλωση που έχει γίνει μέσα στο block παύει να ισχύει και η μόνη ισχύουσα δήλωση είναι η προηγούμενη.

Τι είδους όνομα μπορεί να χρησιμοποιηθεί για μια μεταβλητή; Λίγο-πολύ οτιδήποτε μπορεί κανείς να φτιάξει με μικρά ή κεφαλαία λατινικά γράμματα, με ψηφία και το σύμβολο _ (underscore), φτάνει η λέξη να μην αρχίζει με ψηφίο.

2.3.4 Εισαγωγή δεδομένων με τη scanf

Οι γραμμές 9 και 11 διαβάζουν τους ακεραίους a και b από το πληκτρολόγιο. Η ρουτίνα scanf (κάντε man 3 scanf) παίρνει πάντα ως πρώτη παράμετρο ένα string (το format string) το οποίο είναι έτσι φτιαγμένο που να υποδηλώνει στη scanf τί είδους τύπους δεδομένων θέλουμε να διαβάσουμε. Οι επιπλέον παράμετροι (λίγο-πολύ αυτές οι επιπλέον παράμετροι θα είναι τόσες τον αριθμό όσα και τα % που βρίσκονται μέσα στο format string) παριστάνουν η καθεμία από μια θέση μνήμης2.8, την πρώτη θέση μνήμης που καταλαμβάνει η μεταβλητή την οποία θέλουμε να ``γεμίσει'' η scanf. Στη C για να πάρουμε αυτή τη θέση μνήμης για μια μεταβλητή με όνομα x γράφουμε απλά &x. Αυτή η θέση μνήμης λέγεται και διεύθυνση (address) του x.

Ας έρθουμε τώρα στο format string. Η γραμμή

scanf("%d", &a);
διαβάζει ένα ακέραιο από το πληκτρολόγιο και τον αποθηκεύει στη μεταβλητή a. Το format string είναι το "Το νόημα του "διαβάσει από το πληκτρολόγιο ένα προσημασμένο δεκαδικό (εξ ού και το d, από το decimal) ακέραιο, και να τον τοποθετήσει στη θέση που λέει η επόμενη διεύθυνση μνήμης που έχει περαστεί ως όρισμα στη scanf.

Πώς θα διαβάσουμε τους αριθμούς a, b και x που έχουν δηλωθεί ως εξής;

int	a, b;
double	x;
Η απάντηση είναι:
scanf("%d%d%lf", &a, &b, &x);
Η scanf έχει πολύ περισσότερες δυνατότητες απ' ότι έχουμε δει μέχρι στιγμής. Μπορείτε να συμβουλευτείτε το αντίστοιχο manual page, αλλά θα δούμε μερικές από τις δυνατότητές της παρακάτω, και μερικές δυσκολίες που παρουσιάζει η χρήση της.

2.3.5 Αριθμητικές πράξεις και εκχώρηση αποτελέσματος σε μεταβλητή

Ας ασχοληθούμε τώρα με τη γραμμή
mean = 0.5*(a+b);
Στο δεξιό μέλος του συμβόλου εκχώρησης (=) βρίσκεται μια αριθμητική έκφραση. Τα σύμβολα των πράξεων που υπάρχουν στη C είναι τα +, -, *, /, που είναι οι συνηθισμένες τέσσερεις αριθμητικές πράξεις. Η χρήση των παρενθέσεων είναι τέτοια ώστε να υποδηλώνει ποιες πράξεις γίνονται πρώτα: το αποτέλεσμα θα ήταν πολύ διαφορετικό αν η γραμμή είχε γραφεί mean = 0.5*a+b;. Υπάρχουν και άλλα σύμβολα διμελών πράξεων στη C, αλλά τα παραπάνω είναι τα μόνο που είναι αριθμητικά, έχουν δηλ. νόημα και για αριθμούς κινητής υποδιαστολής (doubles και floats).

Το σύμβολο της διαίρεσης / έχει όμως το νόημα του πηλίκου διαίρεσης ακεραίων αν και τα δυο ορίσματά της είναι ακέραιοι, και το αποτέλεσμα που επιστρέφει μια τέτοια πράξη είναι πάλι τύπου ακεραίου. Με a%b συμβολίζουμε το υπόλοιπο της διαίρεσης του ακεραίου a δια του ακεραίου b (αυτό φυσικά έχει νόημα, όπως και το a/b μόνο όταν το b δεν είναι το 0. 2.9

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



   1 #include        <stdio.h>
   2 
   3 main()
   4 {
   5         int     a, b;
   6         double  x, y;
   7 
   8         a = 2;
   9         b = 3;
  10         x = a/b;
  11         y = 2.0/3;
  12         printf("a=%d, b=%d, x=%g, y=%g\n", a, b, x, y);
  13 }

Το αρχείο expr.c

Ιδού το output αυτού:

% a.out
a=2, b=3, x=0, y=0.666667
Το πρόβλημα εδώ είναι στη γραμμή 10, όπου το x παίρνει την τιμή 0 αντί για 0.66... Ο λόγος είναι ο εξής. Ο C compiler όταν βλέπει την έκφραση a/b την κατανοεί, ως οφείλει, ως το πηλίκο της διαίρεσης του ακεραίου a δια του ακεραίου b, και φτιάχνει κώδικα μηχανής για ακριβώς αυτή την πράξη, της οποίας το αποτέλεσμα μετά (που είναι ένας ακέραιος) το μετατρέπει στον αντίστοιχο double και εκχωρεί αυτό στο x. Φυσικά το πηλίκο της διαίρεσης 2/3 είναι 0, άρα ορθώς το x παίρνει τελικά την τιμή 0.

Γιατί δε συμβαίνει το ίδιο και στη γραμμή 11, όπου βλέπουμε ότι το y παίρνει τη σωστή του τιμή τελικά; Ο λόγος είναι ότι η προς υπολογισμό έκφραση 2.0/3 έχει τον ένα από τους δύο συμμετέχοντες αριθμούς να μην είναι ακέραιος (από τη στιγμή που χρησιμοποιούμε τη δεκαδική υποδιαστολή η σταθερά 2.0 αποθηκεύεται σε μορφή double και όχι int, όπως θα μπορούσε μια και το δεκαδικό της μέρος είναι 0. Ο μόνος τρόπος για να έχει νόημα μια αριθμητική πράξη ανάμεσα σε ένα ακέραιο κι ένα δεκαδικό αριθμό είναι να υποθέσουμε ότι, στη γενικότητα του πράγματος, το αποτέλεσμα είναι δεκαδικό. Αυτό ακριβώς κάνει ο C compiler και συγκεκριμένα μετατρέπει και τον άλλο operand (το 3) στον αντιστοιχο δεκαδικό, και κάνει διαίρεση ανάμεσα σε δυο δεκαδικούς αριθμούς (δεν παίρνει πηλίκο ακεραίων δηλαδή) της αποτέλεσμα είναι 0.666.. που τελικά εκχωρείται στο y.

2.3.6 Χρήση της printf - το πρόγραμμα format.c

Στη γραμμή 12
        printf("a=%d, b=%d, x=%g, y=%g\n", a, b, x, y);
χρησιμοποιούμε τη ρουτίνα printf για να τυπώσουμε στην οθόνη τέσσερεις αριθμούς, δύο int και δύο double, και κάποιο επεξηγηματικό κείμενο.

Η printf παίρνει, όπως και η scanf, ένα πρώτο όρισμα που είναι το format string και το οποίο προσδιορίζει πώς θα τυπωθούν με τη σειρά τα υπόλοιπα ορίσματα της printf.

Μέσα στο format string γράφουμε σε ελεύθερη μορφή το κείμενο που θέλουμε να τυπωθεί (π.χ. το ``a='' είναι τέτοιο κείμενο, όπως και το ``, b='' μετά το πρώτο %d).

Στις θέσεις που θέλουμε να τυπωθεί μια έκφραση ή μια μεταβλητή τοποθετούμε το χαρακτήρα % ακολουθούμενο από κάποιους κωδικούς χαρακτήρες ή και αριθμούς (κάντε man 3 printf), οι οποίοι δηλώνουν τον τύπο της προς τύπωση έκφρασης και διάφορες άλλες παραμέτρους. Μπορεί κανείς π.χ. να προσδιορίσει πόσα δεκαδικά ψηφία θα χρησιμοποιηθούν όταν τυπώνεται ένας double.

Μερικές από τις δυνατές επιλογές για το κείμενο που ακολουθεί το σύμβολο % είναι οι ακόλουθες:
Κείμενο στο format string Τι τυπώνεται
%d int, δεκαδική αναπαράσταση
%u unsigned int, δεκαδική αναπράσταση
%x unsigned int, δεκαεξαδική αναπαράσταση
%o unsigned int, οκταδική αναπαράσταση
%f float/double, συνήθης αναπαράσταση με υποδιαστολή
%e float/double, εκθετική μορφή
%g float/double, επιλέγεται αυτόματα %f ή %e ανάλογα με τον αριθμό
%c int ή char, τυπώνεται το ASCII σύμβολο που αντιστοιχεί στον αριθμό, π.χ. αν η έκφραση είναι ίση με 65 θα τυπωθεί το A κεφαλαίο λατινικό
%s διεύθυνση χαρακτήρα (char *), τυπώνεται η λέξη που έχει αποθηκευτεί να ξεκινά από εκείνη τη διεύθυνση χαρακτήρα
%p διεύθυνση μνήμης

Στο παρακάτω πρόγραμμα



   1 #include        <stdio.h>
   2 
   3 main()
   4 {
   5         printf("[%d]\n", 106);
   6         printf("[%x]\n", 106);
   7         printf("[%o]\n", 106);
   8         printf("[%6d]\n", 106);
   9         printf("[%-6d]\n", 106);
  10         printf("[%06d]\n", 106);
  11         printf("[%c]\n", 106);
  12 
  13         printf("\n");
  14 
  15         printf("[%f]\n", 3.14159);
  16         printf("[%e]\n", 3.14159);
  17         printf("[%g]\n", 3.14159);
  18         printf("[%.3f]\n", 3.14159);
  19         printf("[%10.3f]\n", 3.14159);
  20         printf("[%-10.3f]\n", 3.14159);
  21 }

Το αρχείο format.c

δοκιμάζουμε διάφορους τρόπους να μορφοποιηθεί η εκτύπωση για τον ακέραιο 106 και τον δεκαδικό αριθμό 3.14159. Ιδού το output του προγράμματος format.c

% a.out
[106]
[6a]
[152]
[   106]
[106   ]
[000106]
[j]

[3.141590]
[3.141590e+00]
[3.14159]
[3.142]
[     3.142]
[3.142     ]
%
Σε κάθε μια από τις γραμμές του output όπου τυπώνεται ένας αριθμός (ακέραιος ή δεκαδικός) τυπώνεται μέσα σε ένα ζεύγος αγκυλών, ώστε να είναι φανερό ακριβώς πόσες θέσεις πιάνει. Αλλιώς οι λευκοί χαρακτήρες (blanks) δε θα φαίνονταν.

Στις πρώτες 3 γραμμές τυπώνεται ο ακέραιος 106 σε μορφή δεκαδική, δεκαεξαδική και οκταδική. Στις επόμενες δύό γραμμές τυπώνεται ο ίδιος ακέραιος έτσι ώστε να καταλαμβάνει 6 θέσεις και στοιχισμένος αριστερά (που είναι η default στοίχιση) και στοιχισμένος δεξιά. Στην επόμενη γραμμή καταλμβάνει πάλι 6 θέσεις αλλά συμπληρώνεται με μηδενικά προς τα αριστερά. Η τελευταία γραμμή του πρώτου block γραμμών είναι ίσως η πιο ενδιαφέρουσα και μη ασυνήθιστη σε άλλες γλώσσες προγραμματισμού. Σε αυτήν ο ακέραιος 106 τυπώνεται ως χαρακτήρας: δηλ. τυπώνεται το σύμβολο που του αντιστοιχεί στον πίνακα ASCII που είναι το λατινικό γράμμα j.

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

Θα πρέπει να είναι ήδη φανερό πως οι δυνατότητες της printf όπως και της scanf είναι πάρα πολλές. Δεν έχει νόημα να είμαστε εξαντλητικοί εδώ στην αναφορά μας προς αυτές. Ο χρήστης πρέπει να αμαφερθεί στο αντίστοιχο manual page για να δεί ποιο ακριβώς format string να χρησιμοποιήσει κάθε φορά που θέλει να μορφοποιήσει το output με κάποιο ιδιαίτερο τρόπο. Και με λίγο πειραμτισμό, γράφοντας μικρά προγραμματάκια όπως το format.c μπορεί κάθε φορά να βρίσκει λύση στο πρόβλημά του. Αυτή η λύση βέβαια σπανίως είναι η μόνη δυνατή.



Υποσημειώσεις

... bytes2.7
Το byte είναι μια ομάδα από 8 δυαδικά ψηφία, τα bits. Είναι μάλλον η μικρότερη ομαδοποίηση δυαδικών ψηφίων σε υπολογιστές σήμερα, δηλ. όλα τα μεγέθη εκφράζονται σε ακέραιο αριθμό bytes. Αυτό φυσικά δεν υπαγορεύεται από κάποιο φυσικό νόμο αλλά είναι απλώς μια σύμβαση που έχει επικρατήσει. Τι μπορεί να παραστήσει ένα byte; Κατ' αρχήν τίποτα. Εννοώ με αυτό ότι το πώς ερμηνεύει κανείς μια ομάδα από bytes, είτε λίγα είτε πολλά, είναι αποκλειστικά και μόνο θέμα δικό του, δηλ. θέμα της συγκεκριμένης εφαρμογής. Αυτό που είναι ξεκάθαρο είναι πως μια ομάδα από 8 bits (ένα byte δηλαδή) μπορεί να πάρει 28 = 256 διαφορετικές τιμές. Αυτές μπορούν για παράδειγμα να ερμηνευτούν ως οι ακέραιοι από 0 έως 255 (αυτός είναι ο τύπος unsigned char της C), ως οι ακέραιοι από -128 έως 127 (ο τύπος char), ή ως οτιδήποτε άλλο η εφαρμογή θελήσει.
... μνήμης2.8
Η μνήμη του υπολογιστή πρέπει να θεωρείται μια γραμμική διάταξη από bytes. Αν, για παράδειγμα, ο υπολογιστής σας έχει μνήμη (RAM) 8 megabytes (δηλ. 8.220 = 8388608 bytes) τότε πρέπει να τα θεωρούμε αυτά ως τοποθετημένα στις θέσεις μνήμης από 0 έως 8388607. Μερικά από αυτά τα bytes χρησιμοποιούνται από διάφορα προγράμματα για κώδικα (δηλ. αποθήκευση εντολών) και για δεδομένα και μερικά από το δικό μας πρόγραμμα, ομοίως για την αποθήκευσή του (δηλ. την αποθήκευση των εντολών που απαρτίζουν το πρόγραμμά μας) και την αποθήκευση των δεδομένων του, δηλ. των μεταβλητών του. Κάθε μεταβλητή καταλαμβάνει ένα συνεχές κομμάτι στη μνήμη του υπολογιστή. Για παράδειγμα η μεταβλητή a στο πρόγραμμα mean.c μπορεί να καταλαμβάνει τις θέσεις μνήμης 8152320 έως και την 8152323 ενώ η μεταβλητή mean μπορεί να καταλαμβάνει τα επόμενα 8 bytes, δηλ. τα 8152324 έως και 8152331.
... 0.2.9
Την πράξη a%b να την εμπιστεύεστε μόνο όταν και οι δύο operands a και b είναι θετικοί. Για παράδειγμα, η C υπολογίζει το υπόλοιπο της διαίρεσης του -5 δια του 3 σε -2, πράγμα που διαφωνεί με τον παντού αποδεκτό μαθηματικό ορισμό που θέλει το υπόλοιπο της διαίρεσης του a δια του b να είναι ένας φυσικός αριθμός από 0 έως b-1. (Αυτή η παρατήρηση ισχύει λίγο πολύ σε όλες τις γλώσσες προγραμματισμού.) Αν κάποιος θέλει να έχει στη διάθεσή του τη σωστή πράξη υπολοίπου, ανεξάρτητα από τα πρόσημα, τότε πρέπει να την υλοποιήσει μόνος του, χρησιμοποιώντας φυσικά την υπάρχουσα πράξη %. Αργότερα θα δούμε πώς να το κάνουμε αυτό.

next up previous contents
Next: 2.4 Το πρόγραμμα cond.c Up: 2. Προγραμματισμός στη γλώσσα Previous: 2.2 Το πρόγραμμα hello.c   Contents
Mihalis Kolountzakis 2001-10-21