Δημοσιεύτηκε: 29 Ιούλ 2011, 21:18
από migf1
Ωραία, ας μιλήσουμε πρώτα για συναρτήσεις, που και εύκολες είναι σαν έννοιες και τις χρησιμοποιούμε συνέχεια. Έχουν μια μικρή δυσκολία στη C σε ότι αφορά τα ορίσματα που τους περνάμε, επειδή όταν θέλουμε η συνάρτηση να πειράζει μόνιμα τις τιμές των ορισμάτων της, τα ορίσματα αυτά πρέπει να τα περνάμε ως δείκτες. Αλλά για αρχή τουλάχιστον, αρκεί απλά να το αποστηθίστε το και θα το εξηγήσουμε αναλυτικά αργότερα όταν μιλήσουμε γενικώς για δείκτες.

Λοιπόν, με απλά λόγια οι συναρτήσεις είναι ομαδοποιημένα κομμάτια κώδικα που μπορούν να κληθούν πολλές φορές σε διάφορα σημεία του υπόλοιπου κώδικα, χωρίς να χρειάζεται να γράφουμε και να ξαναγράφουμε τον ίδιο κώδικα. Μπορούν επίσης να δέχονται ορίσματα και να επιστρέφουν τιμές. Ο τύπος των ορισμάτων καθώς και της τιμής επιστροφής της συνάρτησης (που δηλώνονται όταν πρωτο-ορίζουμε την συνάρτηση στο σημείο που γράφουμε τον κώδικά της) ονομάζεται πρότυπο, ή πρωτότυπο ή αρχέτυπο της συνάρτησης (function prototype)... προσωπικά χρησιμοποιώ τον όρο: πρότυπο.

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

Το πρότυπο λοιπόν της συνάρτησης είναι το:

Κώδικας: Επιλογή όλων

float sum2f( float, float);

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

Παρατηρήστε πως στο πρότυπο δεν είμαστε υποχρεωμένοι να ονοματίσουμε τα ορίσματα, αρκεί να παραθέσουμε απλά τον τύπο τους. Συχνά όμως θα δείτε να περιλαμβάνεται και το όνομα των ορισμάτων, δεν είναι λάθος (απλώς αυξάνει τις πιθανότητες να υπάρχει "εμπλοκή" κοινής ονομασίας π.χ. με macros... δεν είναι του παρόντος).

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

Π.χ.

Κώδικας: Επιλογή όλων
float sum2f( float /*x*/, float /*y*/);

ΣΗΜΑΝΤΙΚΟ: Τα πρότυπα ΔΕΝ είναι οι ορισμοί των συναρτήσεων, στους ορισμούς τους (εκεί δηλαδή που γράφουμε και τον κώδικα της συνάρτησης) πρέπει ΥΠΟΧΡΕΩΤΙΚΑ να βάζουμε και τα ονόματα των ορισμάτων.

Όταν μια συνάρτηση δεν έχει ορίσματα, τότε γράφουμε void μέσα στην παρένθεση των ορισμάτων (και στο πρότυπο και στον ορισμό της).

π.χ.
Κώδικας: Επιλογή όλων
float test( void );

Όταν μια συνάρτησή δεν επιστρέφει τίποτα, τότε πάλι χρησιμοποιούμε το void ως τύπο για την τιμή επιστροφής της.

π.χ.
Κώδικας: Επιλογή όλων
void test( void );

void σημαίνει: κενό.

Ας ορίσουμε τώρα την συνάρτησή μας, να επιστρέφει το άθροισμα των 2 ορισμάτων της:

Κώδικας: Επιλογή όλων

float sum2f(float x, float y)
{
return x+y;
}

Η τιμή που θέλουμε να επιστρέφει η συνάρτησή μας μπαίνει με το keyword: return, ακολουθούμενο από την τιμή επιστροφής (ή την έκφραση που την υπολογίζει) η οποία προφανώς πρέπει να συμβαδίζει ως τύπος με τον τύπο επιστροφής που έχουμε δηλώσει πριν από το όνομα της συνάρτησης (αν όχι, ο compiler θα σας βγάλει error ή warning).

Τι τα θέλουμε τα πρότυπα;

Κανονικά στη C δεν μπορούμε να χρησιμοποιήσουμε μια συνάρτηση πριν την ορίσουμε. Οπότε κανονικά η main() που χρησιμοποιεί αν όχι όλες τότε τις περισσότερες από τις συναρτήσεις μας πρέπει να ορίζεται τελευταία. Όπως επίσης αν μια συνάρτηση foo1 χρησιμοποιεί μέσα της μια άλλη συνάρτηση foo2, τότε η foo2 πρέπει να οριστεί πριν από την foo1.

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

Οπότε ο κώδικας ενός προγράμματος που ζητάει 2 float και τυπώνει το άθροισμά τους μπορεί να γραφτεί με (τουλάχιστον) 2 τρόπους:

Τρόπος 1 (χωρίς χρήση προτύπων):
Κώδικας: Επιλογή όλων

#include <stdio.h>
// ------------------------------------------------------
float sum2f( float x, float y)
{
return x+y;
}
// ------------------------------------------------------
int main( void )
{
char inbuf[256]="";
float x, y;

printf("Enter two float numbers: ");
fgets(inbuf, 256, stdin);
sscanf(inbuf, "%f %f", &x, &y);
printf("Their sum is: %f\n", sum2f(x,y) );

return 0;
}

Τρόπος 2 (με χρήση προτύπων):
Κώδικας: Επιλογή όλων

#include <stdio.h>

// function prototypes
float sum2f(float /*x/, float /*y*/);

// ------------------------------------------------------
int main( void )
{
char inbuf[256]="";
float x, y;

printf("Enter two float numbers: ");
fgets(inbuf, 256, stdin);
sscanf(inbuf, "%f %f", &x, &y);
printf("Their sum is: %f\n", sum2f(x,y) );

return 0;
}
// ------------------------------------------------------
float sum2f( float x, float y)
{
return x+y;
}


ΥΓ. Είμαι ακόμα στη δουλειά (από το πρωί) και ήρθε η ώρα να πάω κι εγώ σπιτάκι μου σιγά-σιγά. Μάλλον θα ξαναμπώ αργότερα, αλλιώς αύριο. Γράψτε τυχόν απορίες σας μέχρι τώρα για τα παραπάνω (ή αν έχετε ακόμα απορίες από την είσοδο με το inbuf) και συνεχίζουμε.