Perl, Java
Το πρώτο μου πρόγραμμα
Το παρακάτω πρόγραμμα τυπώνει "hello, world" στην οθόνη.
#include <stdio.h>
main()
{
printf("hello, world\n");
}
Μπορούμε να το αλλάξουμε για να τυπώσει:
Στοιχεία του προγράμματος
Τα προγράμματα της C αποτελούνται από ορισμένες βασικές τάξεις στοιχείων:
Ορισμός απλών συναρτήσεων
Ασκήσεις
Εξοικείωση με το μεταγλωττιστή και τη διαδικασία προγραμματισμού
- Να πληκτρολογήσετε, μεταγλωττίσετε και να εκτελέσετε ένα πρόγραμμα
σε C που να τυπώνει "I am learning C"
- Πειραματιστείτε αλλάζοντας διάφορα στοιχεία του προγράμματος.
(Το πιθανότερο είναι οι περισσότερες αλλαγές σας να καταλήγουν σε λάθη.)
- Φτιάξτε ένα πρόγραμμα το οποίο να τυπώνει με * ένα τετράγωνο
στην οθόνη σαν το παρακάτω:
***************
* *
* *
* *
* *
* *
* *
***************
Για να επαναλαμβανόμενα στοιχεία του τετραγώνου να ορίσετε δύο συναρτήσεις
οι οποίες να τα τυπώνουν και να τις καλέσετε όσες φορές και με τη σειρά
που χρειάζεται.
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 19-23
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 5-7.
Prentice-Hall, second edition, 1988.
Γενική βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 19-23
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- American National
Standard for Information Systems --- programming language --- C:
ANSI X3.159-1989.
Published by the American National Standards Institute, 1430 Broadway, New
York, New York 10018, December 1989.
(Also ISO/IEC 9899:1990).
- Samuel P. Harbison
and Guy L. Steele Jr.
C: A
Reference Manual.
Prentice-Hall, third edition, 1991.
- Mark R. Horton.
Portable C Software.
Prentice Hall, 1990.
- Stephen C. Johnson and
Brian W. Kernighan.
The programming language b.
Computer Science Technical Report 8, Bell Laboratories, Murray Hill, NJ, USA,
January 1977.
- Brian W. Kernighan and
P. J. Plauger.
The Elements
of Programming Style.
McGraw-Hill, second edition, 1978.
- Brian W. Kernighan and
Dennis M. Ritchie.
The C Programming Language.
Prentice-Hall, first edition, 1978.
- Brian W. Kernighan.
Why Pascal is not my favorite programming language.
Technical Report 100, Bell Laboratories, Murray Hill, New Jersey 07974, July
1981.
- Andrew Koenig.
C Traps and
Pitfalls.
Addison-Wesley, 1988.
- Don Libes.
Obfuscated
C and Other Mysteries.
John Wiley and Sons, 1993.
- P. J. Plauger.
The Standard C Library.
Prentice Hall, 1992.
- Henry Rabinowitz and
Chaim Schaap.
Portable C.
Prentice Hall, 1990.
- D. M. Ritchie, S. C. Johnson,
M. E. Lesk, and B. W. Kernighan.
The C programming language.
Bell System Technical Journal, 57(6), July-August, Year=.
- Dennis M. Ritchie.
The development of the C language.
ACM SIGPLAN Notices, 28(3):201-208, March 1993.
Preprints of the History of Programming Languages Conference (HOPL-II).
- L. Rosler.
The evolution of c --- past and future.
Bell System Technical Journal, 63(8), October 1984.
- Robert Sedgewick.
Algorithms in
C.
Addison-Wesley, 1990.
- The Accredited
Standard Committee X3, Information Processing Systems, Technical Committee
for Programming Language C (X3J11).
Rationale for
the ANSI C Programming Language.
Silicon Press, 25 Beverly Road, Summit, NJ 07901, USA, 1990.
Υπολογισμοί με μεταβλητές, είσοδος και έξοδος
Σταθερές
- Η συμβολοσειρά (string) "hello, world" την
οποία είδαμε στο προηγούμενο μάθημα είναι μια
σταθερά (constant) της γλώσσας C.
- Οι σταθερές αυτές χρησιμοποιούνται συχνά για να παραστήσουν μηνύματα
προς το χρήστη (π.χ. "Παρακαλώ βάλτε την κάρτα σας στην υποδοχή") ή
και μεταξύ υπολογιστών (π.χ. "RCPT TO: dspin@aegean.gr").
- Ένα άλλο είδος σταθερών είναι αυτές που παριστάνουν αριθμητικές
τιμές (π.χ. 42 ή 3.1415927).
- Στη C ξεχωρίζουμε της ακέραιες (integer)
σταθερές (π.χ. 42, 123456, -3) και τις σταθερές που παριστάνουν
αριθμούς κινητής υποδιαστολής (floating point numbers)
(π.χ. 3.1415827, -2.0, 6.023e-23).
Εκτύπωση τιμών
- Για να τυπώσουμε ακέραιες τιμές προσθέτουμε στη συμβολοσειρά του
printf τον κωδικό μορφής (format code) %d στο
σημείο που θέλουμε να εμφανιστεί η κάθε τιμή και ακολουθούμε
τη συμβολοσειρά με τις αντίστοιχες τιμές. Παράδειγμα:
printf("Τα γραπτά βαθμολογούνται με βαθμούς από το %d μέχρι το %d.\n",0, 10);
).
- Αντίστοιχα για να τυπώσουμε τιμές κινητής υποδιαστολής χρησιμοποιούμε
τον κωδικό μορφής %g. Παράδειγμα:
printf("Ο αριθμός %g είναι μια προσέγγιση του π.", 3.1415927)
Απλές πράξεις
Οι αριθμητικές τιμές της C μπορούν να συνδυαστούν με τη
χρήση των παρακάτω τελεστών (operands):
Πράξη | Τελεστής της C |
Πρόσθεση | + |
Αφαίρεση | - |
Πολλαπλασιασμός | * |
Διαίρεση | / |
Υπόλοιπο ακέραιας διαίρεσης | % |
- Για τον υπολογισμό μιας τιμής, πρώτα εκτελούνται οι πράξεις ανάμεσα
στους τελεστές * / % και μετά οι πράξεις ανάμεσα στους τελεστές + -.
- Η παραπάνω σειρά μπορεί να μεταβληθεί με τη χρήση παρενθέσεων.
Παραδείγματα
- printf("ένα συν ένα = %d\n", 1 + 1);
- printf("Το εμβαδό του δωματίου είναι %d τετραγωνικά μέτρα.\n", 3 * 5);
- printf("%g βαθμοί Celsius = %g βαθμοί Fahrenheit.\n", 36.7,
32 + 9.0 / 5.0 * 36.7);
- printf("%d\n", 1 + 2 * 3); /* Τυπώνει 7 */
- printf("%d\n", (1 + 2) * 3); /* Τυπώνει 9 */
Μεταβλητές
- Οι αριθμητικές τιμές μπορούν να αποθηκευτούν σε
μεταβλητές (variables)
- Οι μεταβλητές που χρησιμοποιούμε για να αποθηκεύμουμε τιμές κατά
το διάστημα που υπολογίζεται μια συνάρτηση ορίζονται στην αρχή της
αντίστοιχης συνάρτησης μετά το σύμβολο "{".
- Ο ορισμός τους γίνεται γράφοντας τον τύπο της μεταβλητής
(int για ακέραιες τιμές, double για τιμές κινητής υποδιαστολής)
ακολουθούμενο από το όνομα της μεταβλητής.
Στο τέλος του ορισμού γράφουμε το χαρακτήρα ";".
- Μπορούμε να ορίσουμε πολλές μεταβλητές ίδιου τύπου χωρίζοντάς τις
με ",".
Παράδειγμα:
main()
{
int faces;
double x, y;
}
- Για να δώσουμε μια τιμή σε μια μεταβλητή χρησιμοποιούμε τη
σύνταξη:
μεταβλητή = τιμή;
για παράδειγμα:
faces = 2 * 8 + 12;
- Στη συνέχεια μπορούμε να χρησιμοποιούμε την τιμή της μεταβλητής
όπως και οποιοδήποτε άλλη σταθερά. Παράδειγμα:
#include <stdio.h>
main()
{
int faces;
double len;
len = 12.5;
faces = 6;
printf("Επιφάνεια = %g\n", len * len * faces);
}
Είσοδος στοιχείων
Ασκήσεις
Είσοδος έξοδος και υπολογισμοί
- Να γράψετε ένα πρόγραμμα που θα διαβάζει από το χρήστη την
ταχύτητα ενός αντικειμένου σε km/h και την τυπώνει σε m/s.
Παράδειγμα της εκτέλεσης του πρόγραμματος:
Speed (km/h)=120
A speed of 120 km/h is 33.333 m/s
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 23-28, 218-222 (τμήματα)
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 8-12, 157-169 (parts).
Prentice-Hall, second edition, 1988.
Τελεστές σύγκρισης, λογικής και επαναλήψεις
Τελεστές σύγκρισης
Οι αριθμητικές τιμές της C μπορούν να συγκριθούν με τη
χρήση των παρακάτω τελεστών:
Σύγκριση | Τελεστής της C |
Ίσο | == |
Διάφορο | != |
Μικρότερο | < |
Μεγαλύτερο | > |
Μικρότερο ή ίσο | <= |
Μεγαλύτερο ή ίσο | >= |
- Για τον υπολογισμό μιας τιμής, πρώτα εκτελούνται οι πράξεις ανάμεσα
στους τελεστές * / %, μετά οι πράξεις ανάμεσα στους τελεστές + -,
μετά ανάμεσα στους τελεστές < > <= >= και μετά
ανάμεσα στους τελεστές == και !=.
- Η παραπάνω σειρά μπορεί να μεταβληθεί με τη χρήση παρενθέσεων.
- Το αποτέλεσμα της κάθε σύγκρισης είναι
1 (αληθές (true)) αν το αποτέλεσμα της σύγκρισης είναι
αληθές και
0 (ψευδές (false)) αν το αποτέλεσμα της σύγκρισης είναι
ψευδές.
Παραδείγματα
- printf("%d\n", 1 + 1 == 2); /* Τυπώνει 1 */
- printf("%d\n", 1 > 2); /* Τυπώνει 0 */
- printf("%d\n", 5 != 5); /* Τυπώνει 0 */
- printf("%d\n", 1 <= 5); /* Τυπώνει 1 */
- printf("%d\n", 1 <= 1); /* Τυπώνει 1 */
- printf("%d\n", 1 <= 0); /* Τυπώνει 0 */
Βρόχοι με την εντολή while
- Μπορούμε να επαναλάβουμε την εκτέλεση ορισμένων εντολών με τη
δομή ελέγχου (control structure) while.
- Αυτή χρησιμοποιείται ως εξής:
while (συνθήκη)
εντολή;
- Τις περισσότερες φορές θέλουμε να εκτελέσουμε πάνω από μια εντολή
πολλαπλές φορές οπότε περικλείουμε όλες τις αντίστοιχες εντολές μέσα σε
αγκύλες "{" και "}":
while (συνθήκη) {
εντολή1;
εντολή2;
εντολή3;
}
- Η εντολή που ακολουθεί το while εκτελείται όσο η συνθήκη είναι
αληθής, δηλαδή έχει τιμή διάφορη του 0.
Παράδειγμα (τυπώνει τους αριθμούς από το 0 μέχρι το 9):
#include <stdio.h>
main()
{
int i;
i = 0;
while (i < 10) {
printf("%d\n", i);
i = i + 1;
}
}
- Αν η συνθήκη δεν είναι αληθής όταν εκτελεστεί το while για πρώτη
φορά τότε η εντολή που περιέχεται σε αυτό δε θα εκτελεστεί.
- Η δομή ελέγχου while μπορεί να χρησιμοποιηθεί οπουδήποτε θα μπορούσε
και οποιαδήποτε άλλη εντολή (π.χ. η printf) δηλαδή ακόμα και μέσα σε μια άλλη
while.
Το παρακάτω παράδειγμα τυπώνει στην οθόνη ένα τριγωνικό σχήμα:
#include <stdio.h>
main()
{
int row, stars;
row = 0;
while (row < 10) {
stars = row;
while (stars > 0) {
printf("*");
stars = stars - 1;
}
row = row + 1;
printf("\n");
}
}
όπως αυτό:
*
**
***
****
*****
******
*******
********
*********
Βρόχοι με την εντολή do while
- Ορισμένες φορές θέλουμε να ελέγχουμε τη συνθήκη στο τέλος
του βρόχου, δηλαδή η εντολή να εκτελεστεί τουλάχιστον μια φορά.
Στις περιπτώσεις αυτές χρησιμοποιούμε τη δομή ελέγχου do while
- Αυτή χρησιμοποιείται ως εξής:
do
εντολή;
while (συνθήκη);
- Τις περισσότερες φορές θέλουμε να εκτελέσουμε πάνω από μια εντολή
πολλαπλές φορές οπότε περικλείουμε όλες τις αντίστοιχες εντολές μέσα σε
αγκύλες "{" και "}":
do {
εντολή1;
εντολή2;
εντολή3;
} while (συνθήκη);
- Η εντολή που ακολουθεί το do εκτελείται μια φορά και συνεχίζει
να εκτελείται όσο η συνθήκη είναι αληθής, δηλαδή έχει τιμή διάφορη του 0.
- Σημαντικό ρόλο έχει αυτή η δομή ελέγχου όταν διαβάζουμε στοιχεία
από το χρήστη και θέλουμε να ελέγξουμε την είσοδο για λάθη.
Παράδειγμα (εισάγει έναν αριθμό μικρότερο του 10):
#include <stdio.h>
main()
{
int number;
do {
printf("Enter a number less than 10: ");
scanf("%d", &number);
} while (number >= 10);
printf("You entered %d\n", number);
}
όπως φαίνεται από το παρακάτω παράδειγμα:
Enter a number less than 10: 34
Enter a number less than 10: 50
Enter a number less than 10: 2
You entered 2
- Αν η συνθήκη δεν είναι αληθής όταν εκτελεστεί το do για πρώτη
φορά τότε η εντολή που περιέχεται σε αυτό θα εκτελεστεί τουλάχιστον μια φορά.
- Η δομή ελέγχου do μπορεί να χρησιμοποιηθεί οπουδήποτε θα μπορούσε
και οποιαδήποτε άλλη εντολή (π.χ. η printf) δηλαδή ακόμα και μέσα σε μια άλλη
do ή while.
Λογικοί τελεστές
Τα λογικά αποτελέσματα στη C μπορούν να συνδυαστούν με τη
χρήση των παρακάτω λογικών τελεστών:
Παράδειγμα
Ο παρακάτω βρόχος μπορεί να αποτελεί τμήμα του προγράμματος
ελέγχου ενός τραπεζικού μηχανήματος αυτομάτων συναλλαγών:
{
int secret, pin, tries;
secret = 1234; /* Customer's secret PIN */
tries = 0;
do {
printf("Δώστε το PIN σας: ");
scanf("%d", &pin);
tries = tries + 1;
} while (pin != secret && tries < 4);
/* Correct PIN entered or number of tries exhausted */
}
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 26, 67-69, 305-306 (τμήματα)
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 10, 41-42, 223-224 (parts).
Prentice-Hall, second edition, 1988.
Ασκήσεις
Βρόχοι
- Να γράψετε ένα πρόγραμμα που να τυπώνει τον πίνακα της
προπαίδειας όπως στο παρακάτω παράδειγμα:
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
Για να μπορέσουν οι αριθμοί να εμφανιστούν σε στήλες μπορείτε
να χρησιμοποιήσετε στην printf τον κωδικό εξόδου %4d
(εμφάνιση του αριθμού σε χώρο 4 χαρακτήρων) αντί του κωδικού %d.
Προγραμματισμός με χαρακτήρες, αποφάσεις
Η εντολή if-else
- Μπορούμε να εκτελέσουμε ορισμένες εντολές υπό συνθήκη με τη
δομή ελέγχου if.
- Αυτή χρησιμοποιείται ως εξής:
if (συνθήκη)
εντολή;
- Όπως και με τις εντολές while και do όταν θέλουμε να εκτελέσουμε πάνω
από μια εντολή υπό συνθήκη περικλείουμε όλες τις αντίστοιχες εντολές μέσα σε
αγκύλες "{" και "}":
if (συνθήκη) {
εντολή1;
εντολή2;
εντολή3;
}
- Οι εντολή που ακολουθεί το if εκτελείται αν η συνθήκη είναι
αληθής, δηλαδή έχει τιμή διάφορη του 0.
Παράδειγμα (υπολογίζει και τυπώνει την απόλυτη τιμή των αριθμών που διαβάζει
μέχρι να συναντήσει το 0):
#include <stdio.h>
main()
{
int num;
do {
scanf("%d", &num);
if (num < 0)
num = -num;
printf("%d\n", num);
} while (num != 0);
}
- Η δομή ελέγχου if μπορεί να ακολουθηθεί και από τη δομή else
για να προσδιορίσουμε εντολές που θα εκτελεστούν αν η συνθήκη δεν
ισχύει.
Παράδειγμα:
if (grade >= 5)
printf("Περνάει\n");
else
printf("Απορρίπτεται\n");
- Χρειάζεται προσοχή όταν η else ακολουθεί δύο συνεχόμενες if.
Στην περίπτωση αυτή, η else συσχετίζεται με την κοντινότερη if.
Για να εκφράσουμε διαφορετική συσχέτιση πρέπει να χρησιμοποιήσουμε
αγκύλες { }.
Παράδειγμα (τυπώνει μόνο όταν η μεταβλητή printed είναι ψευδής):
if (exam >= 5) {
if (!printed)
printf("Περνάει\n");
} else
if (!printed)
printf("Απορρίπτεται\n");
printed = 1;
Το παρακάτω παράδειγμα (χωρίς αγκύλες) δεν εκτελείται σύμφωνα με τον
τρόπο που είναι στοιχισμένο
if (exam >= 5)
if (!printed)
printf("Περνάει\n");
else
if (!printed)
printf("Απορρίπτεται\n");
printed = 1;
αλλά ως εξής (δεν τυπώνει ποτέ "Απορρίπτεται"):
if (exam >= 5)
if (!printed)
printf("Περνάει\n");
else
if (!printed)
printf("Απορρίπτεται\n");
printed = 1;
- Μπορούμε να συνδυάσουμε συνεχόμενα else if για πολλαπλούς
ελέγχους. Παράδειγμα:
if (grade >= 9)
printf("'Αριστα!\n");
else if (grade >= 7)
printf("Λίαν καλώς\n");
else if (grade >= 5)
printf("Καλώς\n");
else
printf("Κακώς\n");
Τελεστές μοναδιαίας αύξησης και μείωσης, αποτέλεσμα ανάθεσης
- Ο τελεστής ++ στη χρήση ++var αυξάνει την τιμή της μεταβλητής
var κατά ένα.
Η τιμή της μεταβλητής var που χρησιμοποιείται στην παράσταση είναι αυτή
που προκύπτει μετά την αύξηση.
Παράδειγμα (τυπώνει 5, 5):
i = 4;
printf("%d,", ++i)
printf("%d\n", i)
- Ο τελεστής ++ στη χρήση var++ επίσης αυξάνει την τιμή της μεταβλητής
var κατά ένα.
Η τιμή της μεταβλητής var που χρησιμοποιείται στην παράσταση είναι αυτή
που ήταν πριν την αύξηση.
Παράδειγμα (τυπώνει 4, 5):
i = 4;
printf("%d,", i++)
printf("%d\n", i)
- Τα αντίστοιχα ισχύουν και για τον τελεστή -- που μειώνει την τιμή
μιας μεταβλητής κατά 1.
- Η παράσταση "var = value" έχει ως τιμή την τιμή της μεταβλητής.
Παράδειγμα (τυπώνει 2, 2):
i = 4;
printf("%d,", i = 2)
printf("%d\n", i)
- Με τον τρόπο αυτό μπορούμε με συντομία να αναθέσουμε την ίδια τιμή
σε πολλές μεταβλητές (οι μεταβλητές i και j γίνονται 0):
i = j = 0;
Ο τύπος του χαρακτήρα
- Μπορούμε να ορίσουμε μεταβλητές τύπου χαρακτήρα
με τον τύπο char:
main()
{
char c;
}
- Οι μεταβλητές αυτές μπορούν να αποθηκεύσουν έναν ακριβώς χαρακτήρα.
- Οι σταθερές τύπου χαρακτήρα γράφονται με τη χρήση των μονών εισαγωγικών:
main()
{
char c;
c = 'A';
}
- Οι ακολουθίες διαφυγής (escape sequence) που έχουμε
μάθει για τις αλφαριθμητικές σταθερές ισχύουν και για τις σταθερές τύπου
χαρακτήρα.
Είσοδος και έξοδος χαρακτήρων
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 32-41, 86-89
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 15-21, 55-58.
Prentice-Hall, second edition, 1988.
Ασκήσεις
If, char
- Να γράψετε ένα πρόγραμμα που να διαβάζει χαρακτήρες
από την είσοδό του μέχρι να τερματιστεί το αρχείο εισόδου.
Στο τέλος να τυπώνει τον αριθμό των χαρακτήρων, γραμμών,
ψηφίων (0-9), πεζών χαρακτήρων (a-z) και κεφαλαίων χαρακτήρων (A-Z)
που διάβασε. (Οι χαρακτήρες στο σύστημα που χρησιμοποιούμε είναι
ταξινομημένοι αλφαβητικά. Η παράσταση c >= 'a' && c <= 'z' είναι αληθής
για πεζούς χαρακτήρες στη μεταβλητή c.)
- Εκτελέστε το πρόγραμμά σας με είσοδο τον εαυτό του.
Πρόσθετες δομές ελέγχου: switch for break continue
Η εντολή for
- Μπορούμε να συμπυκνώσουμε τον έλεγχο ενός βρόχου με την εντολή
for.
- Αυτή χρησιμοποιείται ως εξής:
for (αρχική παράσταση; παράσταση συνθήκης; τελική παράσταση)
εντολή;
- Ο βρόχος που ορίζει η for εκτελείται ως εξής:
- Υπολογίζεται η αρχική παράσταση.
- Υπολογίζεται η παράσταση συνθήκης και αν είναι αληθής τότε εκτελείται η εντολή.
- Υπολογίζεται η τελική παράσταση.
- Ο βρόχος συνεχίζει από το βήμα 2.
- Παράδειγμα (τυπώνει τους αριθμούς 0-9):
#include <stdio.h>
main()
{
int i;
for (i = 0; i < 10; i++)
printf("%d\n", i);
}
- Η εντολή for είναι ισοδύναμη με την παρακάτω while:
αρχική παράσταση;
while (παράσταση συνθήκης) {
εντολή;
τελική παράσταση;
}
- Οποιαδήποτε από τις τρεις παραστάσεις μπορεί να παραληφθεί.
- Αν παραληφθούν και οι τρεις παραστάσεις τότε ο βρόχος εκτελείται για πάντα
(ατέρμονος βρόχος (infinite loop)).
- Χρησιμοποιούμε τη for όταν οι τρεις παραστάσεις είναι σχετικές
μεταξύ τους.
Η εντολή break
Η εντολή switch
- Η εντολή switch μας επιτρέπει να κατευθύνουμε τη ροή του
προγράμματος προς μια συγκεκριμένη σταθερή τιμή ανάλογα με την
τιμή μιας παράστασης.
- Συντάσσεται ως εξής:
switch (παράσταση) {
case σταθερή1:
εντολή1;
εντολή1α;
εντολή1β;
...
break;
case σταθερή2:
εντολή2;
...
break;
...
default:
εντολή ν;
break;
}
- Ανάλογα με το με ποια σταθερή ισούται η τιμή της παράστασης
εκτελείται η αντίστοιχη εντολή.
- Αν καμία από τις σταθερές δεν ταυτίζεται με την τιμή της παράστασης
τότε εκτελείται η εντολή που ακολουθεί την default (αν υπάρχει), αλλιώς
δεν εκτελείται καμία εντολή.
- Παράδειγμα (τυπώνει την είσοδο μετατρέποντας χαρακτήρες που παριστάνονται
με ακολουθίες διαφυγής στις αντίστοιχες ακολουθίες):
#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF)
switch (c) {
case '\n':
printf("\\n");
break;
case '\a':
printf("\\a");
break;
case '\t':
printf("\\t");
break;
default:
putchar(c);
}
}
Με είσοδο τον εαυτό του παράγει το παρακάτω αποτέλεσμα:
#include <stdio.h>\n\nmain()\n{\n\tint c;\n\n\twhile
((c = getchar()) != EOF)\n\t\tswitch (c) {\n\t\tcase
'\n':\n\t\t\tprintf("\\n");\n\t\t\tbreak;\n\t\tcase
'\a':\n\t\t\tprintf("\\a");\n\t\t\tbreak;\n\t\tcase
'\t':\n\t\t\tprintf("\\t");\n\t\t\tbreak;\n\t\tdefault:
\n\t\t\tputchar(c);\n\t\t}\n}\n
- Το break δηλώνει ότι ο έλεγχος του προγράμματος μετά την εντολή
συνεχίζει στο τέλος της switch.
Σε αντίθετη περίπτωση ο έλεγχος του προγράμματος συνεχίζει στην επόμενη
case.
Η ιδιότητα αυτή μας επιτρέπει να δηλώσουμε πολλαπλές τιμές.
- Το παρακάτω παράδειγμα μετατρέπει όλα τα πεζά φωνήεντα σε a
και σύμφωνα σε z
#include <stdio.h>
main()
{
int c;
while ((c = getchar()) != EOF)
switch (c) {
case 'a': case 'e': case 'i': case 'o':
case 'u': case 'y':
putchar('a');
break;
case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'p':
case 'q': case 'r': case 's': case 't':
case 'v': case 'w': case 'x': case 'z':
putchar('z');
break;
default:
putchar(c);
}
}
Με είσοδο τον εαυτό του παράγει το παρακάτω αποτέλεσμα:
#azzzaza <zzzaa.z>
zaaz()
{
azz z;
zzaza ((z = zazzzaz()) != EOF)
zzazzz (z) {
zaza 'a': zaza 'a': zaza 'a': zaza 'a':
zaza 'a': zaza 'a':
zazzzaz('a');
zzaaz;
zaza 'z': zaza 'z': zaza 'z': zaza 'z':
zaza 'z': zaza 'z': zaza 'z': zaza 'z':
zaza 'z': zaza 'z': zaza 'z': zaza 'z':
zaza 'z': zaza 'z': zaza 'z': zaza 'z':
zaza 'z': zaza 'z': zaza 'z': zaza 'z':
zazzzaz('z');
zzaaz;
zazaazz:
zazzzaz(z);
}
}
Η εντολή continue
- Η εντολή continue μας επιτρέπει να συνεχίσουμε την εκτέλεση
μιας δομής ελέγχου βρόχου (for, while, do) από το σημείο ελέγχου
της συνθήκης.
- Είναι κυρίως χρήσιμη όταν θέλουμε να κάνουμε έναν έλεγχο στην
κορυφή του βρόχου για κάποια ειδική περίπτωση.
- Το παρακάτω παράδειγμα μετατρέπει κάθε πέμπτο πεζό φωνήεν σε a
και σύμφωνο σε z:
#include <stdio.h>
main()
{
int c, i;
i = 0;
while ((c = getchar()) != EOF) {
if (i++ % 5 != 0) {
putchar(c);
continue;
}
switch (c) {
case 'a': case 'e': case 'i': case 'o':
case 'u': case 'y':
putchar('a');
break;
case 'b': case 'c': case 'd': case 'f':
case 'g': case 'h': case 'j': case 'k':
case 'l': case 'm': case 'n': case 'p':
case 'q': case 'r': case 's': case 't':
case 'v': case 'w': case 'x': case 'z':
putchar('z');
break;
default:
putchar(c);
}
}
}
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 85-98
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 55-64.
Prentice-Hall, second edition, 1988.
Ασκήσεις
switch, for
- Να γράψετε ένα πρόγραμμα που να διαβάζει χαρακτήρες
από την είσοδό του μέχρι να συναντήσει την τελεία.
Οι χαρακτήρες που διαβάζει να εκτυπώνονται σύμφωνα με το διεθνές
φωνητικό αλφάβητο:
Alpha Bravo Charlie Delta Echo Foxtrot Golf Hotel India
Juliet Kilo Lima Mike November Oscar Papa Quebec Romeo
Sierra Tango Uniform Victor Whiskey Xray Yankee Zulu.
Τα ψηφία 1-9 να εκτυπώνονται με επαναλαμβανόμενα αστέρια (*)
αντίστοιχα με το ψηφίο.
Χαρακτήρες για τους οποίους δεν υπάρχει αντιστοιχία να εκτυπώνονται
ως έχουν.
Παράδειγμα:
Είσοδος:
Hello 2 you!.
Αποτέλεσμα:
Hotel Echo Lima Lima Oscar ** Yankee Oscar Uniform!
Ορισμός συναρτήσεων
Δήλωση συναρτήσεων
- Μπορούμε να ορίσουμε δικές μας συναρτήσεις με τον εξής τρόπο:
τύπος αποτελέσματος
όνομα συνάρτησης(δηλώσεις παραμέτρων)
{
δηλώσεις τοπικών μεταβλητών;
εντολές;
return (τιμή);
}
- Οι παράμετροι της συνάρτησης είναι μια σειρά από τύπους και ονόματα
μεταβλητών χωρισμένα με κόμμα.
- Όταν καλείται μια συνάρτηση οι μεταβλητές που ορίστηκαν ως παράμετροι
παίρνουν τις τιμές που δόθηκαν στο όρισμα κατά την κλήση.
- Η εντολή return μπορεί να εμφανιστεί σε οποιοδήποτε σημείο της συνάρτησης.
Στο σημείο εκείνο σταματά η εκτέλεση της συνάρτηση και ο
έλεγχος ροής (control flow) του προγράμματος
συνεχίζει από το σημείο που κλήθηκε η συνάρτηση.
Η τιμή που ακολουθεί την return είναι η τιμή που επιστρέφει η συνάρτηση.
- Παράδειγμα:
/*
* Return x squared
*/
double
sqr(double x)
{
return (x * x);
}
- Αν η συνάρτηση δεν επιστρέφει κάποια τιμή, τότε ορίζουμε τον
τύπο της ως void.
- Αν η συνάρτηση δε δέχεται παραμέτρους τότε γράφουμε στην αντίστοιχη θέση
τη λέξη void.
- Παράδειγμα:
void
print_hello(void)
{
printf("Hello, world\n");
}
- Οι συναρτήσεις μπορούν να οριστούν με οποιαδήποτε σειρά μέσα στο πρόγραμμα.
Αν όμως μια συνάρτηση χρησιμοποιηθεί πριν τον
ορισμό (definition), τότε πρέπει να
προηγηθεί μια
δήλωση (declaration) της συνάρτησης.
Η δήλωση γίνεται με τη μορφή
πρωτοτύπου (prototype) το οποίο έχει την ίδια
μορφή με τον ορισμό του ονόματος και των παραμέτρων, αλλά αντί να
ακολουθείται από το τμήμα με τις εντολής ακολουθείται μόνο από ένα ";".
Παράδειγμα (τυπώνει 25):
/* Declaration */
double sqr(double x);
main()
{
printf("%g\n", sqr(5))
}
/* Definition */
double
sqr(double x)
{
return (x * x);
}
Παράμετροι τιμής
- Οι μεταβλητές που αποτελούν το όρισμα της συνάρτησης αποκτούν
την τιμή που θα δώσουμε όταν καλέσουμε τη συνάρτηση.
- Οποιαδήποτε μετατροπή στην τιμή των μεταβλητών αυτών δεν
επηρεάζει την τιμή κάποιας μεταβλητής που δόθηκε ως παράμετρος
κατά την κλήση της συνάρτησης.
- Παράδειγμα (τυπώνει 10, 20, 10):
void
print_n2n(int n)
{
printf("%d ", n);
n = n * 2;
printf("%d ", n);
}
main()
{
int i = 10;
print_n2n(i);
printf("%d\n", i);
}
- Έτσι μπορούμε να χρησιμοποιούμε τις μεταβλητές του ορίσματος
σαν κανονικές μεταβλητές χωρίς να χρειάζεται (ούτε και να
επιτρέπεται) να τις ορίσουμε μέσα στο σώμα της συνάρτησης.
- Ο τρόπος αυτός κλήσης ονομάζεται
κλήση κατ' αξία (call by value).
Καθολικές μεταβλητές
Μεταβλητές static
Μεταβλητές τοπικές σε μπλοκ
Ασκήσεις
Σχεδιασμός
- Σκεφτείτε την υλοποίηση ενός προγράμματος που θα στοιχίζει σωστά
άλλα προγράμματα.
Παράδειγμα εισόδου:
#include <stdio.h>
main(){ int i; for (i=0
;
i<10;i++)printf("i = %d\n", i);}
Παράδειγμα εξόδου:
#include <stdio.h>
main()
{
int i;
for (i = 0; i < 10; i++)
printf("i = %d\n", i);
}
Το πρόγραμμα αυτό θα συζητηθεί στο επόμενο μάθημα.
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 44-49, 121.
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 24-25, 83.
Prentice-Hall, second edition, 1988.
Παράδειγμα: μορφοποίηση προγραμμάτων
Ο κύκλος ζωής του λογισμικού
- Ανεπίσημες προδιαγραφές
- Επίσημες προδιαγραφές
- Αρχιτεκτονική σχεδίαση
- Λεπτομερής σχεδίαση
- Κωδικοποίηση
- Συνένωση
- Έλεγχος και δοκιμαστική λειτουργία
- Λειτουργία και συντήρηση
Ανεπίσημες προδιαγραφές
Να γραφεί ένα πρόγραμμα το οποίο να στοιχίζει σωστά προγράμματα γραμμένα
σε C.
Επίσημες προδιαγραφές
Να γραφεί ένα πρόγραμμα το οποίο θα θέτει σωστά τα κενά στην αρχή των
γραμμών.
Παράδειγμα εισόδου:
#include <stdio.h>
/*
* Play the bahm boom game:
* - print ascending numbers;
* - bahm's at 9 multiples;
* - boom's at 7 multiples;
*/
main()
{
int i;
for (i = 0; i < 100; i++) {
if (i % 9 == 0) {
printf("{BAHM}\n");
if (i % 9 == 0) {
printf("{BAHM}\n");
} else if (i % 7 == 0) {
printf("{BOOM}\n");
} else {
printf("%d\n", i);
}
}
}
Παράδειγμα εξόδου:
#include <stdio.h>
/*
* Play the bahm boom game:
* - print ascending numbers;
* - bahm's at 9 multiples;
* - boom's at 7 multiples;
*/
main()
{
int i;
for (i = 0; i < 100; i++) {
if (i % 9 == 0) {
printf("{BAHM}\n");
if (i % 9 == 0) {
printf("{BAHM}\n");
} else if (i % 7 == 0) {
printf("{BOOM}\n");
} else {
printf("%d\n", i);
}
}
}
}
- Υποθέτουμε ότι όλα τα for, if, while, do, else κλπ ακολουθούνται από εντολές
μέσα σε { }.
- Μετά από κάθε { η στοίχιση αυξάνει κατά ένα επίπεδο.
- Μετά από κάθε } η στοίχιση μειώνεται κατά ένα επίπεδο.
- Κατά την επεξεργασία σταθερών χαρακτήρων και συμβολοσειρών οι
παραπάνω δύο κανόνες δεν ισχύουν.
- Κατά την επεξεργασία σχολίων δεν αλλάζουμε τίποτα.
- Οι γραμμές που αρχίζουν με # δεν αλλάζουν καθόλου.
Αρχιτεκτονική σχεδίαση
- Θέλουμε με κάποιο τρόπο να ξέρουμε τι στοιχείο επεξεργαζόμαστε (
κανονικό πρόγραμμα, συμβολοσειρά, σταθερά χαρακτήρα, σχόλιο, κλπ).
- Αυτό εκφράζεται από την κατάσταση (state)
του προγράμματος.
- Η επεξεργασία για κάθε κατάσταση θα γίνεται χωριστά.
- Ορίζουμε τις παρακάτω καταστάσεις:
- NORMAL,
- HASH,
- SLASH,
- COMMENT,
- STAR,
- STRING,
- BACKSLASH_STRING,
- CHARACTER,
- BACKSLASH_CHARACTER,
- NEWLINE,
και το αντίστοιχο
διάγραμμα μετάπτωσης κατάστασης (state transition diagram)
- Στην αρχή της γραμμής αγνοούμε τα κενά και τυπώνουμε τα
δικά μας κενά.
- Οι χαρακτήρες { } αλλάζουν το επίπεδο στοίχισης.
- Η στοίχιση γίνεται από ξεχωριστή συνάρτηση.
Λεπτομερής σχεδίαση
- Σχεδιάζουμε το πλήρες διάγραμμα μετάπτωσης καταστάσεων.
- Κάθε χαρακτήρας που διαβάζεται στέλνεται στην αντίστοιχη
συνάρτηση επεξεργασίας.
- Στην κατάσταση NEWLINE χειριζόμαστε το θέμα της στοίχισης
πριν γίνει η μετάπτωση στην κατάσταση NORMAL.
- Στην κατάσταση NORMAL χειριζόμαστε την αλλαγή επιπέδου
στοίχισης με τα { και }.
Κωδικοποίηση
#include <stdio.h>
/* States the system can be in */
enum states {
NORMAL,
HASH,
SLASH,
COMMENT,
STAR,
STRING,
BACKSLASH_STRING,
CHARACTER,
BACKSLASH_CHARACTER,
NEWLINE,
};
/* Current state */
int state = NORMAL;
/* Current level of indent (tabs to print at the beginning of a line) */
int indent_level = 0;
/*
* Print tabs to indent the following character by indent_level
*/
void
indent(void)
{
int i;
for (i = 0; i < indent_level; i++)
putchar('\t');
}
/*
* State processing functions start here
*/
void
comment(char c)
{
putchar(c);
if (c == '*')
state = STAR;
}
void
slash(char c)
{
putchar(c);
if (c == '*')
state = COMMENT;
else
state = NORMAL;
}
void
string(char c)
{
putchar(c);
if (c == '"')
state = NORMAL;
else if (c == '\\')
state = BACKSLASH_STRING;
}
void
backslash_string(char c)
{
putchar(c);
state = STRING;
}
void
character(char c)
{
putchar(c);
if (c == '\'')
state = NORMAL;
else if (c == '\\')
state = BACKSLASH_CHARACTER;
}
void
backslash_character(char c)
{
putchar(c);
state = CHARACTER;
}
void
hash(char c)
{
putchar(c);
if (c == '\n')
state = NORMAL;
}
void
normal(char c)
{
putchar(c);
switch (c) {
case '#':
state = HASH;
break;
case '/':
state = SLASH;
break;
case '\'':
state = CHARACTER;
break;
case '"':
state = STRING;
break;
case '{':
indent_level++;
break;
case '\n':
state = NEWLINE;
break;
}
}
void
star(char c)
{
putchar(c);
if (c == '/')
state = NORMAL;
else
state = COMMENT;
}
void
newline(char c)
{
switch (c) {
case ' ':
case '\n':
case '\t':
break;
case '}':
indent_level--;
/* FALLTRHOUGH */
default:
indent();
state = NORMAL;
normal(c);
break;
}
}
/*
* Process a single character.
* Call the appropriate state handling function
*/
void
process(char c)
{
switch (state) {
case NORMAL:
normal(c);
break;
case COMMENT:
comment(c);
break;
case HASH:
hash(c);
break;
case SLASH:
slash(c);
break;
case STAR:
star(c);
break;
case STRING:
string(c);
break;
case BACKSLASH_STRING:
backslash_string(c);
break;
case NEWLINE:
newline(c);
break;
case CHARACTER:
character(c);
break;
case BACKSLASH_CHARACTER:
backslash_character(c);
break;
}
}
main()
{
int c;
while ((c = getchar()) != EOF)
process(c);
}
Έλεγχος μονάδων
Ασκήσεις
Η γλώσσα HTML
- Η HTML (Hypertext Markup Language) είναι η γλώσσα στην οποία γράφονται οι σελίδες στο World Wide Web.
Αποτελείται από κείμενο το οποίο εμφανίζεται στην οθόνη
του φυλλομετρητή (browser) και από
εντολές που περικλείονται μέσα σε < και >.
- Μερικές εντολές είναι οι παρακάτω:
- <p> Αλλαγή παραγράφου.
- <li> Αρχή νέας γραμμής σε λίστα
- <h1> Αρχή επικεφαλίδας επιπέδου 1
- <h2> Αρχή επικεφαλίδας επιπέδου 2
- Μπορείτε να δείτε το περιεχόμενο μιας σελίδας σε HTML με την
εντολή του φυλλομετρητή View - Source.
- Μπορείτε να φυλάξετε το περιεχόμενο μιας σελίδας στο δίσκο σας
σε μορφή HTML με την εντολή του φυλλομετρητή File - Save.
Εμφάνιση HTML
- Γράψτε ένα πρόγραμμα το οποίο τυπώνει στην οθόνη το
περιεχόμενο ενός αρχείου HTML με τον παρακάτω τρόπο:
- Όταν το κείμενο περνάει τη στήλη 60 να αλλάζει γραμμή
μετά το πρώτο τέλος λέξης.
- Οι υπόλοιπες αλλαγές σειράς μέσα στο αρχείο αγνοούνται.
- Η εντολή <p> να αρχίζει νέα σειρά
- Η εντολή <li> να αρχίζει νέα σειρά με τους χαρακτήρες "- "
- Η εντολή <h1> να τυπώνει σε νέα σειρά
τον αριθμό της επικεφαλίδας επιπέδου 1
και να τον αυξάνει κατά ένα.
Επιπλέον ξαναρχίζει την αρίθμηση των επικεφαλίδων επιπέδου 2 από
την αρχή.
- Η εντολή <h2> να τυπώνει σε νέα σειρά
τον αριθμό της επικεφαλίδας επιπέδου 1
ακολουθούμενο από "." και τον αριθμό της επικεφαλίδας επιπέδου 2 τον οποίο
και θα αυξάνει κατά ένα.
- Οι υπόλοιπες εντολές μέσα σε < > θα αγνοούνται.
- Οι εντολές μπορούν να δίνονται με κεφαλαία ή με μικρά γράμματα.
Έτσι για παράδειγμα οι εντολές <l> και <L> θα αντιμετωπίζονται
με τον ίδιο τρόπο.
- Δοκιμάστε το πρόγραμμά σας στο περιεχόμενο της σελίδας "παράδειγμα"
του κεφαλαίου αυτού των σημειώσεων.
- Σημείωση: Το πρόγραμμα δε χρειάζεται να εξετάζει αν οι εντολές με
τις οποίες ενεργεί περιέχουν μόνο τα συγκεκριμένα στοιχεία της εντολής.
Αφού συναντήσει την εντολή θα αγνοεί όλα τα υπόλοιπα στοιχεία της
μέχρι να συναντήσει >.
Έτσι για παράδειγμα οι εντολές <l> και <li> θα αντιμετωπίζονται
με τον ίδιο τρόπο.
Παράδειγμα εισόδου
<h1> Κύρια επικεφαλίδα</h1>
<h2> Επικεφαλίδα επιπέδου 2 </h2>
<p>
Κείμενο το οποίο
πρέπει
να εμφανίζεται στοιχισμένο μέχρι τη στήλη 60.
Οι
λέξεις
αυτές
δεν
πρέπει
να
εμφανίζονται
σε ξεχωριστές
γραμμές.
<p>
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη και πρέπει να σπάσει
<h2> Άλλη επικεφαλίδα επιπέδου 2 </h2>
<p>
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
<ul>
<li> Στοιχείο 1 <LI> Στοιχείο 2
<li> Στοιχείο 3
<li> Στοιχείο 4
</ul>
Παράδειγμα εξόδου
1. Κύρια επικεφαλίδα
1.1. Επικεφαλίδα επιπέδου 2
Κείμενο το οποίο πρέπει να εμφανίζεται στοιχισμένο μέχρι τη στήλη
60. Οι λέξεις αυτές δεν πρέπει να εμφανίζονται σε ξεχωριστές γραμμές.
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη
και πρέπει να σπάσει
1.2. Άλλη επικεφαλίδα επιπέδου 2
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
- Στοιχείο 1
- Στοιχείο 2
- Στοιχείο 3
- Στοιχείο 4
Βιβλιογραφία
- Alfred V. Aho, Ravi Sethi, and
Jeffrey D. Ullman.
Compilers,
Principles, Techniques, and Tools, chapter Lexical Analysis, pages
83-158.
Addison-Wesley, 1985.
- Joseph Arceneaux.
CUG392 --- GNU indent v1.8.
C Users Journal, 12(1):88, January 1994.
- T. Berners-Lee
and D. Connolly.
RFC 1866: Hypertext Markup
Language --- 2.0, November 1995.
- Roel Wieringa.
A survey of structured and object-oriented software specification methods and
techniques.
ACM Computing Surveys, 30(4):459-527, December 1998.
Παράδειγμα HTML
Επικεφαλίδα επιπέδου 2
Κείμενο το οποίο
πρέπει
να εμφανίζεται στοιχισμένο μέχρι τη στήλη 60.
Οι
λέξεις
αυτές
δεν
πρέπει
να
εμφανίζονται
σε ξεχωριστές
γραμμές.
Εδώ αλλάζουμε γραμμή, αλλά η γραμμή αυτή είναι πάρα πολύ μεγάλη και πρέπει να σπάσει
Άλλη επικεφαλίδα επιπέδου 2
Λίστα με στοιχεία (ένα σε κάθε γραμμή):
- Στοιχείο 1
- Στοιχείο 2
- Στοιχείο 3
- Στοιχείο 4
HTML example (english)
Heading level 2
Text that should appear wrapped at column 60.
These
words
should
not
be
spread
on
single
lines.
A new paragraph begins at this point, but this line is quite long and should be split.
Another heading level 2
Element list (one per line):
- Element 1
- Element 2
- Element 3
- Element 4
Πίνακες
Ορισμός και χρήση πινάκων
- Μπορούμε να ορίσουμε μια ομάδα μεταβλητών ίδιου τύπου στην
οποία θα έχουμε πρόσβαση με βάση το όνομά της και έναν
δείκτη (index) ως πίνακα (array).
- Ο ορισμός γίνεται ως εξής:
τύπος όνομα[αριθμός στοιχείων]
Παράδειγμα:
int values[10];
ορίζει έναν πίνακα 10 ακεραίων με όνομα values.
-
Πρόσβαση στα στοιχεία ενός πίνακα έχουμε με βάση το όνομα του
πίνακα και έναν ακέραιο δείκτη.
Ο δείκτης πρέπει να λαμβάνει τιμές από το 0 μέχρι τον αριθμό των στοιχείων - 1.
Το παρακάτω παράδειγμα διαβάζει 10 ακεραίους και τους τυπώνει με την
ανάποδη σειρά:
#include <stdio.h>
main()
{
int values[10];
int i;
for (i = 0; i < 10; i++)
scanf("%d", &values[i]);
for (i = 9; i > -1; i--)
printf("%d\n", values[i]);
}
Πίνακες πολλαπλών διαστάσεων
Πίνακες ως ορίσματα
- Για να ορίσουμε ότι μια παράμετρος συνάρτησης είναι πίνακας
γράφουμε τον ορισμό του πίνακα στις παραμέτρους της συνάρτησης.
Η πρώτη διάσταση του πίνακα μπορεί να παραληφθεί.
Παράδειγμα:
/*
* Return the sum of a vector v elements.
* The vector contains n elements.
*/
double
vector_sum(double v[], int n)
{
int i;
double sum = 0.0;
for (i = 0; i < n; i++)
sum = sum + v[i];
return (sum);
}
- Για να περάσουμε έναν πίνακα ως όρισμα σε μια συνάρτηση
γράφουμε απλώς το όνομά του στις παραμέτρους.
Παράδειγμα:
double v[100];
/* [...] */
printf("Sum = %g\n", vector_sum(v, 100));
- Όταν περνάει ένας πίνακας ως όρισμα σε συνάρτηση δεν περνάει ένα
αντίγραφο της τιμής του, όπως όταν περνάει μια απλή μεταβλητή,
αλλά μια αναφορά (reference) στον ίδιο τον
πίνακα.
Αλλαγές στα στοιχεία του πίνακα που γίνονται μέσα στη συνάρτηση
αναφέρονται στον πίνακα που πέρασε ως όρισμα.
Ο τρόπος αυτός κλήσης λέγεται
κλήση κατ' αναφορά (call by reference).
Παράδειγμα:
/*
* Set all n elements of vector v to the value d
*/
void
vector_setvalue(double v[], int n, double d)
{
int i;
for (i = 0; i < n; i++)
v[i] = d;
}
main()
{
double vals[50];
/* Zero vals */
vector_setvalue(vals, 50, 0.0);
}
Αρχικοποίηση πινάκων
- Μπορούμε να δώσουμε αρχικές τιμές στα στοιχεία ενός πίνακα
αν μετά τη δήλωσή του γράψουμε τις τιμές των στοιχείων
χωρισμένες με κόμματα μέσα σε άγκιστρα.
Παράδειγμα:
int days[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- Στην περίπτωση προσδιορισμού αρχικών τιμών μπορούμε να μην
προσδιορίσουμε το μέγεθος του πίνακα και να αφήσουμε τον
μεταγλωττιστή να το υπολογίσει αυτόματα με βάση τον αριθμό τιμών που
έχουν χρησιμοποιηθεί.
Παράδειγμα:
int days[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
- Αν κάποιες τιμές δεν προσδιοριστούν, τότε αυτές θα είναι μηδέν.
- Μπορούμε να προσδιορίσουμε τιμές για πίνακες πολλών διαστάσεων
περικλείοντας τιμές μέσα σε άγκιστρα μέσα σε άλλα άγκιστρα.
Παράδειγμα:
double unit_matrix[3][3] = {
{1.0, 0.0, 0.0},
{0.0, 1.0, 0.0},
{0.0, 0.0, 1.0}
};
Πρόσθετοι τύποι και μετατροπή μεταξύ τύπων
Ασκήσεις
Πίνακες
- Γράψτε ένα πρόγραμμα το οποίο διαβάζει χαρακτήρες από την
είσοδό του μέχρι το τέλος του αρχείου (EOF).
Στη συνέχεια τυπώνει ένα ραβδόγραμμα με αστεράκια για κάθε έναν από
τους εμφανιζόμενους χαρακτήρες.
Επιπλέον για τους χαρακτήρες που εμφανίζονται
στην είσοδο του προγράμματος τις μέγιστες και τις ελάχιστες φορές
εμφανίζει τον αντίστοιχο χαρακτήρα καθώς και τον αριθμό των
φορών που εμφανίστηκε.
Παράδειγμα εξόδου:
a ********
b ****
e ************
z *
Most frequent: e; 12 time(s).
Least frequent: z; 1 time(s).
Σημείωση: Αν η είσοδος του προγράμματος δεν περιέχει ελληνικούς χαρακτήρες,
τότε μπορείτε να φυλάξετε τη συχνότητα του κάθε χαρακτήρα σε έναν πίνακα
128 θέσεων με δείκτη τον ίδιο το χαρακτήρα.
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 157-160, 25, 61
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 110-112, 9, 37.
Prentice-Hall, second edition, 1988.
Οργάνωση δεδομένων: δομές, ενώσεις, απαριθμήσεις, τύποι
Δομή
- Μπορούμε να δηλώσουμε μια
δομή (structure) η οποία θα περιέχει στο εσωτερικό
της δεδομένα διαφορετικών τύπων ή σημασίας με τον ορισμό struct.
Η δήλωση της δομής γίνεται σύμφωνα με την παρακάτω σύνταξη:
struct ετικέτα δομής {
δήλωση μεταβλητής1;
δήλωση μεταβλητής2;
...
};
Το παρακάτω παράδειγμα δηλώνει ένα σημείο το οποίο αποτελείται από
δύο ακέραιες τιμές x και y:
struct s_point {
int x;
int y;
};
Αντίστοιχα το παρακάτω παράδειγμα δηλώνει μια δομή που περιέχει
τα στοιχεία ενός φοιτητή για ένα μάθημα:
struct s_student {
char name[50];
int grade;
};
- Μετά τη δήλωση της δομής η δεσμευμένη λέξη struct ακολουθούμενη
από την
ετικέτα δομής (structure tag) αποτελεί
νέο τύπο.
- Έχοντας δηλώσει την αντίστοιχη δομή μπορούμε να ορίσουμε μεταβλητές
με βάση τη δομή αυτή.
Το παρακάτω παράδειγμα ορίζει μια μεταβλητή p τύπου struct s_point.
struct s_point p;
- Πρόσβαση στα στοιχεία μιας μεταβλητής τύπου struct έχουμε με τη σύνταξη
μεταβλητή.στοιχείο.
Παράδειγμα:
printf("p=(%d, %d)\n", p.x, p.y);
- Μπορούμε να ορίσουμε μεταβλητές με βάση μια δομή
συνδυάζοντας τη δήλωση της δομής με τον ορισμό των μεταβλητών.
Στην περίπτωση αυτή μπορούμε να παραλείψουμε και το όνομα της ετικέτας.
Παράδειγμα:
struct {
int x, y;
} p1, p2;
p1.x = 4;
p1.y = 5;
- Μπορούμε να αντιγράψουμε τα στοιχεία μιας δομής σε μια άλλη ίδια
με τη χρήση του =.
Παράδειγμα:
struct {
int x, y;
} p1, p2;
p1.x = 4;
p1.y = 5;
p2 = p1;
- Ακόμα, μπορούμε να περάσουμε δομές σαν παραμέτρους σε συναρτήσεις
και να ορίσουμε ότι το αποτέλεσμα μιας συνάρτησης είναι μια δομή.
Παράδειγμα (επιστρέφει ένα σημείο ανάμεσα σε δύο άλλα):
struct s_point {
int x, y;
};
struct s_point
middle(struct s_point a, struct s_point b)
{
struct s_point c;
c.x = (a.x + b.x) / 2;
c.y = (a.y + b.y) / 2;
return (c);
}
- Μπορούμε να εκχωρήσουμε αρχικές τιμές σε μια ένωση ακολουθώντας
τον ορισμό της από = και τις αντίστοιχες τιμές για τα μέλη της
μέσα σε άγκιστρα.
Παράδειγμα:
struct s_point origin = {0, 0};
Ένωση
- Μπορούμε να δηλώσουμε μια
ένωση (union) η οποία θα περιέχει
εναλλακτικά στο εσωτερικό
της δεδομένα διαφορετικών τύπων ή σημασίας με τον ορισμό union.
Η δήλωση της ένωσης γίνεται σύμφωνα με την παρακάτω σύνταξη:
union ετικέτα ένωσης {
δήλωση μεταβλητής1;
δήλωση μεταβλητής2;
...
};
Το παρακάτω παράδειγμα δηλώνει μια ένωση η οποία μπορεί να
περιέχει έναν ακέραιο ή έναν αριθμό κινητής υποδιαστολής:
union u_value {
int i;
double d;
};
- Έχοντας δηλώσει την αντίστοιχη ένωση μπορούμε να ορίσουμε μεταβλητές
με βάση την ένωση αυτή.
Το παρακάτω παράδειγμα ορίζει μια μεταβλητή v τύπου union u_value.
union u_value v;
- Πρόσβαση στα στοιχεία μιας μεταβλητής τύπου union έχουμε με τη σύνταξη
μεταβλητή.στοιχείο.
Παράδειγμα:
printf("v=%d\n", u.i);
- Προσοχή: όταν αποθηκεύσουμε ένα στοιχείο σε μια ένωση οι τιμές
των άλλων στοιχείων παύουν να είναι έγκυρες.
- Αρχική τιμή μπορούμε να δώσουμε μόνο στο πρώτο στοιχείο της ένωσης.
- Συχνά, για να ξέρουμε το είδος της τιμής που αποθηκεύει μια ένωση
ορίζουμε μια δομή που περιέχει:
- μια απαρίθμηση (ορισμό και πεδίο) με τους τύπους των τιμών και
- μια ένωση (ορισμό και πεδίο) με τις τιμές.
Παράδειγμα:
struct s_value {
enum {
T_INT,
T_DOUBLE,
T_CHAR
} type; /* Value type */
union {
int i;
double d;
char c;
} v; /* Actual value */
};
/*
* Read an integer and return a proper struct s_value
*/
struct s_value
read_int(void)
{
struct s_value a;
a.type = T_INT;
scanf("%d", &a.v.i);
return (a);
}
/*
* Read a double and return a proper struct s_value
*/
struct s_value
read_double(void)
{
struct s_value a;
a.type = T_DOUBLE;
scanf("%lg", &a.v.d);
return (a);
}
/*
* Read a character and return a proper struct s_value
*/
struct s_value
read_char(void)
{
struct s_value a;
a.type = T_CHAR;
a.v.c = getchar();
return (a);
}
/*
* Print a struct s_value
*/
void
print_value(struct s_value a)
{
switch (a.type) {
case T_INT:
printf("%d", a.v.i);
break;
case T_DOUBLE:
printf("%lg", a.v.d);
break;
case T_CHAR:
putchar(a.v.c);
break;
default: /* Defensive programming */
printf("Bad value type %d\n", a.type);
break;
}
}
Απαρίθμησης
- Μπορούμε να ορίσουμε δικές μας ομάδες σταθερών ακέραιου τύπου
με τον ορισμό σταθερών απαρίθμησης (enumeration).
Αυτός γίνεται με την παρακάτω σύνταξη:
enum ετικέτα_απαρίθμησης {
όνομα σταθεράς 1,
όνομα σταθεράς 2,
...
};
Παράδειγμα:
enum states {
COMMENT,
STRING,
CODE
};
- Οι σταθερές της περιοχής λαμβάνουν τιμές αρχίζοντας από το 0.
Κάθε επόμενη σταθερά έχει τιμή 1 παραπάνω από την προηγούμενη.
- Μπορούμε να ορίσουμε συγκεκριμένη τιμή για μια σταθερά με
τη χρήση της σύνταξης: όνομα = ακέραια τιμή.
Παράδειγμα:
enum escapes {
NEWLINE = '\n',
BELL = '\a',
TAB = '\t'
};
-
Με βάση τον ορισμό μιας απαρίθμησης μπορούμε να ορίσουμε μεταβλητές του τύπου
αυτού και να τους αναθέσουμε αντίστοιχες τιμές:
enum state s;
enum escapes c;
s = CODE;
c = NEWLINE;
- Οι τιμές της απαρίθμησης καθώς και οι αντίστοιχες μεταβλητές
είναι συμβατές με τιμές και μεταβλητές τύπου int.
Ορισμός τύπων με την typedef
- Μπορούμε να ορίσουμε ένα νέο όνομα για κάποιον υπάρχοντα
τύπο με τη χρήση της εντολής typedef.
Η σύνταξη της typedef είναι είναι ανάλογη με τον ορισμό μιας
μεταβλητής:
typedef τύπος όνομα;
Παράδειγμα:
typedef int age;
typedef struct {
int date; /* 1-31 */
int month; /* 1-12 */
int year; /* FOUR DIGIT */
} date;
typedef double vector[3];
typedef double matrix[4][3];
- Μετά τον ορισμό αυτό μπορούμε να χρησιμοποιούμε το νέο όνομα
οπουδήποτε θα χρησιμοποιούσαμε τον αντίστοιχο τύπο.
Παράδειγμα:
void
print_date(date d)
{
printf("%d/%d/%d", d.date, d.month, d.year);
}
- Μπορούμε να χρησιμοποιήσουμε την typedef για να κάνουμε τα
προγράμματά μας πιο κατανοητά και φορητά ανάμεσα σε διαφορετικές
αρχιτεκτονικές υπολογιστών.
Ασκήσεις
Δομές
- Να γραφεί πρόγραμμα σε C το οποίο να υλοποιεί αριθμομηχανή
μιγαδικών αριθμών σύμφωνα με τις παρακάτω προδιαγραφές:
- Το πρόγραμμα διαβάζει από το
χρήστη
ένα ζεύγος αριθμών Α, B,
το σύμβολο μιας από τις τέσσερεις πράξεις Σ,
ένα ακόμα ζεύγος αριθμών Γ, Δ,
και τυπώνει το αποτέλεσμα (Α + Bi) Σ (Γ + Δi).
- Όταν το αποτέλεσμα είναι (0 + 0i) το πρόγραμμα να τερματίζει τη
λειτουργία του.
Οι μιγαδικοί αριθμοί να οριστούν με τη χρήση δομών.
Καλό είναι κάθε πράξη να υλοποιείται από ξεχωριστή συνάρτηση.
Παράδειγμα:
Enter number a:5 3
Enter operator:+
Enter number b:1 2
Result=6 + 5i
Enter number a:1 1
Enter operator:*
Enter number b:1.5 2
Result=-0.5 + 3.5i
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 179-187, 204-206.
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 127-133, 147.
Prentice-Hall, second edition, 1988.
Δείκτες και δυναμικές δομές δεδομένων
Διάταξη των δεδομένων και του κώδικα στη μνήμη
- Στους υπολογιστές αρχιτεκτονικής von Neuman ο κώδικας του
προγράμματος αποθηκεύεται μαζί με τα αντίστοιχα δεδομένα στην
κεντρική μνήμη του υπολογιστή.
- Η μνήμη είναι συνήθως διατεταγμένη με τρόπο τέτοιο ώστε κάθε
στοιχείο της να μπορεί να οριστεί μονοσήμαντα από ένα συγκεκριμένο
αριθμό.
Ο αριθμός αυτός καλείται διεύθυνση (address) του
στοιχείου.
- Όλα τα στοιχεία ενός προγράμματος που καταλαμβάνουν χώρο στη
μνήμη (μεταβλητές όλων των τύπων και συναρτήσεις) έχουν μια
συγκεκριμένη διεύθυνση.
- Επιπλέον το λειτουργικό σύστημα μας επιτρέπει να ζητήσουμε
να διατεθεί στο πρόγραμμά μας, κατά την ώρα της εκτέλεσής του,
πρόσθετη μνήμη.
- Ο τύπος που μας επιτρέπει να ορίσουμε μεταβλητές
που να περιέχουν διευθύνσεις μνήμης καλείται
δείκτης (pointer).
Δήλωση δεικτών
- Ο ορισμός ενός δείκτη γίνεται με τη σύνταξη:
τύπος *
- Έτσι για παράδειγμα ο τύπος int * ορίζει έναν δείκτη σε
ακέραιους.
- Το παρακάτω παράδειγμα δηλώνει μια μεταβλητή iptr που είναι δείκτης
σε ακέραιους.
int *iptr;
Ο τελεστής &
Χρήση δεικτών
Κλήση κατ' αναφορά
- Με το συνδυασμό των τελεστών & και * μπορούμε να ορίσουμε συναρτήσεις
που να αλλάζουν την τιμή μεταβλητών που περνάν σε αυτές ως δείκτες.
- Στο παρακάτω παράδειγμα η συνάρτηση int_swap αλλάζει μεταξύ τους
τις τιμές των δύο δεικτών σε ακέραιους που είναι οι παράμετροί της.
Το παρακάτω παράδειγμα τυπώνει 2, 1:
void
int_swap(int *i1, int *i2)
{
int tmp;
tmp = *i1;
*i1 = *i2;
*i2 = tmp;
}
main()
{
int a, b;
a = 1;
b = 2;
int_swap(&a, &b);
printf("%d, %d\n", a, b);
}
- Ο τρόπος αυτός κλήσης ονομάζεται κλήση κατ' αναφορά.
Σε ορισμένες γλώσσες προγραμματισμού υποστηρίζεται κατευθείαν από
τη γλώσσα χωρίς τη χρήση ειδικών τελεστών.
Αριθμητική με δείκτες
Ο τελεστής sizeof
- Ο τελεστής sizeof επιστρέφει το μέγεθος της μεταβλητής ή του
τύπου στον οποίο εφαρμόζεται.
Το μέγεθος αυτό εκφράζεται σε bytes.
- Παράδειγμα (τυπώνει 1, 2, 4, 4, 40, 1 σε υπολογιστές Pentium):
main()
{
char c;
short s;
int i;
double d;
int a[10];
printf("%d\n", sizeof(c));
printf("%d\n", sizeof(s));
printf("%d\n", sizeof(i));
printf("%d\n", sizeof(d));
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(char));
}
- Με τη χρήση της sizeof μπορούμε να γράψουμε κώδικα ο οποίος να
μην εξαρτάται από το μέγεθος ενός πίνακα ή ενός τύπου.
Παράδειγμα (μηδενίζει τον πίνακα a):
int a[10];
int *iptr;
for (iptr = a; iptr < a + sizeof(a) / sizeof(int); iptr++)
*iptr = 0;
Δυναμική διάθεση μνήμης
-
Η συνάρτηση malloc() μας επιτρέπει να
ζητήσουμε έναν ελεύθερο χώρο μνήμης για να χρησιμοποιήσουμε στο πρόγραμμά μας.
- Η malloc έχει ως όρισμα το μέγεθος της μνήμης που απαιτούμε
και επιστρέφει ένα δείκτη στην αρχή του αντίστοιχου χώρου.
Ο τύπος της τιμής που επιστρέφει δεν είναι αντίστοιχος
με τον τύπο που χρειαζόμαστε και γι' αυτό πρέπει να χρησιμοποιήσουμε
την αντίστοιχη μετατροπή (π.χ. (double *)malloc...).
- Σε περίπτωση που το σύστημα δεν έχει άλλη διαθέσιμη μνήμη
η malloc επιστρέφει τη σταθερά NULL.
Παράδειγμα:
char *c;
c = (char *)malloc(1000 * sizeof(char));
if (c == NULL) {
printf("Out of memory!\n");
return (1);
}
- Με τη χρήση της malloc μπορούμε να δημιουργήσουμε δυναμικά
χώρο για πίνακες τους οποίους δηλώνουμε ως δείκτες.
- Το παρακάτω παράδειγμα ζητάει από το χρήστη να ορίσει το μέγεθος
ενός πίνακα και στη συνέχεια να δώσει τα στοιχεία του.
#include <stdlib.h>
#include <stdio.h>
main()
{
int *int_table; /* Table of integers */
int nelem; /* Number of elements */
int i;
printf("Enter number of elements:");
scanf("%d", &nelem);
int_table = (int *)malloc(nelem * sizeof(int));
for (i = 0; i < nelem; i++) {
printf("Element %d=", i);
scanf("%d", &int_table[i]);
}
}
- Η συνάρτηση free(δείκτης) ελευθερώνει το χώρο που έχει επιστραφεί
από τη malloc για ανακύκλωση.
- Η συνάρτηση realloc(δείκτης, νέο μέγεθος) λαμβάνει ως όρισμα
ένα δείκτη που έχει επιστραφεί από τη malloc και επιστρέφει έναν
δείκτη σε χώρο με το νέο μέγεθος που έχει προσδιοριστεί.
Παράδειγμα:
int *iptr;
iptr = (int *)malloc(10 * sizeof(int));
/* iptr[0] to iptr[9] can now be used */
iptr = (int *)realloc(iptr, 20 * sizeof(int));
/*
* iptr[0] to iptr[9] retain old values
* iptr[0] to iptr[19] can now be used */
*/
free(iptr);
/* Do not access iptr[0] to iptr[19] from this point onwards */
- Οι malloc, free, realloc, NULL ορίζονται στο αρχείο stdlib.h.
Φροντιστηριακές ασκήσεις
- Συμπληρώστε τον πίνακα με τις τιμές των
μεταβλητών μετά την εκτέλεση κάθε μιας από τις παρακάτω εντολές.
int a, b, c;
int *ip1, *ip2, *ip3;
a = 3;
b = 4;
ip1 = &a;
*ip1 = 8;
ip3 = &c;
ip2 = ip3;
b = *ip1;
*ip2 = *ip1;
| a | b | c | ip1 | ip2 | ip3 |
Αρχή | - | - | - | - | - | - |
a = 3 | 3 | - | - | - | - | - |
b = 4 | 3 | 4 | - | - | - | - |
ip1 = &a | 3 | 4 | - | &a | - | - |
*ip1 = 8 | | | | | | |
ip3 = &c | | | | | | |
ip2 = ip3 | | | | | | |
b = *ip1 | | | | | | |
*ip2 = *ip1 | | | | | | |
- Υπολογίστε τους τύπους των εκφράσεων δεξιά και αριστερά από κάθε ανάθεση
και γράψτε ποιες από τις παρακάτω γραμμές είναι σωστές και ποιες όχι.
int a, b, c, *p1, *p2, *p3;
double da, db, dc, *pd1, *pd2, *pd3;
p1 = &a;
*p1 = 4;
p2 = &p1;
*p2 = *c;
p3 = a;
p2 = p3;
pd1 = p2;
pd2 = &da;
dc = *pd3;
db = *p2;
&a = 43;
Ασκήσεις
Δυναμική χρήση της μνήμης
- Να σχεδιάσετε και να γράψετε ένα πρόγραμμα το οποίο τυπώνει
τους χαρακτήρες που διαβάζει με την ανάποδη σειρά.
Δεν πρέπει να υπάρχει περιορισμός από το πρόγραμμα στον αριθμό των χαρακτήρων
που να μπορεί να δεχτεί.
- Το παρακάτω πρόγραμμα προσθέτει διανύσματα ν διαστάσεων:
/*
* Add two vectors
*
* Diomidis Spinellis, December 1998
*/
#include <stdio.h>
/*
* Print the contents of vector v consisting of n elements
*/
void
vector_print(double v[], int n)
{
int i;
putchar('(');
for (i = 0; i < n; i++) {
printf("%g", v[i]);
if (i < n - 1)
printf(", ");
}
putchar(')');
}
/*
* Input a vector v consisting of n elements
*/
void
vector_input(double v[], int n)
{
int i;
for (i = 0; i < n; i++) {
printf("\tEnter element %d: ", i);
scanf("%lg", &v[i]);
}
}
/*
* Sum vector a and vector b to vector c
* All vectors consist of n elements
*/
void
vector_add(double a[], double b[], double c[], int n)
{
int i;
for (i = 0; i < n; i++)
c[i] = a[i] + b[i];
}
main()
{
int nelem;
double a[10], b[10], c[10];
printf("Enter number of vector elements: ");
scanf("%d", &nelem);
if (nelem > sizeof(a) / sizeof(double)) {
printf("Vector size too large. The maximum vector size is %d.\n",
sizeof(a) / sizeof(double));
return (1);
}
printf("Enter vector a\n");
vector_input(a, nelem);
printf("Enter vector b\n");
vector_input(b, nelem);
vector_add(a, b, c, nelem);
vector_print(a, nelem);
putchar('+');
vector_print(b, nelem);
putchar('=');
vector_print(c, nelem);
}
- Να το μεταγλωττίσετε και να το δοκιμάσετε στη μορφή που είναι.
- Να το αλλάξετε έτσι ώστε να μην έχει περιορισμό ως προς το
μέγεθος των διανυσμάτων που μπορεί να δεχτεί.
- Να το αλλάξετε έτσι ώστε να μην εμφανίζονται καθόλου σε αυτό οι
χαρακτήρες [ και ] (χρησιμοποιήστε δείκτες αντί για πίνακες).
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 135-178 (τμήματα)
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 93-126 (parts).
Prentice-Hall, second edition, 1988.
Προσδιορισμός απαιτήσεων, ανάλυση και σχεδίαση
Απαιτήσεις
Ο προσδιορισμός των απαιτήσεων διαχωρίζεται
- στον προσδιορισμό των απαιτήσεων από το σύστημα και
- στον προσδιορισμό των απαιτήσεων από το λογισμικό.
Το έγγραφο προδιαγραφών απαιτήσεων από το σύστημα (system requirements document)
περιέχει τα παρακάτω στοιχεία (Σκορδαλάκης 1991, σ. 54):
- Ορισμός του προβλήματος
- Αιτιολόγηση του προβλήματος
- Σκοπός του συστήματος και του έργου
- Σκοπός του συστήματος και του έργου
- Περιορισμοί στο σύστημα και στο έργο
- Λειτουργίες ανά συνιστώσα του προβλήματος
- Υλικό
- Λογισμικό
- Άνθρωποι
- Χαρακτηριστικά χρηστών
- Περιβάλλοντα
- ανάπτυξης,
- λειτουργίας και
- συντήρησης
- Στρατηγική λύσης του προβλήματος
- Προτεραιότητες στα χαρακτηριστικά του συστήματος
- Κριτήρια αποδοχής του συστήματος
- Πηγές πληροφοριών
- Λεξιλόγιο
Αντίστοιχα το έγγραφο προδιαγραφών απαιτήσεων από το λογισμικό (software requirements document)
περιέχει τα παρακάτω στοιχεία (Σκορδαλάκης 1991, σ. 63):
- Εισαγωγή
- Σκοπός
- Έκταση
- Ορισμοί, ακρονυμίες και συντομογραφίες
- Αναφορές
- Γενική εικόνα
- Γενική περιγραφή
- Προοπτική του προϊόντος
- Λειτουργίες
- Χαρακτηριστικά των χρηστών
- Γενικοί περιορισμοί
- Παραδοχές και εξαρτήσεις
- Ειδικές απαιτήσεις
- Λειτουργικές απαιτήσεις
- Λειτουργική απαίτηση 1
- Εισαγωγή
- Είσοδοι
- Επεξεργασία
- Έξοδοι
- Λειτουργική απαίτηση 1
- ...
- Λειτουργική απαίτηση ν
- Απαιτήσεις εξωτερικών διαπροσωπειών
- Διαπροσωπείες χρήστη (user interfaces)
- Διαπροσωπείες υλικού (hardware interfaces)
- Διαπροσωπείες λογισμικού (software interfaces)
- Διαπροσωπείες επικοινωνιών (communication interfaces)
- Απαιτήσεις επίδοσης
- Περιορισμοί σχεδίασης
- Συμμόρφωση με τα πρότυπα
- Περιορισμοί από το υλικό
- Ιδιώματα
- Διαθεσιμότητα
- Ασφάλεια
- Συντηρισιμότητα
- Μεταφερσιμότητα
- Άλλες απαιτήσεις
- Βάση δεδομένων
- Τρόποι λειτουργίας
- Προσαρμογή στο χώρο εγκατάστασης
- Παραρτήματα
- Ευρετήριο
Ανάλυση
Για την κατανόηση, τον προσδιορισμό και την έκφραση των απαιτήσεων από το
λογισμικό είναι απαραίτητο ένα
ιδεατό μοντέλο (conceptual model) των διεργασιών
του συστήματος στο οποίο θα λειτουργήσει το λογισμικό.
Τα μοντέλα αυτά χρησιμοποιούν τις παρακάτω τεχνικές
παράστασης:
- Ροή δεδομένων (data flow)
- Μηχανή πεπερασμένων καταστάσεων (finite state machine)
- επικοινωνούσες ταυτόχρονες διεργασίες (communicating concurrent processes)
- Μοντέλο οντοτήτων σχέσεων (entity relationship models)
- Εξομοίωση (simulation)
- Λειτουργική σύνθεση (functional composition)
Η δομημένη ανάλυση (structured analysis)
χρησιμοποιεί ως βάση το μοντέλο ροής δεδομένων και
μια σειρά από
εξειδικευμένους συμβολισμούς για την καταγραφή των
απαιτήσεων:
Εκτός από τη δομημένη ανάλυση η οποία ταιριάζει με το διαδικασιακό παράδειγμα
προγραμματισμού όπως υποστηρίζεται από τις γλώσσες C, Pascal, Fortran κλπ,
στις μέρες μας χρησιμοποιείται συχνά και η
αντικειμενοστρεφής ανάλυση (object oriented analysis)
σε συνδυασμό με αντικειμενοστρεφείς γλώσσες όπως η C++, Java, Eiffel, Smalltalk
κλπ.
Διάγραμμα ροής δεδομένων
Το διάγραμμα ροής δεδομένων χρησιμοποιεί τους συμβολισμούς
που παριστάνονται στο σχήμα που ακολουθεί
για να παραστήσει τη λογική ροή των δεδομένων μέσα στο σύστημα.
Έτσι, το επόμενο σχήμα παριστάνει το διάγραμμα ροής δεδομένων για έναν
απλό ελεγκτή ορθογραφίας.
Το κείμενο αρχικά χωρίζεται σε λέξεις (split words)
οι οποίες ταξινομούνται (sort).
Στη συνέχεια απαλείφονται οι πολλαπλές εμφανίσεις λέξεων (unique).
Το λεξικό του συστήματος ενώνεται με το λεξικό του χρήστη (merge).
Τέλος, εμφανίζονται οι λέξεις που υπάρχουν στο κείμενο αλλά όχι στα
ενωμένα λεξικά (not common).
Λεξικό δεδομένων
Κατά τη δημιουργία ενός μοντέλου θα ονομαστεί τυπικά ένας μεγάλος
αριθμός από οντότητες, τύπους, σχέσεις και ιδιότητες.
Το λεξικό δεδομένων περιέχει όλα τα παραπάνω ονόματα, μαζί με τον τύπο και
μια επεξήγηση του κάθε ονόματος.
Ο παρακάτω πίνακας περιέχει ένα παράδειγμα από λεξικό δεδομένων
για μια υποθετική εφαρμογή τράπεζας.
Όνομα | Τύπος | Περιγραφή |
Πελάτης | Δομή | Η εγγραφή με τα στοιχεία ενός πελάτη.
Περιέχει όνομα, κωδικό λογαριασμού και υπόλοιπο λογαριασμού. |
Κωδικός λογαριασμού | INT(20) | Ο μοναδικός κωδικός του λογαριασμού |
Όνομα | CHAR(30) | Το ονοματεπώνυμο ενός πελάτη |
Υπόλοιπο λογαριασμού | INT(12) | Το καθαρό υπόλοιπο του λογαριασμού σε δρχ. |
Δομικές μονάδες
Σύνθετες κατασκευές, όπως το λογισμικό, απαιτούν τη δημιουργία ενός
σχεδίου πριν αρχίσει η πραγματική υλοποίηση.
Το σχέδιο αυτό βοηθά στην ελαχιστοποίηση των διορθώσεων και των
αλλαγών κατά τη διάρκεια της κωδικοποίησης.
Ο σχεδιασμός του λογισμικού βασίζεται στη δόμησή του σε μακροσκοπικό
(σύστημα, υποσυστήματα, προγράμματα) και σε μικροσκοπικό (σύνθετες
δομικές μονάδες, απλές δομικές μονάδες) επίπεδο.
Έτσι για παράδειγμα το λειτουργικό σύστημα Windows NT μακροσκοπικά
χωρίζεται σε συστήματα επικοινωνίας με το χρήστη, επικοινωνίας με το
υλικό, βοηθητικά προγράμματα, κλπ.
Το σύστημα επικοινωνίας με το χρήστη χωρίζεται στα υποσυστήματα
γραφικών, κειμένου, ήχου, ελεγκτών (controls) κλπ.
Μικροσκοπικά,
οι σύνθετες δομικές μονάδες του υποσυστήματος ελεγκτών μπορεί να
είναι ο ελεγκτής για γραφικό πλήκτρο (button),
ελεγκτής πεδίο εισόδου (input box), ελεγκτής για κυλιόμενη μπάρα
(scrollbar) κλπ.
Τέλος, ο ελεγκτής για την κυλιόμενη μπάρα αποτελείται από απλές
δομικές μονάδες (συναρτήσεις) που αντιδρούν στις εντολές του χρήστη.
Μερικά παραδείγματα σύνθετων δομικών μονάδων είναι τα παρακάτω:
Σχεδίαση
Η σχεδίαση ενός συστήματος ξεκινά από το αρχιτεκτονικό σχέδιο το
οποίο παριστάνει τη μακροσκοπική δομή του λογισμικού.
Σε επόμενο στάδιο ακολουθεί η λεπτομερής σχεδίαση η οποία
παριστάνει τη μικροσκοπική δομή του λογισμικού.
Ορισμένες κατηγορίες σχεδίασης που χρησιμοποιούνται ευρέως είναι
οι παρακάτω:
Η σχεδίαση βασίζεται πάνω στα αποτελέσματα της ανάλυσης των
απαιτήσεων του συστήματος.
Για την αποτύπωση του αρχιτεκτονικού σχεδίου της δομής του
προγράμματος χρησιμοποιείται συχνά
το διάγραμμα δομής προγράμματος (program structure chart).
Στο διάγραμμα αυτό κάθε δομική μονάδα παριστάνεται από έναν κόμβο και
κάθε κλήση από μια δομική μονάδα σε άλλη από ένα βέλος.
Παράλληλα με τα βέλη της κλήσης παριστάνεται με πρόσθετα βέλη
τα οποία περιγράφουν την είσοδο ή το αποτέλεσμα μιας δομικής
μονάδας και η ροή των δεδομένων μεταξύ δομικών μονάδων.
Το παρακάτω σχήμα αποτελεί το διάγραμμα δομής προγράμματος για
έναν απλό υπολογιστή μιγαδικών αριθμών.
Για την αποτύπωση του λεπτομερούς σχεδίου του λογισμικού χρησιμοποιείται
ο ψευδοκώδικας (pseudocode) καθώς και τα
διαγράμματα ροής (flow charts).
Ο ψευδοκώδικας αποτελείται από εντολές ελέγχου της ροής της εκτέλεσης
αντίστοιχες με αυτές των γλωσσών προγραμματισμού (if, while, do).
Η περιγραφές όμως των συνθηκών και των εντολών δίνονται αδρά,
σε φυσική γλώσσα, έτσι ώστε να είναι πιο περιεκτικές και ευνόητες
από τις αντίστοιχες εντολές της γλώσσας προγραμματισμού.
Παράδειγμα ψευδοκώδικα ελέγχου κωδικού (PIN) σε μηχάνημα ATM:
do
Display message asking the user for PIN
Read user PIN
if incorrect PIN
Display error message
while incorrect PIN
Ασκήσεις
- Επιλέξτε ένα σύνθετο σύστημα λογισμικού της αρεσκείας σας και
αποτυπώστε με τους κατάλληλους συμβολισμούς
την ανάλυση,
το μακροσκοπικό σχέδιο και ένα μικρό αντιπροσωπευτικό τμήμα
από το λεπτομερή σχεδιασμό.
Βιβλιογραφία
- Peter Rechenberg.
Εισαγωγή στην Πληροφορική. σ. 155-162
Κλειδάριθμος, 1992.
- Εμμανουήλ Σκορδαλάκης.
Εισαγωγή στην Τεχνολογία Λογισμικού.
Συμμετρία, 1991.
- Εμμ. Α. Γιακουμάκης
Τεχνολογία Λογισμικού: Απαιτήσεις Λογισμικού, σχεδίαη λογισμικού
Εκδόσεις Α. Σταμούλης, Αθήνα Πειραιάς 1994.
- Εμμ. Α. Γιακουμάκης
Τεχνολογία Λογισμικού: Κωδικοποίηση, έλεγχος και συντήρηση λογισμικού
Εκδόσεις Α. Σταμούλης, Αθήνα Πειραιάς 1993.
- F. P. Brooks.
The
Mythical Man Month.
Addison-Wesley, 1975.
- Alan M. Davis.
201
Principles of Software Development.
McGraw-Hill, 1995.
- Tom DeMarco and
Timothy R. Lister.
Peopleware: Productive Projects and Teams.
Dorset House Publishing, 1987.
- Jr. Frederick
P. Brooks.
No silver bullet: Essence and accidents of software engineering.
IEEE Computer, pages 10–19, April 1987.
- P. J. Plauger.
Programming on Purpose: Essays on Software Design.
Prentice-Hall, 1993.
- P. J. Plauger.
Programming on Purpose II: Essays on Software People.
Prentice-Hall, 1993.
- P. J. Plauger.
Programming on Purpose III: Essays on Software Technology.
Prentice-Hall, 1994.
- Roger S. Pressman.
Software Engineering: A Practitioner's Approach.
McGraw-Hill, 1987.
- Charles H. Schmauch.
ISO
9000 for Software Developers.
ASQC Quality Press, Milwaukee, Wisconsin, USA, 1995.
- Ian Sommerville.
Software Engineering.
Addison-Wesley, third edition, 1989.
- Roel Wieringa.
A survey of structured and object-oriented software specification methods and
techniques.
ACM Computing Surveys, 30(4):459–527, December 1998.
- Edward Yourdon.
Death
March.
Prentice-Hall, 1997.
Οργάνωση προγραμμάτων: σχεδιασμός σε τμήματα αφηρημένοι τύποι δεδομένων
Χωρισμός του προγράμματος σε αρχεία
- Μεγαλύτερα προγράμματα οργανώνονται καλύτερα σε πολλαπλά αρχεία.
Η οργάνωση αυτή διευκολύνει την ομαδική εργασία, τον έλεγχο των
τμημάτων του έργου και τη συντήρηση.
Σε πραγματικά μεγάλα συστήματα ο χωρισμός ενός προγράμματος σε πολλά
αρχεία επιδρά θετικά και στο χρόνο που απαιτείται για τη μεταγλώττιση.
- Για να χωρίσουμε ένα πρόγραμμα σε πολλά αρχεία απλώς χωρίζουμε
τις συναρτήσεις και τις καθολικές μεταβλητές σε λογικές ομάδες
και γράφουμε τις συναρτήσεις και μεταβλητές κάθε ομάδας σε ένα ξεχωριστό αρχείο.
- Κάθε καθολική συνάρτηση ή μεταβλητή πρέπει να εμφανίζεται σε ένα και μόνο
ένα αρχείο.
- Κάθε αρχείο μεταγλωττίζεται ξεχωριστά και έτσι πρέπει να έχει τα
δικά του #include στην αρχή.
- Ο τρόπος που χρησιμοποιούμε καθολικές μεταβλητές και συναρτήσεις
που έχουν οριστεί σε ένα αρχείο, σε άλλο αναλύεται στις επόμενες
ενότητες.
Ξεχωριστή μεταγλώττιση
Δήλωση και χρήση καθολικών μεταβλητών
Δήλωση και χρήση συναρτήσεων
- Οι καθολικές συναρτήσεις που ορίζονται σε ένα αρχείο μπορούν
να χρησιμοποιηθούν σε οποιοδήποτε άλλο.
- Για να μπορέσουν να χρησιμοποιηθούν πρέπει να δηλωθούν
με την εντολή extern.
- Η δήλωση μιας συνάρτησης με extern στο αρχείο που
θέλουμε να τη χρησιμοποιήσουμε πρέπει να είναι ακριβώς
ίδια με αυτή που έχει οριστεί στο αρχείο ορισμού.
Παράδειγμα:
/*
* Definition file:
*/
int
fun(int a, double b[3], char *cp)
{
...
}
/*
* Other file
*/
extern int fun(int a, double b[3], char *cp);
void
fun2(void)
{
char c;
double q[3];
fun(1, q, &c);
}
Χρήση αρχείων επικεφαλίδων
Περιορισμός της εμβέλειας
Αφηρημένοι τύποι
- Η δυνατότητα χωρισμού ενός προγράμματος σε ανεξάρτητες λειτουργικές
μονάδες επιτρέπει τον ορισμό αφηρημένων οντοτήτων στις οποίες η
πρόσβαση γίνεται μόνο μέσω συναρτήσεων και με συγκεκριμένο τρόπο.
- Η χρήση των οντοτήτων αυτών γίνεται μόνο μέσω των συναρτήσεων και
των τύπων που ορίζονται σε αντίστοιχο αρχείο επικεφαλίδων,
ενώ η υλοποίηση γίνεται σε ξεχωριστό αρχείο C.
Ο τρόπος αυτός προγραμματισμού ξεχωρίζει την υλοποίηση από τους μηχανισμούς
πρόσβασης επιτρέποντάς μας να αλλάξουμε την υλοποίηση χωρίς να επηρεαστεί
το υπόλοιπο πρόγραμμα.
- Το παρακάτω παράδειγμα ορίζει έναν μετρητή ο οποίος μπορεί
μόνο να αυξάνεται:
/*
* Header file
*/
extern int get_counter(void);
extern void inc_counter(void);
/*
* C file
*/
static int counter;
int
get_counter(void)
{
return (counter);
}
void
inc_counter(void)
{
counter++;
}
- Το παραπάνω παράδειγμα δημιουργεί έναν μόνο μετρητή.
Με τη χρήση δεικτών και δυναμικής μνήμης μπορούμε να ορίσουμε ένα
εργοστάσιο που να δημιουργεί απεριόριστο αριθμό από μετρητές.
Ο αφηρημένος τύπος του μετρητή παριστάνεται ως ένας δείκτης σε
ακέραιο:
/*
* Header file
*/
typedef int *counter;
extern counter new_counter(void);
extern int get_counter(counter c);
extern void inc_counter(counter c);
/*
* C file
*/
/*
* Return a new counter object
*/
counter
new_counter(void)
{
counter c;
c = (counter)malloc(sizeof(int));
*c = 0;
return (c);
}
int
get_counter(counter c)
{
return (*c);
}
void
inc_counter(counter c)
{
(*c)++;
}
- Με τη χρήση των παραπάνω αρχείων μπορούμε να προγραμματίσουμε
με δύο λ.χ. μετρητές:
#include <stdio.h>
#include "counter.h"
main()
{
counter c1, c2;
c1 = new_counter();
c2 = new_counter();
inc_counter(c1);
inc_counter(c1);
inc_counter(c2);
printf("%d %d\n", get_counter(c1), get_counter(c2));
}
- Το παραπάνω παράδειγμα επιτρέπει σε κάποιον να διαβάσει στο
αρχείο των επικεφαλίδων ότι ο αφηρημένος τύπος είναι ένας δείκτης
σε ακέραιο και να τον μεταβάλει με λάθος τρόπο (πχ *c = 12;).
Μπορούμε να διασφαλίσουμε τον αφηρημένο τύπο από τέτοιου είδους
προσβάσεις ορίζοντας μια δομή στο αρχείο υλοποίησης
και μόνο έναν δείκτη στη δομή αυτή στο αρχείο επικεφαλίδων
(η γραφή structptr->member είναι συντομογραφία της (*structptr).member):
/*
* Header file
*/
typedef struct s_counter *counter;
extern counter new_counter(void);
extern int get_counter(counter c);
extern void inc_counter(counter c);
/*
* C file
*/
struct s_counter {
int value;
};
/*
* Return a new counter object
*/
counter
new_counter(void)
{
counter c;
c = (counter)malloc(sizeof(struct s_counter));
c->value = 0;
return (c);
}
int
get_counter(counter c)
{
return (c->value);
}
void
inc_counter(counter c)
{
c->value++;
}
- Είναι αξιοσημείωτο ότι η παραπάνω (διαφορετική) υλοποίηση συνεχίζει
να είναι συμβατή με το πρόγραμμα το οποίο χρησιμοποιεί τους δύο δείκτες.
Ασκήσεις
Υλοποίηση σε τμήματα - έλεγχος
- Να γράψετε μια συνάρτηση void hangman(int n) η οποία θα
σχεδιάζει στην οθόνη μια κρεμάλα με έναν κρεμασμένο άνθρωπο
όπως τον παρακάτω:
++----
| O
| /|\
| / \
(Επιτρέπεται να βελτιώσετε το παραπάνω σχέδιο).
Ανάλογα με την τιμή του n (0-6) θα εμφανίζεται και αντίστοιχος αριθμός
από τα μέλη του ανθρώπου.
n = 0
++----
|
|
|
n = 1
++----
| O
|
|
...
n = 6
++----
| O
| /|\
| / \
Προσπαθήστε η συνάρτησή σας να μην περιέχει επαναλαμβανόμενο κώδικα.
- Ολοκληρώστε το πρόγραμμά σας προσθέτοντας τη συνάρτηση main με
εντολές κατάλληλες για να ελέγξετε τη σωστή λειτουργία της συνάρτησης
hangman.
- Γράψτε (σε ξεχωριστό αρχείο C) πρόγραμμα το οποίο υλοποιεί το
παιγνίδι "κρεμάλα" μεταξύ δύο παικτών.
Συγκεκριμένα το πρόγραμμα διαβάζει από
ένα χρήστη μια λέξη μέχρι 20 χαρακτήρες.
Στη συνέχεια επαναλαμβάνει τα παρακάτω:
- καθαρίζει την οθόνη (τυπώνοντας 24 \n),
- ζωγραφίζει μια (αρχικά) άδεια κρεμάλα
χρησιμοποιώντας τη συνάρτηση που έχετε ορίσει,
- τυπώνει τόσα αστεράκια (αρχικά) όσα και τα γράμματα της λέξης που έχει δώσει ο πρώτος
χρήστης,
- ζητάει από έναν δεύτερο χρήστη να μαντέψει ένα γράμμα,
- αν το γράμμα είναι σωστό τότε το γράμμα εμφανίζεται στις αντίστοιχες
θέσεις στα αστεράκια που τυπώνονται, αλλιώς αυξάνεται κατά ένα ο αριθμός
των τμημάτων του σώματος που εμφανίζονται στην κρεμάλα.
Όταν ο δεύτερος παίκτης "κρεμαστεί" ή μαντέψει τη λέξη εμφανίζεται αντίστοιχο
μήνυμα.
Σημείωση: για να διαβάσετε τη λέξη μπορείτε να διαβάζετε χαρακτήρες
μέχρι να συναντήσετε \n.
Παράδειγμα:
Enter word: hello
++----
|
|
|
The word is: *****
Enter letter guess: a
Sorry...
++----
| O
|
|
The word is: *****
Enter letter guess: e
Bravo!
++----
| O
|
|
The word is: *e***
Enter letter guess: t
Sorry...
++----
| O
| |
|
The word is: *e***
Enter letter guess: l
Bravo!
++----
| O
| |
|
The word is: *ell*
Enter letter guess: t
Sorry...
++----
| O
| /|
|
The word is: *ell*
Enter letter guess:
...
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 102-106, 117-122
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Luca Cardelli and
Peter Wegner.
On understanding types, data abstraction, and polymorphism.
ACM Computing Surveys, 17(4):471–522, December 1985.
- Guilio Iannello.
Programming abstract data types, iterator and generic modules in c.
Software: Practice & Experience, 20(3):243–260, March 1990.
- Bjarne Stroustrup.
Data abstraction in C.
Bell System Technical Journal, 63(8):1701–1732, October
1984.
Συμβολοσειρές
Παράσταση συμβολοσειρών
Επεξεργασία συμβολοσειρών
- Η επεξεργασία αλφαριθμητικών σταθερών γίνεται με τη χρήση δεικτών.
Το παρακάτω παράδειγμα τυπώνει "hello, world" στην οθόνη:
#include <stdio.h>
void
print_string(char *s)
{
while (*s != '\0') {
putchar(*s);
s++;
}
}
main()
{
print_string("hello, world\n");
}
- Στο παραπάνω παράδειγμα μπορούσαμε να
παραλείψουμε τη σύγκριση *s != '\0' και να γράψουμε απλά while (*s)
- Ακόμα μπορούσαμε να γράψουμε την print_string με τη χρήση πινάκων:
void
print_string(char *s)
{
int i;
for (i = 0; s[i] != '\0'; i++)
putchar(s[i]);
}
- Όλοι οι παραπάνω τρόποι είναι ισοδύναμοι και σωστοί.
Είσοδος και έξοδος
- Η συνάρτηση fgets(buff, n, stdin) διαβάζει από την είσοδο του
προγράμματος (π.χ. το πληκτρολόγιο) μια γραμμή από n-1 το πολύ
χαρακτήρες και του τοποθετεί στη θέση buff.
- Αν η fgets συναντήσει το τέλος του αρχείου επιστρέφει NULL,
αλλιώς επιστρέφει την τιμή buff.
- Αντίστοιχα, μπορούμε να τυπώσουμε μια συμβολοσειρά str με τη
χρήση της συνάρτησης printf("%s", str);.
- Το παρακάτω παράδειγμα διαβάζει μια γραμμή από το πληκτρολόγιο
(μέχρι το \n) και την τυπώνει:
#include <stdio.h>
main()
{
char buff[256];
fgets(buff, sizeof(buff), stdin);
printf("You entered: %s\n", buff);
}
- Η χρήση της πιο απλής συνάρτησης gets πρέπει να αποφεύγεται διότι
οδηγεί σε ανασφαλή προγράμματα.
Συναρτήσεις βιβλιοθήκης
Στην επικεφαλίδα string.h ορίζονται αρκετές συναρτήσεις για το
χειρισμό συμβολοσειρών.
Οι πιο χρήσιμες από αυτές είναι οι παρακάτω:
- char * strcpy(char * a, const char * b);
- Αντιγράφει τη συμβολοσειρά b στη συμβολοσειρά a.
- char * strcat(char * a, const char * b);
- Προσθέτει τη συμβολοσειρά b στο τέλος της συμβολοσειράς a.
- int strcmp(const char * a, const char * b);
- Συγκρίνει τις συμβολοσειρές a και b και επιστρέφει
0 αν είναι ίδιες, -1 αν ο πρώτος διαφορετικός χαρακτήρας της a είναι
μικρότερος από τον αντίστοιχο της b, και 1 στην αντίθετη περίπτωση.
- size_t strlen(const char * a);
- Επιστρέφει τον αριθμό των χαρακτήρων της συμβολοσειράς a.
- char * strchr(const char * a, int c);
- Επιστρέφει ένα δείκτη στην πρώτη εμφάνιση του χαρακτήρα c στη
γραμματοσειρά a ή NULL αν δεν εμφανίζεται.
Σύνθετες δομές
- Τυπικά οι συμβολοσειρές φυλάσσονται σε πιο σύνθετες δομές
όπως πίνακες, δομές και ενώσεις.
- Στις περιπτώσεις αυτές η μνήμη για τους χαρακτήρες δεσμεύεται
με τη χρήση της malloc.
- Το παρακάτω παράδειγμα διαβάζει 5 γραμμές σε έναν πίνακα και
τις τυπώνει με ανάποδη σειρά.
- Αρχικά, κάθε συμβολοσειρά διαβάζεται στον προσωρινό
ενταμιευτή (buffer) buff.
- Στη συνέχεια η malloc δεσμεύει χώρο από τη δυναμική μνήμη
στον οποίο δείχνει η αντίστοιχη σειρά της lines και στην
οποία αντιγράφονται τα περιεχόμενα του buff.
#include <stdio.h>
#include <string.h>
main()
{
int i;
char buff[1024];
char *lines[5];
for (i = 0; i < 5; i++) {
fgets(buff, sizeof(buff), stdin);
lines[i] = (char *)malloc(strlen(buff) + 1);
strcpy(lines[i], buff);
}
for (i = 4; i >= 0; i--)
printf("%s", lines[i]);
}
Ασκήσεις
Συμβολοσειρές
- Υλοποιήστε τις συναρτήσεις που ορίζονται στο string.h με
δικό σας όνομα (π.χ. my_strlen) σε ξεχωριστό αρχείο.
- Γράψτε ένα πρόγραμμα που να ελέγχει τις συναρτήσεις που
υλοποιήσατε.
Η άσκηση είναι προαιρετική.
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 149-153.
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Brian W. Kernighan and Dennis M. Ritchie.
The C Programming Language, pages 104-106.
Prentice-Hall, second edition, 1988.
Η πρότυπη βιβλιοθήκη
Εισαγωγή
- Το πρότυπο ISO/ANSI της γλώσσας C ορίζει την πρότυπη
βιβλιοθήκη ως ένα σύνολο συναρτήσεων που πρέπει να παρέχονται
από υλοποιήσεις που είναι βασισμένες σε πλήρη υπολογιστή (hosted
implementations).
- Οι επόμενες σελίδες περιγράφουν πολύ αδρά τα περιεχόμενα
των βασικών συναρτήσεων κάθε κατηγορίας, έτσι ώστε να δοθεί μια
γενική εικόνα του περιεχομένου της βιβλιοθήκης.
Λεπτομέρειες για τη χρήση των συναρτήσεων υπάρχουν στη βιβλιογραφία.
Είσοδος και έξοδος
Επικεφαλίδα
#include <stdio.h>
Περιλαμβάνει
Συναρτήσεις για είσοδο και έξοδο στοιχείων και επεξεργασία αρχείων.
Βασικές συναρτήσεις
- fopen
- Επιστρέφει ένα ρεύμα (stream) για
την επεξεργασία ενός αρχείου.
- fclose
- Τερματίζει την επεξεργασία ενός αρχείου.
- printf
- Τυπώνει φορμαρισμένα στην έξοδο (stdout).
- fprintf
- Τυπώνει φορμαρισμένα σε αρχείο.
- sprintf
- Τυπώνει φορμαρισμένα σε συμβολοσειρά.
- fscanf
- Διαβάζει φορμαρισμένα από αρχείο.
- scanf
- Διαβάζει φορμαρισμένα από την είσοδο (stdin).
- getc
- Διαβάζει έναν χαρακτήρα από αρχείο.
- getchar
- Διαβάζει έναν χαρακτήρα από την είσοδο.
- putc
- Τυπώνει έναν χαρακτήρα σε αρχείο.
- putchar
- Τυπώνει έναν χαρακτήρα στην έξοδο.
- fread
- Διαβάζει στοιχεία από το αρχείο.
- fwrite
- Τυπώνει στοιχεία στο αρχείο.
- fseek
- Ορίζει τη θέση στο αρχείο
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει τα περιεχόμενα του αρχείου test.c:
#include <stdio.h>
main()
{
FILE *f;
int c;
f = fopen("test.c", "r");
while ((c = getc(f)) != EOF)
putchar(c);
}
Χαρακτηρισμός χαρακτήρων
Επικεφαλίδα
#include <ctype.h>
Περιλαμβάνει
Συναρτήσεις που χαρακτηρίζουν τον είδος ενός χαρακτήρα.
Βασικές συναρτήσεις
- isdigit
- Επιστρέφει αληθές αν ο χαρακτήρας είναι ψηφίο
- isalpha
- Επιστρέφει αληθές αν ο χαρακτήρας είναι αλφαβητικός
- isalnum
- Επιστρέφει αληθές αν ο χαρακτήρας είναι αλφαβητικός ή ψηφίο
- isspace
- Επιστρέφει αληθές αν ο χαρακτήρας είναι κάποιο κενό
- isupper
- Επιστρέφει αληθές αν ο χαρακτήρας είναι κεφαλαίος
- islower
- Επιστρέφει αληθές αν ο χαρακτήρας είναι πεζός
Οι παραπάνω συναρτήσεις σε πολλές υλοποιήσεις δεν υποστηρίζουν
τους ελληνικούς χαρακτήρες.
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει τον αριθμό των ψηφίων, πεζών και κεφαλαίων
χαρακτήρων που συναντά στην είσοδό του.
#include <stdio.h>
#include <ctype.h>
main()
{
int c;
int digits, upper, lower;
digits = upper = lower = 0;
while ((c = getchar()) != EOF) {
if (isdigit(c))
digits++;
if (isupper(c))
upper++;
if (islower(c))
lower++;
}
printf("digits = %d\n", digits);
printf("upper = %d\n", upper);
printf("lower = %d\n", lower);
}
Μαθηματικά
Επικεφαλίδα
#include <math.h>
Περιλαμβάνει
Μαθηματικές συναρτήσεις σε αριθμούς κινητής υποδιαστολής (double)
Βασικές συναρτήσεις
- sin
- Ημίτονο
- cos
- Συνημίτονο
- tan
- Εφαπτομένη
- asin
- Τόξο ημίτονου
- acos
- Τόξο συνημίτονου
- atan2
- Τόξο εφαπτομένης
- sinh
- Υπερβολικό ημίτονο
- cosh
- Υπερβολικό συνημίτονο
- log
- Φυσικός λογάριθμος
- pow
- Δύναμη
- sqrt
- Τετραγωνική ρίζα
- ceil
- Στρογγυλεύει προς τα άνω
- floor
- Στρογγυλεύει προς τα κάτω
- fmod
- Υπόλοιπο διαίρεσης
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει 3.1415...
#include <stdio.h>
#include <math.h>
main()
{
printf("%g\n", 2.0 * asin(1.0));
}
Βοηθητικές συναρτήσεις
Επικεφαλίδα
#include <stdlib.h>
Περιλαμβάνει
Συναρτήσεις μετατροπής αριθμών,
χρήσης δυναμικής μνήμης
(βλ. δυναμική διάθεση μνήμης),
λειτουργίας στο περιβάλλον του λειτουργικού συστήματος και
χρήσης ταξινομημένων πινάκων.
Βασικές συναρτήσεις
- atof
- Μετατρέπει συμβολοσειρά σε double
- atol
- Μετατρέπει συμβολοσειρά σε long
- atoi
- Μετατρέπει συμβολοσειρά σε int
- abs
- Επιστρέφει την απόλυτη τιμή ενός int
- max
- Επιστρέφει το μέγιστο δύο αριθμών
- min
- Επιστρέφει τον ελάχιστο δύο αριθμών
- rand
- Επιστρέφει έναν ψευδοτυχαίο αριθμό 0 - RAND_MAX
- srand
- Καθορίζει τη βάση εκκίνησης της rand
- malloc
- Δεσμεύει και επιστρέφει δυναμική μνήμη
- free
- Ελευθερώνει δυναμική μνήμη
- realloc
- Αλλάζει το μέγεθος ενός τμήματος δυναμικής μνήμης
- exit
- Τερματίζει το πρόγραμμα
- system
- Εκτελεί εντολή του λειτουργικού συστήματος
- getenv
- Επιστρέφει την τιμή μιας μεταβλητής του λειτουργικού συστήματος
- qsort
- Ταξινομεί έναν πίνακα
- bsearch
- Δυαδική αναζήτηση σε ταξινομημένο πίνακα
Παράδειγμα
Το παρακάτω παράδειγμα γεμίζει έναν πίνακα με ψευδοτυχαίους αριθμούς,
τον ταξινομεί και επιτρέπει στο χρήστη να ψάξει για έναν αριθμό
μέσα στον πίνακα.
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
/*
* Qsort/bsearch comparison function
*/
int
compare(const int *a, const int *b)
{
return (*a - *b);
}
/*
* Print an integer table contents using a given label
*/
void
dump_int_table(char *label, int *table, int nelem)
{
int i;
printf("%s\n", label);
for (i = 0; i < nelem; i++)
printf("(%d, %d) ", i, table[i]);
putchar('\n');
}
main()
{
int *tbl; /* Integer table */
char buff[10]; /* User input */
int n, i; /* User number, counter */
int *pos; /* Found position */
const int TABLE_SIZE = 64;
/* Randomize the random number generator using current time */
srand(time(NULL));
/* Allocate table memory */
tbl = (int *)malloc(TABLE_SIZE * sizeof(int));
/* Fill table with random numbers (0 - 2 * TABLE_SIZE) */
for (i = 0; i < TABLE_SIZE; i++)
tbl[i] = rand() % (TABLE_SIZE * 2);
dump_int_table("Table with random numbers", tbl, TABLE_SIZE);
/* Sort the table contents */
qsort(tbl, TABLE_SIZE, sizeof(int), compare);
dump_int_table("Sorted table with random numbers", tbl, TABLE_SIZE);
/* Read and convert a number from the user (without using scanf) */
printf("Search for which number? (0-%d):", 2 * TABLE_SIZE);
fgets(buff, sizeof(buff), stdin);
n = atoi(buff);
/* Search for the number and report result */
pos = bsearch(&n, tbl, TABLE_SIZE, sizeof(int), compare);
if (pos)
printf("The number %d is located at table position %d\n",
n, pos - tbl);
else
printf("The number %d is not in the table\n");
/* Free memory and exit - not strictly needed */
free(tbl);
exit(0);
}
Συμβολοσειρές
Επικεφαλίδα
#include <string.h>
Περιλαμβάνει
Συναρτήσεις επεξεργασίας συμβολοσειρών
(βλ. αναλυτικές σημειώσεις).
Διάγνωση
Επικεφαλίδα
#include <assert.h>
Περιλαμβάνει
Τη συνάρτηση assert
Βασικές συναρτήσεις
- assert
- Με τη δήλωση assert(x) ο προγραμματιστής δηλώνει
στο πρόγραμμα ότι με βάση το σχεδιασμό του περιμένει
ότι η χ θα είναι αληθής.
Αν η x δεν είναι αληθής το πρόγραμμα διακόπτει την εκτέλεσή του
με μήνυμα που πληροφορεί το χειριστή για το σημείο που παρουσιάστηκε
το πρόβλημα.
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει τους αριθμούς 0-9.
Στη συνέχεια θέλουμε να τυπώσει 20 με τη χρήση του i.
Για το σκοπό αυτό ελέγχουμε ότι το i στο τέλος του βρόχου είναι όντως 10.
#include <stdio.h>
#include <assert.h>
main()
{
int i;
for (i = 0; i < 10; i++)
printf("%d\n", i);
/* i should be 10 here */
assert(i == 10);
printf("%d\n", i + i);
}
Ώρα και ημερομηνία
Επικεφαλίδα
#include <time.h>
Περιλαμβάνει
Συναρτήσεις για την επεξεργασία ημερομηνίας και ώρας
Βασικές συναρτήσεις
- time
- Επιστρέφει την ώρα (σε δευτερόλεπτα από το 1970)
- localtime
- Μετατρέπει την ώρα από δευτερόλεπτα σε τοπική ώρα και την αποθηκεύει στη δομή struct tm
- asctime
- Μετατρέπει την ώρα από τη δομή σε συμβολοσειρά.
- difftime
- Επιστρέφει τη διαφορά ανάμεσα σε δύο ώρες
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει την τοπική ώρα.
#include <stdio.h>
#include <time.h>
main()
{
struct tm local;
time_t now;
time(&now);
local = *localtime(&now);
printf("%s\n", asctime(&local));
}
Όρια υλοποίησης
Επικεφαλίδα
#include <limits.h>
#include <float.h>
Περιλαμβάνει
Σταθερές που ορίζουν τα όρια των ακεραίων και αριθμών κινητής
υποδιαστολής για τη συγκεκριμένη υλοποίηση.
Βασικές τιμές
- CHAR_MAX
- Ο μέγιστος char
- CHAR_MIN
- Ο ελάχιστος char
- INT_MAX
- Ο μέγιστος int
- INT_MIN
- Ο ελάχιστος int
- DBL_MAX
- Ο μέγιστος double
- DBL_MIN
- Ο ελάχιστος double
- DBL_DIG
- Τα δεκαδικά ψηφία ακρίβειας των double
Παράδειγμα
Το παρακάτω παράδειγμα τυπώνει τα όρια της υλοποίησης.
#include <stdio.h>
#include <limits.h>
#include <float.h>
main()
{
printf("CHAR_MAX=%d\n", CHAR_MAX);
printf("CHAR_MIN=%d\n", CHAR_MIN);
printf("INT_MAX=%d\n", INT_MAX);
printf("INT_MIN=%d\n", INT_MIN);
printf("DBL_MAX=%g\n", DBL_MAX);
printf("DBL_MIN=%g\n", DBL_MIN);
printf("DBL_DIG=%d\n", DBL_DIG);
}
Στην υλοποίηση Visual C++ 5.00 τυπώνει:
CHAR_MAX=127
CHAR_MIN=-128
INT_MAX=2147483647
INT_MIN=-2147483648
DBL_MAX=1.79769e+308
DBL_MIN=2.22507e-308
DBL_DIG=15
Ασκήσεις
Πρότυπη βιβλιοθήκη
- Να βρείτε και να διαβάσετε την τεκμηρίωση για τη συνάρτηση
rename.
Γράψτε ένα πρόγραμμα που να τη χρησιμοποιεί.
Η άσκηση είναι προαιρετική.
Βιβλιογραφία
- Brian W. Kernighan, Dennis M. Ritchie
Η γλώσσα προγραμματισμού C. σ. 337-349
Δεύτερη έκδοση.
Κλειδάριθμος, 1988.
- Chuck Allison.
The Standard C library, part 1.
C Users Journal, 13(1):69, January 1995.
- Chuck Allison.
The Standard C library, part 2.
C Users Journal, 13(2):89, February 1995.
- Chuck Allison.
The Standard C library, part 3.
C Users Journal, 13(3):59, March 1995.
- American National
Standard for Information Systems — programming language — C:
ANSI X3.159–1989.
Published by the American National Standards Institute, 1430 Broadway, New
York, New York 10018, December 1989.
(Also ISO/IEC 9899:1990).
- Brian W. Kernighan
and Dennis M. Ritchie.
The C
Programming Language, pages 241–258.
Prentice-Hall, second edition, 1988.
- P. J. Plauger.
The Standard C Library.
Prentice Hall, 1992.
Θέματα εξετάσεων
Εξεταστική περιόδος Φεβρουαρίου 1999
ΠΑΝΕΠΙΣΤΗΜΙΟ
ΑΙΓΑΙΟΥ
Τμήμα
Πληροφοριακών
και Επικοινωνιακών
Συστημάτων
Σχεδιασμός και Υλοποίηση Λογισμικού
Διδάσκων: Διομήδης Σπινέλλης
| Εξεταστική περίοδος
Φεβρουαρίου 1999
|
Θέμα
1ο: (2 βαθμοί)
Γράψτε
σε C μια συνάρτηση
που να δέχεται
ως όρισμα
τρεις διαφορετικούς
δείκτες σε
ακεραίους
και μεταθέτει
κυκλικά δεξιόστροφα
τις τιμές
τους. Γράψτε
ένα πρόγραμμα
για τον έλεγχο
της λειτουργίας
της συνάρτησης
αυτής.
Θέμα
2ο: (2 βαθμοί)
Σχεδιάστε
το διάγραμμα
ροής δεδομένων
για μια ταμιακή
μηχανή. Να
λάβετε υπόψη
σας ότι οι
μηχανές αυτές
διαθέτουν
"φορολογική
μνήμη" στην
οποία αποθηκεύονται
τα στοιχεία
των συναλλαγών.
Θέμα
3ο: (3 βαθμοί)
Γράψτε
σε C ένα πρόγραμμα
το οποίο να
δέχεται για
είσοδο τις
συντεταγμένες
(x,y) 100 σημείων
ως αριθμούς
κινητής υποδιαστολής.
Στο τέλος, το
πρόγραμμα
πρέπει να τυπώνει
για κάθε ένα
από τα σημεία
τη θέση του
(x, y) καθώς
και την απόστασή
του από την
αρχή των αξόνων
(0,0). Οι συντεταγμένες
κάθε σημείου
πρέπει να φυλάσσονται
σε δομή (structure). Η
συνάρτηση
της C για την
τετραγωνική
ρίζα (sqrt) ορίζεται
στην επικεφαλίδα
math.h.
Θέμα
4ο: (3 βαθμοί)
Ο τελικός
βαθμός ενός
μαθήματος
είναι κατά
20\% ο βαθμός των
ασκήσεων
και κατά 80\% ο
βαθμός των
εξετάσεων
όταν και οι
δύο βαθμοί
είναι πάνω
από τη βάση,
αλλιώς είναι
ο κατώτερος
από τους δύο.
Σας ζητείται
να υλοποιήσετε
μια εφαρμογή
η οποία διαβάζει
συνέχεια
ζεύγη βαθμών
ασκήσεων
και εξετάσεων
και τυπώνει
λεκτικά (π.χ.
"δέκα") τον
ακέραιο τελικό
βαθμό. Όταν
εισαχθεί το
ζεύγος (-1, -1) η
εφαρμογή τυπώνει
λεκτικά τον
ακέραιο μέσο
όρο των τελικών
βαθμών και
τερματίζει
τη λειτουργία
της. Σχεδιάστε
το διάγραμμα
δομής και γράψτε
σε C το αντίστοιχο
πρόγραμμα.
Διάρκεια εξέτασης 2,5 ώρες
| Καλή επιτυχία!
|
Πρόγραμμα για το θέμα 1: αντιστροφή τιμών
#include <stdio.h>
/*
* Rotate variable values clockwise
*/
void
rotate3(int *a, int *b, int *c)
{
int tmp;
tmp = *c;
*c = *b;
*b = *a;
*a = tmp;
}
main()
{
int v1, v2, v3;
v1 = 1;
v2 = 2;
v3 = 3;
rotate3(&v1, &v2, &v3);
printf("Expect 3 1 2: [%d %d %d]\n", v1, v2, v3);
}
Πρόγραμμα για το θέμα 3: απόσταση σημείων
#include <stdio.h>
#include <math.h>
/*
* Return x squared
*/
double
sqr(double x)
{
return (x * x);
}
main()
{
struct s_point {
double x, y; /* Coordinates */
} points[100];
int i;
for (i = 0; i < 100; i++)
scanf("%lg %lg", &points[i].x, &points[i].y);
for (i = 0; i < 100; i++) {
printf("x=%lg y=%lg ", points[i].x, points[i].y);
printf("d=%lg\n", sqrt(sqr(points[i].x) + sqr(points[i].y)));
}
}
Πρόγραμμα για το θέμα 4: βαθμολογία
#include <stdio.h>
/*
* Print a number 0-10 as a word
*/
void
print_grade(int g)
{
switch (g) {
case 0:
printf("μηδέν\n");
break;
case 1:
printf("ένα\n");
/* ... */
case 10:
printf("δέκα\n");
break;
}
}
main()
{
int exercise, exam, grade;
int count, sum;
count = sum = 0;
for (;;) {
scanf("%d %d", &exercise, &exam);
if (exercise == -1 && exam == -1)
break;
if (exercise >= 5 && exam >= 5)
grade = 0.8 * exercise + 0.2 * grade;
else if (exercise < exam)
grade = exercise;
else
grade = exam;
print_grade(grade);
count++;
sum = sum + grade;
}
printf("M.O. = ");
print_grade(sum / grade);
}
Εξεταστική περιόδος Σεπτεμβρίου 1999
ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΙΓΑΙΟΥ
Τμήμα Πληροφοριακών και Επικοινωνιακών Συστημάτων
Σχεδιασμός και Υλοποίηση Λογισμικού
Διδάσκων: Διομήδης Σπινέλλης |
Εξεταστική περίοδος
Σεπτεμβρίου 1999 |
Θέμα 1ο: (2.5 βαθμοί)
Γράψτε σε C τη συνάρτηση strrev που δέχεται ως όρισμα ένα δείκτη σε χαρακτήρες τερματισμένους με Σ\0Τ (συμβολοσειρά) και αντιστρέφει τη σειρά των χαρακτήρων της συμβολοσειράς. Αν για παράδειγμα η συμβολοσειρά πριν την κλήση τής strrev είναι "live" μετά την κλήση της πρέπει να είναι "evil". Γράψτε ένα απλό πρόγραμμα για τον έλεγχο της λειτουργίας της συνάρτησης αυτής.
Θέμα 2ο: (2.5 βαθμοί)
Προσδιορίστε, σε όχι περισσότερο από μια σελίδα, τις απαιτήσεις λογισμικού για ένα αυτόματα μηχάνημα τραπεζικών συναλλαγών.
Θέμα 3ο: (2.5 βαθμοί)
Να γράψετε ένα πρόγραμμα σε C που να διαβάζει χαρακτήρες από την είσοδό του μέχρι να τερματιστεί το αρχείο εισόδου. Στο τέλος το πρόγραμμα πρέπει να τυπώνει έναν πίνακα ο οποίος για κάθε χαρακτήρα που περιέχεται στο αρχείο θα εμφανίζει το χαρακτήρα αυτό καθώς και το ποσοστό εμφάνισής του σε σχέση με τον αριθμό των χαρακτήρων του αρχείου. Παράδειγμα:
a 12.2\%
e 9.3\%
k 7.3\%
Θέμα 4ο: (2.5 βαθμοί)
Ο παρακάτω κώδικας ορίζει έναν πίνακα αντιστοιχίας ανάμεσα σε χαρακτήρες του λατινικού αλφαβήτου και τον αντίστοιχο κώδικα Morse:
struct s_morse {
char c; /* Character code */
char *morse; /* Morse code */
} morse_table[] = {
'A', ".-",
'B', "-...",
'C', "-.-.",
/* [...] complete table follows */
};
Να γράψετε ένα πρόγραμμα σε C που να διαβάζει χαρακτήρες από την είσοδό του μέχρι να τερματιστεί το αρχείο εισόδου. Για κάθε χαρακτήρα να τυπώνει (με τη χρήση του morse_table) τον αντίστοιχο κώδικα Morse.
Διάρκεια εξέτασης 2,5 ώρες |
Καλή επιτυχία! |
Πρόγραμμα για το θέμα 4: Morse
#include <stdio.h>
struct s_morse {
char c;
char *morse;
} morsetable[] = {
'A', ".-",
'B', "-...",
'C', "-.-.",
};
main()
{
int i, c;
while ((c = getchar()) != EOF) {
for (i = 0; i < sizeof(morsetable) / sizeof(struct s_morse); i++)
if (c == morsetable[i].c)
printf("%s\n", morsetable[i].morse);
}
}
Πρόοδος 1999
ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΙΓΑΙΟΥ
Τμήμα Πληροφοριακών και Επικοινωνιακών Συστημάτων
Σχεδιασμός και Υλοποίηση Λογισμικού
Διδάσκων: Επικ. Καθηγητής Διομήδης Σπινέλλης |
Πρόοδος
Νοεμβρίου 1999 |
Θέμα 1ο: (5 βαθμοί)
Γράψτε σε C ένα πρόγραμμα που διαβάζει από την είσοδό του ακέραιους βαθμούς από το 0 μέχρι το 10. Αφού διαβάσει ένα βαθμό να τυπώνει στην οθόνη του "Περνάει" αν ο βαθμός είναι μεγαλύτερος από 4 ή "Δεν περνάει" αν ο βαθμός είναι μικρότερος από 5. Όταν εισαχθεί ο βαθμός -1, το πρόγραμμα τερματίζει τη λειτουργία του και τυπώνει το μέσο όρο των βαθμών που διάβασε.
Θέμα 2ο: (2 βαθμοί)
Τι θα τυπώσει το παρακάτω πρόγραμμα;
#include <stdio.h>
int
a(int a, int b)
{
a++;
return (a * b + 1);
}
main()
{
int i, f;
f = 1;
for (i = 0; i < 4; i++) {
f = f + a(i, i + 1);
printf("%d\n", f);
}
}
Θέμα 3ο: (3 βαθμοί)
Να ορίσετε σε C μια συνάρτηση που να δέχεται ως όρισμα την ταχύτητα ενός αυτοκινήτου σε km/h και την απόστασή του από τον προορισμό του σε km. Η συνάρτηση να επιστρέφει το χρόνο (σε s) που χρειάζεται το αυτοκίνητο για να φτάσει στον προορισμό του με τη συγκεκριμένη ταχύτητα. Όλα τα μεγέθη να οριστούν ως αριθμοί κινητής υποδιαστολής.
Διάρκεια εξέτασης 2 ώρες |
Καλή επιτυχία! |
Εξεταστική περιόδος Ιανουαρίου 2000
ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΙΓΑΙΟΥ
Τμήμα Πληροφοριακών και Επικοινωνιακών Συστημάτων
Σχεδιασμός και Υλοποίηση Λογισμικού
Διδάσκων: Επίκ. Καθηγητής Διομήδης Σπινέλλης |
Εξεταστική περίοδος
Ιανουαρίου 2000 |
Θέμα 1ο: (2.5 βαθμοί)
Γράψτε σε C τη συνάρτηση farraysum που δέχεται ως όρισμα έναν πίνακα αριθμών κινητής υποδιαστολής και έναν ακέραιο που ορίζει το μέγεθος του πίνακα. Η συνάρτηση επιστρέφει το άθροισμα των στοιχείων του πίνακα. Γράψτε ένα απλό πρόγραμμα για τον έλεγχο της λειτουργίας της συνάρτησης αυτής.
Θέμα 2ο: (2.5 βαθμοί)
Προσδιορίστε, σε όχι περισσότερο από μια σελίδα, τις απαιτήσεις λογισμικού για ένα σύστημα παρακολούθησης δανεισμού βιβλίων από τη βιβλιοθήκη.
Θέμα 3ο: (2 βαθμοί)
Να γράψετε ένα πρόγραμμα σε C που να διαβάζει χαρακτήρες από την είσοδό του μέχρι να τερματιστεί το αρχείο εισόδου. Στο τέλος το πρόγραμμα πρέπει να εμφανίζει ένα μήνυμα αν στο αρχείο εισόδου οι παρενθέσεις και οι αγκύλες που ανοίγουν δεν ταυτίζονται αριθμητικά με αυτές που κλείνουν σύμφωνα με το παρακάτω παράδειγμα:
Λάθος: στο αρχείο εμφανίζονται 5 Σ(Σ και 4 Σ)Τ.
Λάθος: στο αρχείο εμφανίζονται 12 Σ{Σ και 15 Σ}Τ.
Το πρόγραμμα δε χρειάζεται να ελέγχει τη σειρά με την οποία εμφανίζονται τα στοιχεία (π.χ. κλείσιμο πριν από άνοιγμα).
Θέμα 4ο: (3 βαθμοί)
Να γράψετε σε C ένα πρόγραμμα που να διαβάζει από την είσοδό του θετικούς ακέραιους αριθμούς μέχρι να συναντήσει το -1. Στο τέλος το πρόγραμμα να τυπώνει πόσες φορές εμφανίστηκε ο κάθε αριθμός. Ο κάθε αριθμός μαζί με τις φορές που έχει εμφανιστεί να φυλαχτεί σε μια δομή (struct) της C. Το πρόγραμμα πρέπει να μπορεί να χειριστεί θεωρητικά απεριόριστο αριθμό στοιχείων με τη χρήση δυναμικής μνήμης. Παράδειγμα:
Είσοδος: 545 79334 2 143 545 79334 79334 934744 934744 -1
Έξοδος:
545: 2
79334: 3
2: 1
143: 1
934744: 2
Διάρκεια εξέτασης 2,5 ώρες |
Καλή επιτυχία! |
Εξεταστική περιόδος Σεπτεμβρίου 2000
ΠΑΝΕΠΙΣΤΗΜΙΟ ΑΙΓΑΙΟΥ
Τμήμα Πληροφοριακών και Επικοινωνιακών Συστημάτων
Σχεδιασμός και Υλοποίηση Λογισμικού
Διδάσκων: Επίκ. Καθηγητής Διομήδης Σπινέλλης |
Εξεταστική περίοδος
Σεπτεμβρίου 2000 |
Θέμα 1ο: (2.5 βαθμοί)
Γράψτε σε C μια συνάρτηση που να δέχεται ως όρισμα δύο χρονικές στιγμές t1, t2 με t1 < t2 εκφρασμένες ως ώρες, λεπτά, δευτερόλεπτα και να επιστρέφει το χρόνο σε δευτερόλεπτα που μεσολαβεί ανάμεσα στα t1, t2. Γράψτε ένα απλό πρόγραμμα για τον έλεγχο της λειτουργίας της συνάρτησης αυτής. Να ορίσετε και να χρησιμοποιήσετε βοηθητικές συναρτήσεις για να αποφύγετε την επανάληψη κώδικα.
Θέμα 2ο: (2.5 βαθμοί)
Προσδιορίστε, σε όχι περισσότερο από μια σελίδα, τις απαιτήσεις λογισμικού για έναν απλό επεξεργαστή κειμένου.
Θέμα 3ο: (2 βαθμοί)
Η γλώσσα επισημείωσης HTML χρησιμοποιεί την ακολουθία "<tag ...>" για να προσδιορίσει χαρακτηριστικά του κειμένου. Να γράψετε ένα πρόγραμμα σε C που να διαβάζει HTML ως χαρακτήρες από την είσοδό του μέχρι να τερματιστεί το αρχείο εισόδου. Το πρόγραμμα θα εμφανίζει στην έξοδό του το κείμενο της εισόδου χωρίς τις ακολουθίες επισημείωσης. Παράδειγμα:
Είσοδος:
<html><body><h1>Εισαγωγή</h1> Κείμενο της εισαγωγής</body></html>
Έξοδος:
Εισαγωγή Κείμενο της εισαγωγής
Το πρόγραμμα δε χρειάζεται να ελέγχει μη κανονικά σχηματισμένη HTML
(π.χ. επισημειώσεις μέσα σε επισημειώσεις).
Θέμα 4ο: (3 βαθμοί)
Να γράψετε σε C ένα πρόγραμμα που να διαβάζει από την είσοδό του α) τον αριθμό των αθλητών που λαμβάνουν μέρος σε ένα άθλημα και β) για κάθε αθλητή το επώνυμό του (μέχρι 20 χαρακτήρες) και την επίδοσή του (ως αριθμό κινητής υποδιαστολής). Στο τέλος το πρόγραμμα να τυπώνει ξανά τους αθλητές και τις επιδόσεις τους εμφανίζοντας τρία αστεράκια πλάι στο όνομα του αθλητή με την καλύτερη (μικρότερη) επίδοση. Τα στοιχεία του κάθε αθλητή να φυλαχτούν σε μια δομή (struct) της C. Το πρόγραμμα πρέπει να μπορεί να χειριστεί θεωρητικά απεριόριστο αριθμό αθλητών με τη χρήση δυναμικής μνήμης. Το όνομα και η επίδοση του αθλητή μπορούν να διαβαστούν με τη συμβολοσειρά της scanf "%s %g".
Διάρκεια εξέτασης 2,5 ώρες |
Καλή επιτυχία! |
Πληροφορίες για μεταγλωττιστές
Ο μεταγλωττιστής gcc
Προσοχή
Η σελίδα αυτή περιέχει πιθανώς χρήσιμα για μερικούς στοιχεία,
άσχετα όμως με το μάθημα και με τα εργαστήρια.
Τα στοιχεία αυτά δεν αποτελούν τμήμα του μαθήματος ούτε των εργαστηρίων.
Ο διδάσκων και οι υπεύθυνοι των εργαστηρίων δεν υποστηρίζουν τα εργαλεία
τα οποία αναφέρονται στη σελίδα αυτή, ούτε απαντούν σε ερωτήσεις σχετικές
με αυτά.
Κανονική υποστήριξη και βοήθεια υπάρχει στα πλαίσια των εργαστηρίων
για τα εργαλεία τα οποία είναι εγκατεστημένα στα μηχανήματα των εργαστηρίων.
Απαντήσεις σχετικά με τη γλώσσα C (όχι όμως σχετικά με τα εργαλεία αυτά)
δίδονται στα πλαίσια των θεωρητικών μαθημάτων.
Και τώρα τα στοιχεία:
Καλή τύχη!
Αποτελέσματα ασκήσεων
Ασκήσεις 3, 4
cs00001@icsd.aegean.gr | 10 | 10 |
cs00002@icsd.aegean.gr | 10 | 9.5 |
cs00003@icsd.aegean.gr | 10 | 9.5 |
cs00004@icsd.aegean.gr | 10 | 10 |
cs00005@icsd.aegean.gr | 10 | 9.5 |
cs00006@icsd.aegean.gr | 10 | 10 |
cs00007@icsd.aegean.gr | 10 | 10 |
cs00008@icsd.aegean.gr | 10 | 10 |
cs00009@icsd.aegean.gr | | |
cs00010@icsd.aegean.gr | 10 | 10 |
cs00011@icsd.aegean.gr | 10 | 10 |
cs00012@icsd.aegean.gr | 10 | 9.5 |
cs00013@icsd.aegean.gr | 10 | 10 |
cs00014@icsd.aegean.gr | 10 | 10 |
cs00015@icsd.aegean.gr | | |
cs00016@icsd.aegean.gr | 10 | 9.5 |
cs00017@icsd.aegean.gr | 10 | 9 |
cs00018@icsd.aegean.gr | 10 | 10 |
cs00019@icsd.aegean.gr | 10 | 10 |
cs00020@icsd.aegean.gr | 10 | 10 |
cs00021@icsd.aegean.gr | 10 | 10 |
cs00022@icsd.aegean.gr | 10 | 10 |
cs00023@icsd.aegean.gr | 10 | 10 |
cs00024@icsd.aegean.gr | | |
cs00025@icsd.aegean.gr | 10 | 9.5 |
cs00026@icsd.aegean.gr | 10 | 9.5 |
cs00027@icsd.aegean.gr | 0 | 10 |
cs00028@icsd.aegean.gr | 10 | 10 |
cs00029@icsd.aegean.gr | 10 | 10 |
cs00030@icsd.aegean.gr | | |
cs00031@icsd.aegean.gr | 10 | 9.5 |
cs00032@icsd.aegean.gr | 10 | 10 |
cs00033@icsd.aegean.gr | 10 | 9.5 |
cs00034@icsd.aegean.gr | 0 | 10 |
cs00035@icsd.aegean.gr | 10 | 10 |
cs00036@icsd.aegean.gr | 10 | 10 |
cs00037@icsd.aegean.gr | 10 | 10 |
cs00038@icsd.aegean.gr | 10 | 10 |
cs00039@icsd.aegean.gr | 10 | 10 |
cs00040@icsd.aegean.gr | 10 | 10 |
cs00041@icsd.aegean.gr | 10 | 10 |
cs00042@icsd.aegean.gr | | |
cs00043@icsd.aegean.gr | 10 | 10 |
cs00044@icsd.aegean.gr | 10 | 10 |
cs00045@icsd.aegean.gr | 10 | 10 |
cs00046@icsd.aegean.gr | 10 | 10 |
cs00047@icsd.aegean.gr | 10 | 10 |
cs00048@icsd.aegean.gr | 10 | 10 |
cs00049@icsd.aegean.gr | 10 | 9.5 |
cs00050@icsd.aegean.gr | 10 | 10 |
cs00051@icsd.aegean.gr | 10 | 9 |
cs00052@icsd.aegean.gr | 10 | 9.5 |
cs00053@icsd.aegean.gr | 10 | 9.5 |
cs00054@icsd.aegean.gr | 10 | 9 |
cs00055@icsd.aegean.gr | | |
cs00056@icsd.aegean.gr | 10 | 9 |
cs00057@icsd.aegean.gr | | |
cs00058@icsd.aegean.gr | 10 | 9.5 |
cs00059@icsd.aegean.gr | 10 | 10 |
cs00060@icsd.aegean.gr | 10 | 9.5 |
cs00061@icsd.aegean.gr | 10 | 10 |
cs00062@icsd.aegean.gr | | |
cs00063@icsd.aegean.gr | | |
cs00064@icsd.aegean.gr | 10 | 9.5 |
cs00065@icsd.aegean.gr | 10 | 9.5 |
cs00066@icsd.aegean.gr | 10 | 10 |
cs00067@icsd.aegean.gr | | |
cs00068@icsd.aegean.gr | 10 | 10 |
| | |
| | |
cs99004@icsd.aegean.gr | 10 | 10 |
cs99010@icsd.aegean.gr | 10 | 10 |
cs99014@icsd.aegean.gr | 0 | 10 |
cs99016@icsd.aegean.gr | 8 | 7 |
cs99034@icsd.aegean.gr | 10 | 10 |
cs99042@icsd.aegean.gr | 0 | 10 |
cs99043@icsd.aegean.gr | 0 | 10 |
s96052@math.aegean.gr | 10 | 10 |
Ασκήσεις 3-6
| 09-Nov-00 | 09-Nov-00 | 16-Nov-00 | 23-Nov-00 |
E-mail | Άσκηση 3 | Άσκηση 4 | Άσκηση 5 | Άσκηση 6 |
1ο Έτος | | | | |
cs00001@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 10.0 |
cs00002@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00003@icsd.aegean.gr | 10.0 | 9.5 | 9.5 | 9,0* |
cs00004@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00005@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00006@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00007@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00008@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00009@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00010@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 10.0 |
cs00011@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 9.5 |
cs00012@icsd.aegean.gr | 10.0 | 9.5 | 9,0* | 9.0 |
cs00013@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 10.0 |
cs00014@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9.0 |
cs00015@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00016@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 9.0 |
cs00017@icsd.aegean.gr | 10.0 | 9.0 | 9.5 | 9.5 |
cs00018@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 10.0 |
cs00019@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00020@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 0.0 |
cs00021@icsd.aegean.gr | 10.0 | 10.0 | 0.0 | 9,0* |
cs00022@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9.5 |
cs00023@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9.5 |
cs00024@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00025@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 9,0* |
cs00026@icsd.aegean.gr | 10.0 | 9.5 | 8.5 | 10.0 |
cs00027@icsd.aegean.gr | 0.0 | 10.0 | 10.0 | 9.5 |
cs00028@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9,0* |
cs00029@icsd.aegean.gr | 10.0 | 10.0 | 9,0* | 9.5 |
cs00030@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00031@icsd.aegean.gr | 10.0 | 9.5 | 9.5 | 10.0 |
cs00032@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 9.5 |
cs00033@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00034@icsd.aegean.gr | 0.0 | 10.0 | 10.0 | 10.0 |
cs00035@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00036@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9.0 |
cs00037@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00038@icsd.aegean.gr | 10.0 | 10.0 | 9,0* | 9,0* |
cs00039@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00040@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9,0* |
cs00041@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00042@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00043@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00044@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 9.0 |
cs00045@icsd.aegean.gr | 10.0 | 10.0 | 0.0 | 9.0 |
cs00046@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00047@icsd.aegean.gr | 10.0 | 10.0 | 8,5* | 10.0 |
cs00048@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00049@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00050@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00051@icsd.aegean.gr | 10.0 | 9.0 | 10.0 | 10.0 |
cs00052@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00053@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00054@icsd.aegean.gr | 10.0 | 9.0 | 10.0 | 10.0 |
cs00055@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00056@icsd.aegean.gr | 10.0 | 9.0 | 10.0 | 10.0 |
cs00057@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00058@icsd.aegean.gr | 10.0 | 9.5 | 9,0* | 8,0* |
cs00059@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9.5 |
cs00060@icsd.aegean.gr | 10.0 | 9.5 | 9,0* | 10.0 |
cs00061@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs00062@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00063@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00064@icsd.aegean.gr | 10.0 | 9.5 | 10.0 | 10.0 |
cs00065@icsd.aegean.gr | 10.0 | 9.5 | 9,0* | 10.0 |
cs00066@icsd.aegean.gr | 10.0 | 10.0 | 9.0 | 0.0 |
cs00067@icsd.aegean.gr | 0.0 | 0.0 | 0.0 | 0.0 |
cs00068@icsd.aegean.gr | 10.0 | 10.0 | 9,0* | 9,0* |
cs00069@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 9.0 |
| 10.0 | 10.0 | 10.0 | 9.0 |
2ο Έτος | | | | |
cs99004@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 10.0 |
cs99010@icsd.aegean.gr | 10.0 | 10.0 | 9.5 | 10.0 |
cs99014@icsd.aegean.gr | 0.0 | 10.0 | 10.0 | 9.5 |
cs99016@icsd.aegean.gr | 8.0 | 7.0 | 0.0 | 10.0 |
cs99034@icsd.aegean.gr | 10.0 | 10.0 | 10.0 | 9,0* |
cs99039@icsd.aegean.gr | 0.0 | 10.0 | 10.0 | 10.0 |
cs99042@icsd.aegean.gr | 0.0 | 10.0 | 10.0 | 10.0 |
cs99043@icsd.aegean.gr | 0.0 | 0.0 | 10.0 | 10.0 |
Μαθηματικό | | | | |
s96052@math.aegean.gr | 10.0 | 10.0 | 9.5 | 9.5 |