Συναρτήσεις • Κληση/Επιστροφη • Παραμετροι • Περασμα/Επιστροφη δια αναφορας • Δεικτες (τελεστες * και &)
• Εμβελεια Μεταβλητων (συναρτησεων) • τοπικες/καθολικες/στατικες/αυτοματες
• Αναδρομη
#include <stdio.h> float compute_area(float x, float y);
πρωτοτυπο συναρτησης
{
ορισμος συναρτησης
τυπικοι παραμετροι float compute_area(float a, float b) return (a * b); } int main() { float length, width, area;
ορισματα/ πραγματικοι παραμετροι
}
printf(“Enter length and width: “); scanf(“%f%f”,&length, &width); area = compute_area(length, width);
κληση συναρτησης
printf(“The area of a rectangle %f m by %f m is %f sq. m\n” length, width, area); return 0;
Σημασία Κλήσης • Κατανομη μνημης για παραμετρους και τοπικες μεταβλητες της συναρτησης (εαν υπαρχουν) • Αντιγραφη των τιμων των ορισματων στις παραμετρους (εαν υπαρχουν παραμετροι) • Ξεκινα εκτελεσης απο την πρωτη εντολη της συναρτησης
Σημασία Επιστροφής • Αποτιμηση της εκφρασης που ακολουθει το return και αντιγραφη της τιμης στο σημειο κλησης (εαν επιστρεφεται τιμη) • Συνεχιση εκτελεσης με την εντολη που ακολουθει την κληση
#include <stdio.h> int compute_sum(int x, int y); int compute_sum(int a, int b) { int sum; sum = a + b; return sum; } int main() { int sum=0; sum = compute_sum(5, 4);
sum
09
a
5
b sum
printf(“The sum of %d and %d is %d\n”,4, 5, sum); return(0); }
4 9
#include <stdio.h> int compute_sum(int x, int y); int compute_sum(int a, int b) { int sum; sum = a + b; return sum; }
sum
int main() { int sum=0; sum = compute_sum(5, 4); printf(“The sum of %d and %d is %d\n”,4, 5, sum); return(0); }
9
Παραμέτροι • Επιτρεπουν την επικοινωνια μεταξυ συναρτησεων – περασμα δια τιμης (τιμή) • Διοχετευση πληροφοριων προς στην συναρτηση • Μεταβλητη στην συναρτηση κλησης δεν επηρεαζεται αντιγραφεται η τιμη της
– περασμα/επιστροφη δια αναφορας (διεύθυνση) • Διοχετευση πληροφοριων απο την συναρτηση (και εισοδο) • Μεταβλητη στην συναρτηση κλησης μπορει να της ανατεθουν τιμες στην καλουμενη συναρτηση (scanf με τελεστη διευθυνσης) • Επιστροφη πολλων τιμων μεσο διευθυνσεων
#include <stdio.h> int swap(int x, int y); void swap(int a, int b) { int temp; temp = a; a = b; b = temp; }
a
4
c
6
int main() { int a=4, c=6; printf(“a: %d, b: %d\n”,a,c); swap(a, c); printf(“a: %d, b: %d\n”,a,c);
a
46
b
64
return(0); }
temp
4
#include <stdio.h> int swap(int *x, int *y); void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; }
a
46
c
64
int main() { int a=4, c=6; printf(“a: %d, c: %d\n”,a,c); swap(&a, &c); printf(“a: %d, c: %d\n”,a,c);
a
return(0); }
b temp
4
#include <stdio.h> int swap(int *x, int *y); void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; } int main() { int a=4, c=6; printf(“a: %d, c: %d\n”,a,c); swap(&a, &c); printf(“a: %d, c: %d\n”,a,c); return(0); }
a
46
c
64
Δεικτες (pointers) • Συνταξη Δηλωσης Δεικτη – τυπος *ονομα_μεταβλητης – int *foo, *pointer, no_pointer;
• Σημασια Δεικτη – μεταβλητη που περιεχει διευθυνση μιας αλλης μεταβλητης
Δεικτες • Τελεστης Διευθυνσης & – Συνταξη: &ονομα_μεταβλητης (συναρτηση) – Σημασια: δινει την διευθυνση της μεταβλητης
• Τελεστης Εμμεσης Αναφορας * – Συνταξη: *διευθυνση – Σημασια: δινει την τιμη στην διευθυνση
Τελεστης * • Τελεστης γινομενου a*b;
• Δηλωση Δεικτη int *p;
• Τελεστης Εμμεσης Αναφορας * x = *p + 1;
Παραδειγμα με Δεικτες int *p, y, *z; y y = 6; p = &y; z = p; *p = *p + 1; y = *z + 1;
p
*p
z
*z
Παραδειγμα δεικτες • Γραψετε την συναρτηση sort2 που ταξινομει δυο αριθμους a και b ωστε μετα την εκτελεση a<=b • Χρειαζονται δεικτες
Παραδειγμα δεικτες void sort2(int *a, int *b) { int temp; if (*a>*b) temp=*a; *a=*b; *b=temp; }
Παραδειγμα δεικτες void sort2(int *a, int *b) { if (*a>*b) swap(a,b); }
Παραδειγμα δεικτες • Γραψετε την συναρτηση sort3 που ταξινομει τρεις ακεραιους αριθμους a, b και c ωστε μετα την εκτελεση a<=b<=c • Χρησιμοποιηστε την sort2
Παραδειγμα δεικτες void sort3(int *a, int *b, int *c) { sort2(a,b); /* a<= b*/ sort2(a,c); /* a<=c and a<=b sort2(b,c); /* b<= c */ }
Χρηση δεικτων • Χρησιμοποιατε δεικτες μονο οταν χρειαζονται - εμμεση αναφορα ειναι αργη σχεδον σε ολους τους υπολογιστες • Οταν μια συναρτηση επιστρεφει μια τιμη χρησιμοποιατε return αντι δεικτη • Πλευρικα φαινομενα μεσω δεικτων πιο δυσκολα να κατανοηθουν/ανιχνευτουν • Πολυ κοινη πηγη λαθων
Εμβέλεια Μεταβλητής (scope) • Το τμημα του προγραμματος που μπορει μια μεταβλητη να χρησιμοποιηθει – local (τοπικες): • δηλωνονται στην αρχη ενος programming block {..} • οπουδηποτε μετα τον ορισμο μεσα στο block
– global (καθολικες) • δηλωνονται εξω απο συναρτησεις • οπουδηποτε μετα τον ορισμο
– Συγκρουσεις:τοπικες ονομασιες εχουν προτεραιοτητα
#include <stdio.h> int sum=0;
Καθολικη (global)
int compute_sum(int x, int y); void compute_sum(int a, int b) { sum = a + b; }
int main() { int a = 4;
Παραμετροι (parameters)
Τοπικη (local) Ορισματα (arguments)
compute_sum(a, 6); printf(“The sum of %d and %d is %d\n”,a, 6, sum); return(0); }
Καθολικες Μεταβλητες • Γενικα πρεπει να αποφευγονται: δυσκολο να κατανοησεις πλευρικα φαινομενα γιατι διεπαφη γινεται χωρις παραμετρους • Χρησιμη για μεταβλητες που χρησιμοποιουντε απο πολλες συναρτησεις
#include <stdio.h> int sum=0; int compute_sum(int x, int y); int compute_sum(int a, int b) { int sum; sum = a + b; return sum; } int main() { sum = compute_sum(5, 4);
sum
09
a
5
b sum
printf(“The sum of %d and %d is %d\n”,4, 5, sum); return(0); }
4 9
#include <stdio.h> int sum=0; int compute_sum(int x, int y); void compute_sum(int a, int b) {
sum
09
a
5
sum = a + b; } int main() {
b
compute_sum(5, 4); printf(“The sum of %d and %d is %d\n”,4, 5, sum); return(0); }
4
Τοπικες Μεταβλητες • Αυτοματες (automatic) οι τιμες δεν διατηρουνται μεταξυ εκτελεσεων του block που δηλωνεται η μεταβλητη. Δεσμευση/ αποδεσμευση μνημης καθε κληση/ επιστροφη • Στατικες (static) οι τιμες τους υφιστανται μετα την πρωτη εκτελεση του block που ανηκουν. Μια φορα δεσμευση μνημης (αναδρομη!)
Παραδειγμα automatic και static void count_events(int events) { int total = 0; total += events; printf(“Events up to now: %d\n”,total); } int main() { count_events(5); count_events(10); return 0; }
Παραδειγμα automatic και static void count_events(int events) { static int total = 0; total += events; printf(“Events up to now: %d\n”,total); } int main() { count_events(5); count_events(10); return 0; }
Εμβέλεια Συναρτησεων C • Το τμημα του προγραμματος που μπορει μια συναρτηση να χρησιμοποιηθει • Oλες οι συναρτησεις σε ενα αρχειο ειναι καθολικες (δεν υπαρχουν τοπικες συναρτησεις) • Η C δεν παρεχει τοπικες συναρτησεις (αλλες γλωσσες μπορουν πχ pascal)
Αναδρομή (recursion) • Συναρτηση ειναι αναδρομικη εαν ο ορισμος της περιεχει κληση στον ευατο της • Αναδρομικη λυση ενος προβληματος ειναι συχνα ο “φυσικος” τροπος επιλυσης του • Διαμορφωση προβληματος για αναδρομικη λυση • Καθε αναδρομικη συναρτηση μπορει να υλοποιηθει με επαναληψη
Αναδρομή (recursion) • Αναδρομικη και Τερματικη περιπτωση – Πρεπει να υπαρχει τουλαχιστο μια βασικη περιπτωση (base-case) που τερματιζει αναδρομη. Αλλιως απειρος αναδρομη ή δεσμευση ολοκληρη μνημης. – Η αναδρομική κλήση πρέπει να είναι ένα βήμα πιο κοντά σε τερματική περίπτωση, από την κλήση που οδήγησε σε αυτή.
Αναδρομή (recursion) • • • •
Υπολογισμος n! n! = n n-1 n-2 … 1, 1!=1 0!=1 n! = n n-1! fact(n) = n fact(n-1) και fact(1)=1, fact(0)=1
Αναδρομή (recursion) float factorial(int n) { if (n<2) return 1; return n*factorial(n-1); }
float factorial(int n) { int i ; int fact = 1; for(i=n;i>2;--i) fact = fact *i; return fact; }
Προβληματα Αναδρομής • Αχρειαστος υπολογισμος • Δεσμευση μνημης (για αυτοματες μεταβλητες)
Ακολουθια Fibonacci • 0, 1, 1, 2, 3, 5, 8, 13, . . . . . • Fib(n) = Fib(n – 2) + Fib(n – 1) και Fib(0) = 0, Fib(1) = 1 • πχ – – – –
Fib(2) = Fib(0)+ Fib(1) = 0 + 1 = 1 Fib(3) = Fib(1)+ Fib(2)= 1 + 1 = 2 Fib(4) = Fib(2)+ Fib(3)= 1 + 2 = 3 ........
Αναδρομικο Fibonacci int Fib (int x){ if (x == 0) return 0; else if (x == 1) return 1; else return Fib(x – 2) + Fib(x – 1); }
Fib(5)
Fib(3)
Fib(1)
1
Fib(4)
Fib(2)
Fib(2)
Fib(0)
Fib(1)
Fib(0)
0
1
0
Fib(3)
Fib(1) Fib(1)
1
Fib(2)
1 Fib(0) Fib(1) 0
Ο ορισμός δεν είναι αποδοτικός
1
Fibonacci με επαναληψη int Fib (int x){ int f, a=0, b=1,i; if (x < 2) return x; for(i=2;i<=x;++i){ f=a+b; εννοια a = b; b = f; } return f; }
moving window
Αναδρομη και static • Συναρτηση read_and_sum που διαβαζει μια σειρα θετικων ακεραιων απροσδιοριστου μεγευθους (τερματιζεται με 0) και υπολογιζει και επιστρεφει το αθροισμα τους.
Αναδρομη και static int read_and_sum() { int number; scanf(“%d”,&number); if (number == 0) return 0; return number + read_and_sum(); }
Αναδρομη και static(problematic) int read_and_sum() { static int number; scanf(“%d”,&number); if (number == 0) return 0; return number + read_and_sum(); }
Αναδρομη Γραψετε την συναρτηση reverse που διαβαζει μια απροσδιοριστου μεγεθους σειρας και την τυπωνει αντιστροφα. void reverse() { int number; scanf(“%d”,&number); if (number == 0) return; printf(“%d\n”,number); }