Κεφάλαιο – 5
Εισαγωγή στον προγραμματισμό C
Εισαγωγή
Η 'C' είναι μια από τις πιο δημοφιλείς γλώσσες προγραμματισμού στον σύγχρονο κόσμο των υπολογιστών. Η γλώσσα προγραμματισμού C σχεδιάστηκε και δημιουργήθηκε από τους Brian Kernighan και Dennis Ritchie στο Bell Research Labs το 1972.
Η 'C' είναι μια γλώσσα ειδικά σχεδιασμένη για να παρέχει στον προγραμματιστή πρόσβαση σε όλα σχεδόν τα εσωτερικά στοιχεία μιας μηχανής - καταχωρητές, υποδοχές εισόδου/εξόδου και απόλυτες διευθύνσεις. Ταυτόχρονα, το 'C' επιτρέπει την επεξεργασία δεδομένων και τη σπονδυλοποίηση προγραμματισμένου κειμένου όση είναι απαραίτητη, έτσι ώστε να μπορούν να κατασκευαστούν πολύπλοκα έργα πολλαπλού προγραμματισμού με οργανωμένο και έγκαιρο τρόπο.
Παρόλο που η γλώσσα προοριζόταν αρχικά να εκτελείται υπό το UNIX, υπήρχε μεγάλο ενδιαφέρον για την εκτέλεση υπό το λειτουργικό σύστημα MS-DOS σε υπολογιστή IBM και σε συμβατά. Είναι μια εξαιρετική γλώσσα για αυτό το περιβάλλον λόγω της απλότητας της έκφρασης, της συμπαγούς κώδικα και του μεγάλου εύρους εφαρμογής.
Επιπλέον, λόγω της απλότητας και της ευκολίας γραφής ενός μεταγλωττιστή C, είναι συνήθως η πρώτη γλώσσα υψηλού επιπέδου διαθέσιμη σε οποιονδήποτε νέο υπολογιστή, συμπεριλαμβανομένων των μικροϋπολογιστών, των μικρών υπολογιστών και των κεντρικών υπολογιστών.
Γιατί να χρησιμοποιήσετε το C στον προγραμματισμό ανάκτησης δεδομένων
Στον σημερινό κόσμο του προγραμματισμού υπολογιστών, υπάρχουν πολλές διαθέσιμες γλώσσες υψηλού επιπέδου. Αυτές οι γλώσσες είναι καλές επειδή έχουν πολλές δυνατότητες που είναι κατάλληλες για τις περισσότερες εργασίες προγραμματισμού. Ωστόσο, υπάρχουν διάφοροι λόγοι για τους οποίους το C είναι η πρώτη επιλογή των προγραμματιστών που θέλουν να κάνουν προγραμματισμό ανάκτησης δεδομένων, προγραμματισμό συστήματος, προγραμματισμό συσκευών ή προγραμματισμό υλικού:
- Η C είναι μια δημοφιλής γλώσσα που προτιμάται από επαγγελματίες προγραμματιστές. Ως αποτέλεσμα, μια μεγάλη γκάμα μεταγλωττιστών C και χρήσιμων εξαρτημάτων είναι διαθέσιμη.
- Η C είναι μια φορητή γλώσσα . Ένα πρόγραμμα C γραμμένο για ένα σύστημα υπολογιστή μπορεί να μεταγλωττιστεί και να εκτελεστεί σε άλλο σύστημα με ελάχιστη ή καθόλου τροποποίηση. Η φορητότητα βελτιώνεται από το πρότυπο ANSI για C, ένα σύνολο κανόνων για μεταγλωττιστές C.
- Το C επιτρέπει την εκτεταμένη χρήση των μονάδων στον προγραμματισμό. Ο κώδικας C μπορεί να γραφτεί σε υπορουτίνες που ονομάζονται συναρτήσεις. Αυτές οι λειτουργίες μπορούν να επαναχρησιμοποιηθούν σε άλλες εφαρμογές ή προγράμματα. Δεν χρειάζεται να καταβάλετε επιπλέον προσπάθεια κατά τον προγραμματισμό μιας νέας εφαρμογής για να δημιουργήσετε την ίδια ενότητα που αναπτύξατε σε άλλη εφαρμογή νωρίτερα.
Μπορείτε να χρησιμοποιήσετε αυτήν τη δυνατότητα στο νέο πρόγραμμα χωρίς αλλαγές ή με κάποιες μικρές αλλαγές. Στην περίπτωση του προγραμματισμού ανάκτησης δεδομένων, θα βρείτε αυτή την ποιότητα πολύ χρήσιμη όταν χρειάζεται να εκτελέσετε τις ίδιες λειτουργίες πολλές φορές σε διαφορετικές εφαρμογές διαφορετικών προγραμμάτων.
- Η C είναι μια ισχυρή και ευέλικτη γλώσσα. Αυτός είναι ο λόγος για τον οποίο το C χρησιμοποιείται για τόσο διαφορετικά έργα όπως λειτουργικά συστήματα, επεξεργαστές κειμένου, γραφικά, υπολογιστικά φύλλα, ακόμη και μεταγλωττιστές για άλλες γλώσσες.
- Η C είναι μια γλώσσα λίγων λέξεων, που περιέχει μόνο λίγους όρους, που ονομάζονται λέξεις-κλειδιά, που χρησιμεύουν ως το θεμέλιο πάνω στο οποίο οικοδομείται η λειτουργικότητα της γλώσσας. Αυτές οι λέξεις-κλειδιά, που ονομάζονται επίσης δεσμευμένες λέξεις, το κάνουν πιο ισχυρό και δίνουν ένα ευρύ πεδίο προγραμματισμού και κάνουν τον προγραμματιστή να αισθάνεται ικανός να κάνει οποιοδήποτε τύπο προγραμματισμού σε C.
Επιτρέψτε μου να υποθέσω ότι δεν γνωρίζετε τίποτα για το C.
Υποθέτω ότι δεν γνωρίζετε τίποτα για τον προγραμματισμό C και δεν έχετε ιδέα για προγραμματισμό. Θα ξεκινήσω με τις πιο βασικές έννοιες της γλώσσας C και θα σας μεταφέρω στον προγραμματισμό υψηλού επιπέδου C, συμπεριλαμβανομένων των συνήθως εκφοβιστικών εννοιών των δεικτών, των δομών και της δυναμικής εκχώρησης μνήμης.
Θα σας πάρει πολύ χρόνο και προσπάθεια για να κατανοήσετε πλήρως αυτές τις έννοιες γιατί δεν είναι εύκολο να τις κατανοήσετε, αλλά είναι πολύ ισχυρά εργαλεία.
Ο προγραμματισμός C είναι ένα τεράστιο πλεονέκτημα σε τομείς όπου μπορεί να χρειαστεί να χρησιμοποιήσετε γλώσσα assembly, αλλά θα προτιμούσατε να τον διατηρήσετε απλό στη σύνταξη και τη συντήρηση. Ο χρόνος που εξοικονομείται από την κωδικοποίηση σε C μπορεί να είναι τεράστιος σε τέτοιες περιπτώσεις.
Παρόλο που η γλώσσα C απολαμβάνει ένα καλό ρεκόρ όταν τα προγράμματα μεταφέρονται από τη μια εφαρμογή στην άλλη, υπάρχουν διαφορές στους μεταγλωττιστές που θα βρείτε κάθε φορά που προσπαθείτε να χρησιμοποιήσετε έναν άλλο μεταγλωττιστή.
Οι περισσότερες διαφορές γίνονται εμφανείς όταν χρησιμοποιείτε μη τυπικές επεκτάσεις, όπως κλήσεις στο DOS BIOS όταν χρησιμοποιείτε MS-DOS, αλλά ακόμη και αυτές οι διαφορές μπορούν να ελαχιστοποιηθούν με προσεκτική επιλογή δομών προγραμματισμού.
Όταν έγινε φανερό ότι η γλώσσα προγραμματισμού C γινόταν μια πολύ δημοφιλής γλώσσα διαθέσιμη σε ένα ευρύ φάσμα υπολογιστών, μια ομάδα ενδιαφερόμενων ατόμων συναντήθηκε για να προτείνει ένα τυπικό σύνολο κανόνων για τη χρήση της γλώσσας προγραμματισμού C.
Η ομάδα αντιπροσώπευε όλους τους τομείς της βιομηχανίας λογισμικού και μετά από πολλές συναντήσεις και πολλά προκαταρκτικά προσχέδια, έγραψαν τελικά ένα αποδεκτό πρότυπο για τη γλώσσα C. Έχει γίνει αποδεκτό από το Αμερικανικό Εθνικό Ινστιτούτο Προτύπων (ANSI) και από τον Διεθνή Οργανισμό Προτύπων (ISO) .
Δεν επιβάλλεται σε καμία ομάδα ή χρήστη, αλλά δεδομένου ότι είναι τόσο ευρέως αποδεκτό, θα ήταν οικονομική αυτοκτονία για κάθε συγγραφέα μεταγλωττιστή να αρνηθεί να συμμορφωθεί με το πρότυπο.
Τα προγράμματα που γράφτηκαν σε αυτό το βιβλίο προορίζονται κυρίως για χρήση σε υπολογιστή IBM-PC ή συμβατό υπολογιστή, αλλά μπορούν να χρησιμοποιηθούν με οποιονδήποτε τυπικό μεταγλωττιστή ANSI, καθώς συμμορφώνεται τόσο πολύ με το πρότυπο ANSI.
Ας ξεκινήσουμε
Για να μπορέσετε να κάνετε οτιδήποτε σε οποιαδήποτε γλώσσα και να ξεκινήσετε τον προγραμματισμό, πρέπει να γνωρίζετε πώς να ονομάσετε ένα αναγνωριστικό. Ένα αναγνωριστικό χρησιμοποιείται για οποιαδήποτε μεταβλητή, συνάρτηση, ορισμό δεδομένων κ.λπ. Στη γλώσσα προγραμματισμού C, ένα αναγνωριστικό είναι ένας συνδυασμός αλφαριθμητικών χαρακτήρων, ο πρώτος είναι ένα γράμμα του αλφαβήτου ή μια υπογράμμιση και το υπόλοιπο είναι οποιοδήποτε γράμμα του αλφαβήτου, οποιοδήποτε αριθμητικό ψηφίο ή η υπογράμμιση.
Δύο κανόνες πρέπει να λαμβάνονται υπόψη κατά την ονομασία αναγνωριστικών.
- Η περίπτωση των αλφαβητικών χαρακτήρων είναι σημαντική. Η C είναι γλώσσα με διάκριση πεζών-κεφαλαίων. Αυτό σημαίνει ότι το Recovery είναι διαφορετικό από το Recovery και το RecOveRY είναι διαφορετικό από τα δύο που αναφέρθηκαν προηγουμένως.
- Σύμφωνα με το πρότυπο ANSI-C, μπορούν να χρησιμοποιηθούν τουλάχιστον 31 σημαντικοί χαρακτήρες και θα θεωρηθούν σημαντικοί από έναν συμμορφούμενο μεταγλωττιστή ANSI-C. Εάν χρησιμοποιούνται περισσότεροι από 31, όλοι οι χαρακτήρες πέρα από τον 31ο μπορεί να αγνοηθούν από οποιονδήποτε μεταγλωττιστή.
Λέξεις-κλειδιά
Υπάρχουν 32 λέξεις που ορίζονται ως λέξεις-κλειδιά στο C. Αυτές έχουν προκαθορισμένες χρήσεις και δεν μπορούν να χρησιμοποιηθούν για κανέναν άλλο σκοπό σε ένα πρόγραμμα C. Χρησιμοποιούνται από τον μεταγλωττιστή ως βοήθημα για τη μεταγλώττιση του προγράμματος. Γράφονται πάντα με πεζά. Ακολουθεί πλήρης λίστα:
αυτο |
διακοπή |
περίπτωση |
απανθρακώνω |
συνθ |
συνεχίζω |
αθέτηση |
κάνω |
διπλό |
αλλού |
αρίθμηση |
εξωτερικό |
φλοτέρ |
για |
πήγαινε |
αν |
ενθ |
μακρύς |
μητρώο |
απόδοση |
μικρός |
υπογεγραμμένος |
μέγεθος του |
στατικός |
struct |
διακόπτης |
typedef |
ένωση |
ανυπόγραφο |
κενός |
πτητικός |
ενώ |
Εδώ βλέπουμε τη μαγεία του C. Η υπέροχη συλλογή με 32 μόνο λέξεις-κλειδιά δίνει ευρεία χρήση σε διαφορετικές εφαρμογές. Κάθε πρόγραμμα υπολογιστή έχει δύο οντότητες που πρέπει να ληφθούν υπόψη, τα δεδομένα και το πρόγραμμα. Εξαρτώνται σε μεγάλο βαθμό το ένα από το άλλο και ο προσεκτικός σχεδιασμός και των δύο οδηγεί σε ένα καλά σχεδιασμένο και καλογραμμένο πρόγραμμα.
Ας ξεκινήσουμε με ένα απλό πρόγραμμα C:
/* Πρώτο πρόγραμμα για εκμάθηση C */
#include <stdio.h>
void main()
{
printf("Αυτό είναι ένα πρόγραμμα C\n"); // εκτύπωση μηνύματος
}
Αν και το πρόγραμμα είναι πολύ απλό, αξίζει να σημειωθούν μερικά σημεία. Ας εξετάσουμε το παραπάνω πρόγραμμα. Ό,τι υπάρχει μέσα στο /* και στο */ θεωρείται σχόλιο και θα αγνοηθεί από τον μεταγλωττιστή. Δεν πρέπει να συμπεριλάβετε σχόλια σε άλλα σχόλια, επομένως κάτι τέτοιο δεν επιτρέπεται:
/* αυτό είναι ένα /* σχόλιο */ μέσα σε ένα σχόλιο, το οποίο είναι λάθος */
Υπάρχει επίσης ένας τρόπος τεκμηρίωσης που λειτουργεί μέσα σε μια γραμμή. Χρησιμοποιώντας το // μπορούμε να προσθέσουμε μικρή τεκμηρίωση σε αυτή τη γραμμή.
Κάθε πρόγραμμα C περιέχει μια συνάρτηση που ονομάζεται main. Αυτό είναι το σημείο εκκίνησης του προγράμματος. Κάθε συνάρτηση πρέπει να επιστρέφει μια τιμή. Σε αυτό το πρόγραμμα η συνάρτηση main δεν επιστρέφει τιμή επιστροφής επομένως έχουμε γράψει void main. Θα μπορούσαμε επίσης να γράψουμε αυτό το πρόγραμμα ως:
/* Πρώτο πρόγραμμα για εκμάθηση C */
#include <stdio.h>
κύριος()
{
printf("Αυτό είναι ένα πρόγραμμα C\n"); // εκτύπωση μηνύματος
επιστροφή 0;
}
Και τα δύο προγράμματα είναι ίδια και εκτελούν την ίδια εργασία. Το αποτέλεσμα και των δύο προγραμμάτων θα εκτυπώσει την ακόλουθη έξοδο στην οθόνη:
Αυτό είναι ένα πρόγραμμα C
Το #include<stdio.h> επιτρέπει στο πρόγραμμα να αλληλεπιδρά με την οθόνη, το πληκτρολόγιο και το σύστημα αρχείων του υπολογιστή σας. Θα το βρείτε στην αρχή σχεδόν κάθε προγράμματος C.
Η main() δηλώνει την έναρξη της συνάρτησης, ενώ οι δύο σγουρές αγκύλες δείχνουν την αρχή και το τέλος της συνάρτησης. Οι σγουρές αγκύλες στο C χρησιμοποιούνται για την ομαδοποίηση εντολών όπως σε μια συνάρτηση ή στο σώμα ενός βρόχου. Μια τέτοια ομαδοποίηση είναι γνωστή ως σύνθετη πρόταση ή μπλοκ.
printf("Αυτό είναι ένα πρόγραμμα C\n"); εκτυπώνει τις λέξεις στην οθόνη. Το προς εκτύπωση κείμενο περικλείεται σε διπλά εισαγωγικά. Το \n στο τέλος του κειμένου λέει στο πρόγραμμα να εκτυπώσει μια νέα γραμμή ως μέρος της εξόδου. Η συνάρτηση printf() χρησιμοποιείται για την εμφάνιση της εξόδου στην οθόνη.
Τα περισσότερα από τα προγράμματα C είναι με πεζά γράμματα. Συνήθως θα βρείτε κεφαλαία γράμματα που χρησιμοποιούνται σε ορισμούς προεπεξεργαστή που θα συζητηθούν αργότερα ή μέσα σε εισαγωγικά ως μέρη συμβολοσειρών χαρακτήρων.
Σύνταξη του προγράμματος
Ας το όνομα του προγράμματός μας είναι CPROG.C. Για να εισαγάγετε και να μεταγλωττίσετε το πρόγραμμα C, ακολουθήστε τα εξής βήματα:
- Δημιουργήστε τον ενεργό κατάλογο των προγραμμάτων σας C και ξεκινήστε τον επεξεργαστή σας. Για αυτό μπορεί να χρησιμοποιηθεί οποιοσδήποτε επεξεργαστής κειμένου, αλλά οι περισσότεροι μεταγλωττιστές C, όπως το Turbo C++ της Borland, διαθέτουν ένα ενσωματωμένο περιβάλλον ανάπτυξης (IDE) που σας επιτρέπει να εισάγετε, να μεταγλωττίσετε και να συνδέσετε τα προγράμματά σας σε μία βολική ρύθμιση.
- Γράψτε και αποθηκεύστε τον πηγαίο κώδικα. Θα πρέπει να ονομάσετε το αρχείο CPROG.C.
- Μεταγλώττιση και σύνδεση CPROG.C. Εκτελέστε την κατάλληλη εντολή που καθορίζεται από τα εγχειρίδια του μεταγλωττιστή σας. Θα πρέπει να λάβετε ένα μήνυμα που να δηλώνει ότι δεν υπήρχαν σφάλματα ή προειδοποιήσεις.
- Ελέγξτε τα μηνύματα του μεταγλωττιστή. Εάν δεν λάβετε σφάλματα ή προειδοποιήσεις, όλα θα πρέπει να είναι εντάξει. Εάν υπάρχει κάποιο σφάλμα κατά την πληκτρολόγηση του προγράμματος, ο μεταγλωττιστής θα το πιάσει και θα εμφανίσει ένα μήνυμα σφάλματος. Διορθώστε το σφάλμα, που εμφανίζεται στο μήνυμα σφάλματος.
- Το πρώτο σας πρόγραμμα C πρέπει τώρα να έχει μεταγλωττιστεί και να είναι έτοιμο για εκτέλεση. Εάν εμφανίσετε μια λίστα καταλόγου με όλα τα αρχεία με το όνομα CPROG, θα λάβετε τα τέσσερα αρχεία με διαφορετική επέκταση που περιγράφονται ως εξής:
- CPROG.C, το αρχείο πηγαίου κώδικα
- CPROG.BAK, το αντίγραφο ασφαλείας του αρχείου πηγής που δημιουργήσατε με το πρόγραμμα επεξεργασίας
- CPROG.OBJ, περιέχει τον κωδικό αντικειμένου για CPROG.C
- CPROG.EXE, το εκτελέσιμο πρόγραμμα που δημιουργήθηκε κατά τη μεταγλώττιση και σύνδεση του CPROG.C
- Για να εκτελέσετε ή να εκτελέσετε το CPROG.EXE, απλώς πληκτρολογήστε cprog. Στην οθόνη εμφανίζεται το μήνυμα This is a C program.
Ας εξετάσουμε τώρα το παρακάτω πρόγραμμα:
/* Πρώτο πρόγραμμα για εκμάθηση C */ // 1
// 2
#include <stdio.h> // 3
// 4
main() // 5
{
// 6
printf("Αυτό είναι ένα πρόγραμμα C\n"); // 7
// 8
επιστροφή 0; // 9
} // 10
Όταν κάνετε μεταγλώττιση αυτού του προγράμματος, ο μεταγλωττιστής εμφανίζει ένα μήνυμα παρόμοιο με το ακόλουθο:
cprog.c(8) : Σφάλμα: `;' αναμενόμενο
ας σπάσουμε αυτό το μήνυμα σφάλματος σε μέρη. cprog.c είναι το όνομα του αρχείου όπου βρέθηκε το σφάλμα. Το (8) είναι ο αριθμός γραμμής όπου βρέθηκε το σφάλμα. Σφάλμα: `;' αναμενόμενο είναι Μια περιγραφή του σφάλματος.
Αυτό το μήνυμα είναι αρκετά κατατοπιστικό και σας λέει ότι στη γραμμή 8 του CPROG.C ο μεταγλωττιστής περίμενε να βρει ένα ερωτηματικό αλλά δεν το έκανε. Ωστόσο, γνωρίζετε ότι το ερωτηματικό παραλείφθηκε στην πραγματικότητα από τη γραμμή 7, επομένως υπάρχει μια απόκλιση.
Γιατί ο μεταγλωττιστής αναφέρει ένα σφάλμα στη γραμμή 8 όταν, στην πραγματικότητα, ένα ερωτηματικό παραλείφθηκε από τη γραμμή 7. Η απάντηση βρίσκεται στο γεγονός ότι η C δεν ενδιαφέρεται για πράγματα όπως διαλείμματα μεταξύ των γραμμών. Το ερωτηματικό που ανήκει μετά την πρόταση printf() θα μπορούσε να είχε τοποθετηθεί στην επόμενη γραμμή, αν και κάτι τέτοιο θα ήταν κακός προγραμματισμός στην πράξη.
Μόνο αφού συναντήσει την επόμενη εντολή (return) στη γραμμή 8, ο μεταγλωττιστής είναι σίγουρος ότι λείπει το ερωτηματικό. Επομένως, ο μεταγλωττιστής αναφέρει ότι το σφάλμα βρίσκεται στη γραμμή 8.
Μπορεί να υπάρχει μια σειρά από πιθανότητες διαφορετικών τύπων σφαλμάτων. Ας συζητήσουμε τη σύνδεση των μηνυμάτων σφάλματος. Τα σφάλματα σύνδεσης είναι σχετικά σπάνια και συνήθως προκύπτουν από ορθογραφικό λάθος του ονόματος μιας συνάρτησης βιβλιοθήκης C. Σε αυτήν την περίπτωση, λαμβάνετε ένα μήνυμα Σφάλμα: ακαθόριστα σύμβολα: μήνυμα σφάλματος, ακολουθούμενο από το ανορθόγραφο όνομα. Μόλις διορθώσετε την ορθογραφία, το πρόβλημα θα πρέπει να εξαφανιστεί.
Εκτύπωση αριθμών
Ας δούμε το ακόλουθο παράδειγμα:
// Πώς να εκτυπώσετε τους αριθμούς //
#include<stdio.h>
void main()
{
int num = 10;
printf(" Ο αριθμός είναι %d", num);
}
Η έξοδος του προγράμματος θα εμφανιστεί στην οθόνη ως εξής:
Ο αριθμός είναι 10
Το σύμβολο % χρησιμοποιείται για να σηματοδοτήσει την έξοδο πολλών διαφορετικών τύπων μεταβλητών. Ο χαρακτήρας που ακολουθεί το σύμβολο % είναι το ad, το οποίο σηματοδοτεί τη ρουτίνα εξόδου για να πάρει μια δεκαδική τιμή και να την εξάγει.
Χρήση μεταβλητών
Στο C, μια μεταβλητή πρέπει να δηλωθεί για να μπορέσει να χρησιμοποιηθεί. Οι μεταβλητές μπορούν να δηλωθούν στην αρχή οποιουδήποτε μπλοκ κώδικα, αλλά οι περισσότερες βρίσκονται στην αρχή κάθε συνάρτησης. Οι περισσότερες τοπικές μεταβλητές δημιουργούνται όταν καλείται η συνάρτηση και καταστρέφονται κατά την επιστροφή από αυτήν τη συνάρτηση.
Για να χρησιμοποιήσετε μεταβλητές στα προγράμματά σας C, πρέπει να γνωρίζετε τους ακόλουθους κανόνες όταν δίνετε το όνομα σε μεταβλητές στο C:
- Το όνομα μπορεί να περιέχει γράμματα, ψηφία και τον χαρακτήρα υπογράμμισης (_).
- Ο πρώτος χαρακτήρας του ονόματος πρέπει να είναι ένα γράμμα. Η υπογράμμιση είναι επίσης νομικός πρώτος χαρακτήρας, αλλά δεν συνιστάται η χρήση του.
- Το C κάνει διάκριση πεζών-κεφαλαίων, επομένως το όνομα της μεταβλητής num είναι Διαφορετικό από το Num.
- Οι λέξεις-κλειδιά C δεν μπορούν να χρησιμοποιηθούν ως ονόματα μεταβλητών. Μια λέξη-κλειδί είναι μια λέξη που αποτελεί μέρος της γλώσσας C.
Η ακόλουθη λίστα περιέχει μερικά παραδείγματα νόμιμων και παράνομων ονομάτων μεταβλητών C:
Όνομα μεταβλητής |
Νόμιμη ή όχι |
Σε ένα |
Νομικός |
Ttpt2_t2p |
Νομικός |
Tt pt |
Παράνομο: Δεν επιτρέπεται ο χώρος |
_1990_φόρος |
Νόμιμη αλλά δεν συνιστάται |
Jack_phone# |
Παράνομο: Περιέχει τον παράνομο χαρακτήρα # |
Περίπτωση |
Παράνομο: Είναι λέξη-κλειδί C |
1 βιβλίο |
Παράνομο: Ο πρώτος χαρακτήρας είναι ψηφίο |
Το πρώτο νέο πράγμα που ξεχωρίζει είναι η πρώτη γραμμή του σώματος του main():
int num = 10;
Αυτή η γραμμή ορίζει μια μεταβλητή με το όνομα 'num' τύπου int και την αρχικοποιεί με την τιμή 10. Αυτό μπορεί επίσης να έχει γραφτεί ως:
int num; /* ορισμός μη αρχικοποιημένης μεταβλητής 'num' */
/* και μετά από όλους τους ορισμούς μεταβλητών: */
αριθμός = 10; /* εκχωρεί τιμή 10 στη μεταβλητή 'num' */
Οι μεταβλητές μπορεί να ορίζονται στην αρχή ενός μπλοκ (ανάμεσα στις αγκύλες {και}), συνήθως αυτό είναι στην αρχή ενός σώματος συνάρτησης, αλλά μπορεί επίσης να είναι στην αρχή ενός άλλου τύπου μπλοκ.
Μεταβλητές που ορίζονται στην αρχή ενός μπλοκ από προεπιλογή στην «αυτόματη» κατάσταση. Αυτό σημαίνει ότι υπάρχουν μόνο κατά την εκτέλεση του μπλοκ. Όταν ξεκινήσει η εκτέλεση της συνάρτησης, οι μεταβλητές θα δημιουργηθούν αλλά το περιεχόμενό τους θα είναι απροσδιόριστο. Όταν επιστρέψει η συνάρτηση, οι μεταβλητές θα καταστραφούν. Ο ορισμός θα μπορούσε επίσης να γραφτεί ως εξής:
auto int num = 10;
Εφόσον ο ορισμός με ή χωρίς την αυτόματη λέξη-κλειδί είναι εντελώς ισοδύναμος, η αυτόματη λέξη-κλειδί είναι προφανώς μάλλον περιττή.
Ωστόσο, μερικές φορές αυτό δεν είναι αυτό που θέλετε. Ας υποθέσουμε ότι θέλετε μια συνάρτηση να μετράει πόσες φορές καλείται. Εάν η μεταβλητή καταστρέφεται κάθε φορά που επιστρέφει η συνάρτηση, αυτό δεν θα είναι δυνατό.
Επομένως, είναι δυνατό να δώσουμε στη μεταβλητή αυτό που ονομάζεται στατική διάρκεια, που σημαίνει ότι θα παραμείνει ανέπαφη καθ' όλη τη διάρκεια της εκτέλεσης του προγράμματος. Για παράδειγμα:
static int num = 10;
Αυτό αρχικοποιεί τη μεταβλητή num σε 10 στην αρχή της εκτέλεσης του προγράμματος. Από εκεί και πέρα η τιμή θα παραμείνει ανέγγιχτη. η μεταβλητή δεν θα αρχικοποιηθεί ξανά εάν η συνάρτηση κληθεί πολλές φορές.
Μερικές φορές δεν αρκεί να είναι προσβάσιμη η μεταβλητή μόνο από μία συνάρτηση ή μπορεί να μην είναι βολικό να μεταβιβαστεί η τιμή μέσω μιας παραμέτρου σε όλες τις άλλες συναρτήσεις που τη χρειάζονται.
Αλλά εάν χρειάζεστε πρόσβαση στη μεταβλητή από όλες τις συναρτήσεις σε ολόκληρο το αρχείο προέλευσης, αυτό μπορεί επίσης να γίνει με τη στατική λέξη-κλειδί, αλλά βάζοντας τον ορισμό εκτός όλων των συναρτήσεων. Για παράδειγμα:
#include <stdio.h>
static int num = 10; /* θα είναι προσβάσιμο από ολόκληρο το αρχείο προέλευσης */
int main (κενό)
{
printf("Ο αριθμός είναι: %d\n", num);
επιστροφή 0;
}
Και υπάρχουν επίσης περιπτώσεις όπου μια μεταβλητή πρέπει να είναι προσβάσιμη από ολόκληρο το πρόγραμμα, το οποίο μπορεί να αποτελείται από πολλά αρχεία προέλευσης. Αυτό ονομάζεται καθολική μεταβλητή και πρέπει να αποφεύγεται όταν δεν απαιτείται.
Αυτό γίνεται επίσης βάζοντας τον ορισμό εκτός όλων των συναρτήσεων, αλλά χωρίς τη χρήση της στατικής λέξης-κλειδιού:
#include <stdio.h>
int num = 10; /* θα είναι προσβάσιμο από ολόκληρο το πρόγραμμα! */
int main (κενό)
{
printf("Ο αριθμός είναι: %d\n", num);
επιστροφή 0;
}
Υπάρχει επίσης η εξωτερική λέξη-κλειδί, η οποία χρησιμοποιείται για την πρόσβαση σε καθολικές μεταβλητές σε άλλες ενότητες. Υπάρχουν επίσης μερικοί προσδιορισμοί που μπορείτε να προσθέσετε σε ορισμούς μεταβλητών. Το σημαντικότερο από αυτά είναι ο κ.στ. Μια μεταβλητή που ορίζεται ως const δεν μπορεί να τροποποιηθεί.
Υπάρχουν δύο ακόμη τροποποιητές που χρησιμοποιούνται λιγότερο συχνά. Ο τροποποιητής πτητικού και καταχωρητή. Ο πτητικός τροποποιητής απαιτεί από τον μεταγλωττιστή να έχει πραγματικά πρόσβαση στη μεταβλητή κάθε φορά που διαβάζεται. Μπορεί να μην βελτιστοποιήσει τη μεταβλητή τοποθετώντας την σε έναν καταχωρητή ή κάτι τέτοιο. Αυτό χρησιμοποιείται κυρίως για σκοπούς επεξεργασίας πολλαπλών νημάτων και διακοπής κ.λπ.
Ο τροποποιητής καταχωρητή ζητά από τον μεταγλωττιστή να βελτιστοποιήσει τη μεταβλητή σε έναν καταχωρητή. Αυτό είναι δυνατό μόνο με τις αυτόματες μεταβλητές και σε πολλές περιπτώσεις ο μεταγλωττιστής μπορεί να επιλέξει καλύτερα τις μεταβλητές για βελτιστοποίηση σε καταχωρητές, επομένως αυτή η λέξη-κλειδί είναι παρωχημένη. Η μόνη άμεση συνέπεια της δημιουργίας ενός καταχωρητή μεταβλητής είναι ότι δεν μπορεί να ληφθεί η διεύθυνσή του.
Ο πίνακας των μεταβλητών, που δίνεται στην επόμενη σελίδα, περιγράφει την κλάση αποθήκευσης πέντε τύπων κλάσεων αποθήκευσης.
Στον πίνακα βλέπουμε ότι η λέξη-κλειδί extern είναι τοποθετημένη σε δύο σειρές. Η εξωτερική λέξη-κλειδί χρησιμοποιείται σε συναρτήσεις για να δηλώσει μια στατική εξωτερική μεταβλητή που ορίζεται αλλού.
Αριθμητικοί τύποι μεταβλητών
Το C παρέχει πολλούς διαφορετικούς τύπους αριθμητικών μεταβλητών επειδή διαφορετικές αριθμητικές τιμές έχουν διαφορετικές απαιτήσεις αποθήκευσης μνήμης. Αυτοί οι αριθμητικοί τύποι διαφέρουν ως προς την ευκολία με την οποία μπορούν να εκτελεστούν ορισμένες μαθηματικές πράξεις σε αυτούς.
Οι μικροί ακέραιοι αριθμοί απαιτούν λιγότερη μνήμη για αποθήκευση και ο υπολογιστής σας μπορεί να εκτελέσει μαθηματικές πράξεις με τέτοιους αριθμούς πολύ γρήγορα. Οι μεγάλοι ακέραιοι αριθμοί και οι τιμές κινητής υποδιαστολής απαιτούν περισσότερο χώρο αποθήκευσης και περισσότερο χρόνο για μαθηματικές πράξεις. Χρησιμοποιώντας τους κατάλληλους τύπους μεταβλητών, διασφαλίζετε ότι το πρόγραμμά σας εκτελείται όσο το δυνατόν πιο αποτελεσματικά.
Οι αριθμητικές μεταβλητές του Γ εμπίπτουν στις ακόλουθες δύο κύριες κατηγορίες:
- Ακέραιες μεταβλητές
- Μεταβλητές κινητής υποδιαστολής
Σε καθεμία από αυτές τις κατηγορίες υπάρχουν δύο ή περισσότεροι συγκεκριμένοι τύποι μεταβλητών. Ο πίνακας που δίνεται στη συνέχεια δείχνει την ποσότητα της μνήμης, σε byte, που απαιτείται για τη διατήρηση μιας μεμονωμένης μεταβλητής κάθε τύπου.
Ο τύπος char μπορεί να είναι ισοδύναμος είτε με υπογεγραμμένο είτε με ανυπόγραφο, αλλά είναι πάντα ξεχωριστός τύπος από οποιοδήποτε από αυτά.
Στο C δεν υπάρχει διαφορά μεταξύ της αποθήκευσης χαρακτήρων ή των αντίστοιχων αριθμητικών τους τιμών σε μια μεταβλητή, επομένως δεν χρειάζεται επίσης να μετατραπεί μια συνάρτηση μεταξύ ενός χαρακτήρα και της αριθμητικής του τιμής ή το αντίστροφο. Για τους άλλους ακέραιους τύπους, εάν παραλείψετε υπογεγραμμένο ή ανυπόγραφο, η προεπιλογή θα υπογραφεί, οπότε π.χ. το int και το signed int είναι ισοδύναμα.
Ο τύπος int πρέπει να είναι μεγαλύτερος ή ίσος του τύπου short και μικρότερος ή ίσος του τύπου long. Εάν χρειάζεται απλώς να αποθηκεύσετε κάποιες τιμές που δεν είναι εξαιρετικά μεγάλες, είναι συχνά καλή ιδέα να χρησιμοποιήσετε τον τύπο int. είναι συνήθως το μέγεθος που μπορεί να αντιμετωπίσει ο επεξεργαστής το πιο εύκολο, και επομένως το πιο γρήγορο.
Με πολλούς μεταγλωττιστές το double και το long double είναι ισοδύναμα. Αυτό σε συνδυασμό με το γεγονός ότι οι περισσότερες τυπικές μαθηματικές συναρτήσεις λειτουργούν με τον τύπο διπλό, είναι ένας καλός λόγος για να χρησιμοποιείτε πάντα τον τύπο διπλό εάν πρέπει να εργαστείτε με κλασματικούς αριθμούς.
Ο παρακάτω πίνακας είναι για να περιγράψει καλύτερα τους τύπους μεταβλητών:
Τύποι ειδικού σκοπού που χρησιμοποιούνται συνήθως:
Τύπος μεταβλητής |
Περιγραφή |
μέγεθος_t |
ανυπόγραφος τύπος που χρησιμοποιείται για την αποθήκευση των μεγεθών των αντικειμένων σε byte |
time_t |
χρησιμοποιείται για την αποθήκευση των αποτελεσμάτων της συνάρτησης time(). |
clock_t |
χρησιμοποιείται για την αποθήκευση των αποτελεσμάτων της συνάρτησης clock(). |
ΑΡΧΕΙΟ |
χρησιμοποιείται για πρόσβαση σε ροή (συνήθως αρχείο ή συσκευή) |
ptrdiff_t |
υπογεγραμμένος τύπος διαφοράς μεταξύ 2 δεικτών |
div_t |
χρησιμοποιείται για την αποθήκευση των αποτελεσμάτων της συνάρτησης div(). |
ldiv_t |
χρησιμοποιείται για την αποθήκευση των αποτελεσμάτων της συνάρτησης ldiv(). |
fpos_t |
χρησιμοποιείται για τη διατήρηση πληροφοριών θέσης αρχείου |
will_list |
χρησιμοποιείται στον χειρισμό μεταβλητών ορισμών |
wchar_t |
ευρύς τύπος χαρακτήρων (χρησιμοποιείται για εκτεταμένα σύνολα χαρακτήρων) |
sig_atomic_t |
χρησιμοποιείται σε χειριστές σήματος |
Jmp_buf |
χρησιμοποιείται για μη τοπικά άλματα |
Για να κατανοήσουμε καλύτερα αυτές τις μεταβλητές, ας πάρουμε ένα παράδειγμα:
/* Πρόγραμμα για να πει το εύρος και το μέγεθος σε byte της μεταβλητής C */
#include <stdio.h>
int main()
{
int a? /* απλός ακέραιος τύπος */
long int b? /* μακρύς ακέραιος τύπος */
σύντομη int c; /* σύντομος ακέραιος τύπος */
ανυπόγραφο int d? /* ανυπόγραφος ακέραιος τύπος */
χαρ ε? /* τύπος χαρακτήρων */
float f; /* τύπος κινητής υποδιαστολής */
διπλό g? /* κινητή υποδιαστολή διπλής ακρίβειας */
a = 1023;
b = 2222;
c = 123;
d = 1234;
e = 'X';
f = 3,14159;
g = 3,1415926535898;
printf( "\nΈνας χαρακτήρας είναι %d byte", sizeof( char ));
printf( "\nΈνα int είναι %d bytes", sizeof( int ));
printf( "\nΤο short είναι %d bytes", sizeof( short ));
printf( "\nΤο μήκος είναι %d byte", sizeof( long ));
printf( "\nΈνας ανυπόγραφος χαρακτήρας είναι %d byte",
sizeof( ανυπόγραφο char ));
printf( "\nΈνα ανυπόγραφο int είναι %d byte",
sizeof( unsigned int ));
printf( "\nΈνα ανυπόγραφο short είναι %d byte",
sizeof( ανυπόγραφο σύντομο ));
printf( "\nΈνα μη υπογεγραμμένο μήκος είναι %d byte",
sizeof( ανυπόγραφο μακρύ ));
printf( "\nΈνα float είναι %d byte", sizeof( float ));
printf( "\nΈνα διπλό είναι %d bytes\n", sizeof( double ));
printf("a = %d\n", a); /* δεκαδική έξοδο */
printf("a = %o\n", a); /* οκταδική έξοδος */
printf("a = %x\n", a); /* δεκαεξαδική έξοδο */
printf("b = %ld\n", b); /* δεκαδική μεγάλη έξοδο */
printf("c = %d\n", c); /* δεκαδική σύντομη έξοδος */
printf("d = %u\n", d); /* ανυπόγραφη έξοδος */
printf("e = %c\n", e); /* έξοδος χαρακτήρων */
printf("f = %f\n", f); /* κυμαινόμενη έξοδος */
printf("g = %f\n", g); /* έξοδος διπλού πλωτήρα */
printf("\n");
printf("a = %d\n", a); /* απλή έξοδος εισόδου */
printf("a = %7d\n", a); /* χρησιμοποιήστε πλάτος πεδίου 7 */
printf("a = %-7d\n", a); /* αριστερά δικαιολογώ μέσα
πεδίο 7 */
c = 5;
d = 8;
printf("a = %*d\n", c, a); /* χρησιμοποιήστε πλάτος πεδίου 5*/
printf("a = %*d\n", d, a); /* χρησιμοποιήστε πλάτος πεδίου 8 */
printf("\n");
printf("f = %f\n", f); /* απλή έξοδος float */
printf("f = %12f\n", f); /* χρησιμοποιήστε πλάτος πεδίου 12 */
printf("f = %12.3f\n", f); /* χρησιμοποιήστε 3 δεκαδικά ψηφία */
printf("f = %12,5f\n", f); /* χρησιμοποιήστε 5 δεκαδικά ψηφία */
printf("f = %-12,5f\n", f); /* αριστερά δικαιολογείται στο πεδίο */
επιστροφή 0;
}
Το αποτέλεσμα του προγράμματος μετά την εκτέλεση θα εμφανίζεται ως:
Ένας χαρακτήρες είναι 1 byte
Το int είναι 2 byte
Το short είναι 2 byte
Το μήκος είναι 4 byte
Ένας ανυπόγραφος χαρακτήρας είναι 1 byte
Ένα ανυπόγραφο int είναι 2 byte
Ένα ανυπόγραφο short είναι 2 byte
Ένα ανυπόγραφο μήκος είναι 4 byte
Ένας πλωτήρας είναι 4 byte
Ένα διπλό είναι 8 byte
a = 1023
a = 1777
α = 3 επ
b = 2222
c = 123
d = 1234
e = Χ
f = 3,141590
g = 3,141593
a = 1023
a = 1023
a = 1023
a = 1023
a = 1023
f = 3,141590
f = 3,141590
f = 3,142
f = 3,14159
f = 3,14159 |
Πριν από τη χρήση της, μια μεταβλητή σε ένα πρόγραμμα C, πρέπει να δηλωθεί. Μια δήλωση μεταβλητής λέει στον μεταγλωττιστή το όνομα και τον τύπο μιας μεταβλητής και προαιρετικά αρχικοποιεί τη μεταβλητή σε μια συγκεκριμένη τιμή.
Εάν το πρόγραμμά σας επιχειρήσει να χρησιμοποιήσει μια μεταβλητή που δεν έχει δηλωθεί, ο μεταγλωττιστής δημιουργεί ένα μήνυμα σφάλματος. Μια δήλωση μεταβλητής έχει την ακόλουθη μορφή:
typename varname;
typename καθορίζει τον τύπο της μεταβλητής και πρέπει να είναι μία από τις λέξεις-κλειδιά. varname είναι το όνομα της μεταβλητής. Μπορείτε να δηλώσετε πολλές μεταβλητές του ίδιου τύπου σε μία γραμμή διαχωρίζοντας τα ονόματα των μεταβλητών με κόμματα:
int count, αριθμός, start? /* τρεις ακέραιες μεταβλητές */
float ποσοστό, σύνολο? /* δύο float μεταβλητές */
Η λέξη-κλειδί typedef
Η λέξη-κλειδί typedef χρησιμοποιείται για τη δημιουργία νέου ονόματος για έναν υπάρχοντα τύπο δεδομένων. Στην πραγματικότητα, το typedef δημιουργεί ένα συνώνυμο. Για παράδειγμα, η δήλωση
typedef int ακέραιος αριθμός;
εδώ βλέπουμε το typedef δημιουργεί ακέραιο ως συνώνυμο του int. Στη συνέχεια, μπορείτε να χρησιμοποιήσετε ακέραιο αριθμό για να ορίσετε μεταβλητές τύπου int, όπως σε αυτό το παράδειγμα:
ακέραιος αριθμός?
Επομένως, το typedef δεν δημιουργεί νέο τύπο δεδομένων, σας επιτρέπει μόνο να χρησιμοποιήσετε ένα διαφορετικό όνομα για έναν προκαθορισμένο τύπο δεδομένων.
Αρχικοποίηση αριθμητικών μεταβλητών
Όταν δηλώνεται οποιαδήποτε μεταβλητή, ο μεταγλωττιστής λαμβάνει εντολή να αφήσει κατά μέρος χώρο αποθήκευσης για τη μεταβλητή. Ωστόσο, η τιμή που είναι αποθηκευμένη σε αυτό το διάστημα, η τιμή της μεταβλητής, δεν ορίζεται. Μπορεί να είναι μηδέν ή μπορεί να είναι κάποια τυχαία τιμή "σκουπίδια". Πριν χρησιμοποιήσετε μια μεταβλητή, θα πρέπει πάντα να την αρχικοποιείτε σε μια γνωστή τιμή. Ας πάρουμε αυτό το παράδειγμα:
int count? /* Αφιερώστε χώρο αποθήκευσης για μέτρηση */
καταμέτρηση = 0; /* Αποθήκευση 0 σε αριθμό */
Αυτή η δήλωση χρησιμοποιεί το σύμβολο ίσου (=), το οποίο είναι ο τελεστής εκχώρησης του C. Μπορείτε επίσης να αρχικοποιήσετε μια μεταβλητή όταν δηλωθεί. Για να το κάνετε αυτό, ακολουθήστε το όνομα της μεταβλητής στη δήλωση δήλωσης με σύμβολο ίσου και την επιθυμητή αρχική τιμή:
int count = 0;
διπλός ρυθμός = 0,01, πολυπλοκότητα = 28,5;
Προσέξτε να μην αρχικοποιήσετε μια μεταβλητή με τιμή εκτός του επιτρεπόμενου εύρους. Ακολουθούν δύο παραδείγματα αρχικοποιήσεων εκτός εύρους:
int ποσό = 100000;
ανυπόγραφο μήκος int = -2500;
Ο μεταγλωττιστής C δεν εντοπίζει τέτοια σφάλματα. Το πρόγραμμά σας μπορεί να μεταγλωττιστεί και να συνδεθεί, αλλά μπορεί να λάβετε απροσδόκητα αποτελέσματα όταν εκτελείται το πρόγραμμα.
Ας πάρουμε το ακόλουθο παράδειγμα για να υπολογίσουμε τον συνολικό αριθμό τομέων σε έναν δίσκο:
// Μοντέλο προγράμματος για τον υπολογισμό τομέων σε δίσκο //
#include<stdio.h>
#define SECTOR_PER_SIDE 63
#define SIDE_PER_CYLINDER 254
void main()
{
int κύλινδρος=0;
clrscr();
printf("Εισαγάγετε τον αριθμό κυλίνδρων στο δίσκο \n\n\t");
scanf("%d",&cylinder); // Λάβετε την τιμή από τον χρήστη //
printf("\n\n\t Συνολικός αριθμός τομέων στο δίσκο = %ld", (μακρύς)SECTOR_PER_SIDE*SIDE_PER_CYLINDER* κύλινδρος);
getch();
}
Η έξοδος του προγράμματος είναι η εξής:
Εισαγάγετε τον αριθμό των κυλίνδρων στο δίσκο
1024
Συνολικός αριθμός τομέων στο δίσκο = 16386048
Σε αυτό το παράδειγμα βλέπουμε τρία νέα πράγματα να μάθουμε. Το #define χρησιμοποιείται για τη χρήση συμβολικών σταθερών στο πρόγραμμα ή σε ορισμένες περιπτώσεις για εξοικονόμηση χρόνου ορίζοντας μεγάλες λέξεις σε μικρά σύμβολα.
Εδώ έχουμε ορίσει τον αριθμό των τομέων ανά πλευρά που είναι 63 ως SECTOR_PER_SIDE για να γίνει το πρόγραμμα εύκολο στην κατανόηση. Η ίδια περίπτωση ισχύει για το #define SIDE_PER_CYLINDER 254. Η scanf() χρησιμοποιείται για τη λήψη της εισόδου από τον χρήστη.
Εδώ παίρνουμε τον αριθμό των κυλίνδρων ως είσοδο από τον χρήστη. * χρησιμοποιείται για τον πολλαπλασιασμό δύο ή περισσότερων τιμών όπως φαίνεται στο παράδειγμα.
Η συνάρτηση getch() λαμβάνει βασικά μια είσοδο χαρακτήρων από το πληκτρολόγιο. Πληκτρολογώντας getch(); εδώ σταματάμε την οθόνη μέχρι να πατηθεί οποιοδήποτε πλήκτρο από το πληκτρολόγιο.
χειριστές
Ένας τελεστής είναι ένα σύμβολο που δίνει εντολή στο C να εκτελέσει κάποια λειτουργία ή ενέργεια σε έναν ή περισσότερους τελεστές. Ο τελεστής είναι κάτι στο οποίο ενεργεί ένας τελεστής. Στο C, όλοι οι τελεστές είναι εκφράσεις. Οι τελεστές C χωρίζονται στις ακόλουθες τέσσερις κατηγορίες:
- Ο χειριστής ανάθεσης
- Μαθηματικοί τελεστές
- Σχεσιακούς τελεστές
- Λογικοί τελεστές
Χειριστής ανάθεσης
Ο τελεστής εκχώρησης είναι το σύμβολο ίσου (=). Η χρήση του ίσου στον προγραμματισμό είναι διαφορετική από τη χρήση του σε κανονικές μαθηματικές αλγεβρικές σχέσεις. Αν γράφεις
x = y;
Σε ένα πρόγραμμα C, δεν σημαίνει ότι το x είναι ίσο με το y. Αντίθετα, σημαίνει "εκχωρήστε την τιμή του y στο x." Σε μια δήλωση εκχώρησης C, η δεξιά πλευρά μπορεί να είναι οποιαδήποτε έκφραση και η αριστερή πλευρά πρέπει να είναι ένα όνομα μεταβλητής. Έτσι, το έντυπο έχει ως εξής:
μεταβλητή = έκφραση;
Κατά τη διάρκεια της εκτέλεσης, η έκφραση αξιολογείται και η τιμή που προκύπτει εκχωρείται στη μεταβλητή.
Μαθηματικοί τελεστές
Οι μαθηματικοί τελεστές του C εκτελούν μαθηματικές πράξεις όπως πρόσθεση και αφαίρεση. Το C έχει δύο μονομερείς μαθηματικούς τελεστές και πέντε δυαδικούς μαθηματικούς τελεστές. Οι μοναδικοί μαθηματικοί τελεστές ονομάζονται έτσι επειδή παίρνουν έναν μόνο τελεστή. Το C έχει δύο μαθηματικούς τελεστές.
Οι τελεστές αύξησης και μείωσης μπορούν να χρησιμοποιηθούν μόνο με μεταβλητές, όχι με σταθερές. Η λειτουργία που εκτελείται είναι να προσθέσουμε ένα ή να αφαιρέσουμε ένα από τον τελεστή. Με άλλα λόγια, οι δηλώσεις ++x; και --y; είναι τα ισοδύναμα αυτών των δηλώσεων:
x = x + 1;
y = y - 1;
Οι δυαδικοί μαθηματικοί τελεστές παίρνουν δύο τελεστές. Οι πρώτοι τέσσερις δυαδικοί τελεστές, οι οποίοι περιλαμβάνουν τις κοινές μαθηματικές πράξεις που βρίσκονται σε μια αριθμομηχανή (+, -, *, /), είναι γνωστοί σε εσάς. Ο πέμπτος τελεστής Modulus επιστρέφει το υπόλοιπο όταν ο πρώτος τελεστής διαιρεθεί με τον δεύτερο τελεστή. Για παράδειγμα, 11 συντελεστής 4 ισούται με 3 (το 11 διαιρείται με το 4, δύο φορές και το 3 έχει περισσέψει).
Σχέσιοι χειριστές
Οι σχεσιακοί τελεστές του C χρησιμοποιούνται για τη σύγκριση παραστάσεων. Μια έκφραση που περιέχει έναν σχεσιακό τελεστή αξιολογείται είτε ως true (1) είτε ως false (0). Το C έχει έξι σχεσιακούς τελεστές.
Λογικοί τελεστές
Οι λογικοί τελεστές του C σάς επιτρέπουν να συνδυάσετε δύο ή περισσότερες σχεσιακές εκφράσεις σε μια ενιαία έκφραση που αξιολογείται είτε ως true είτε ως false. Οι λογικοί τελεστές αξιολογούν είτε ως true είτε ως false, ανάλογα με την true ή false τιμή των τελεστών τους.
Εάν το x είναι μια ακέραια μεταβλητή, οι εκφράσεις που χρησιμοποιούν λογικούς τελεστές θα μπορούσαν να γραφτούν με τους ακόλουθους τρόπους:
(x > 1) && (x < 5)
(x >= 2) && (x <= 4)
Χειριστής |
Σύμβολο |
Περιγραφή |
Παράδειγμα |
Χειριστές ανάθεσης |
ίσος |
= |
αντιστοιχίστε την τιμή του y στο x |
x = y |
Μαθηματικοί τελεστές |
Αύξηση |
++ |
Αυξάνει τον τελεστή κατά ένα |
++x, x++ |
Μείωση |
-- |
Μειώνει τον τελεστή κατά ένα |
--x, x-- |
Πρόσθεση |
+ |
Προσθέτει δύο τελεστές |
x + y |
Αφαίρεση |
- |
Αφαιρεί τον δεύτερο τελεστή από τον πρώτο |
x - y |
Πολλαπλασιασμός |
* |
Πολλαπλασιάζει δύο τελεστές |
x * y |
Διαίρεση |
/ |
Διαιρεί τον πρώτο τελεστή με τον δεύτερο τελεστή |
x / y |
Modulus |
% |
Δίνει το υπόλοιπο όταν ο πρώτος τελεστής διαιρείται με τον δεύτερο τελεστή |
x % και |
Σχεσιακούς τελεστές |
Ισος |
= = |
Ισότητα |
x = = y |
Μεγαλύτερο από |
> |
Μεγαλύτερο από |
x > y |
Λιγότερο από |
< |
Λιγότερο από |
x < y |
Μεγαλύτερο ή ίσο με |
>= |
Μεγαλύτερο ή ίσο με |
x >= y |
Μικρότερο ή ίσο με |
<= |
Μικρότερο ή ίσο με |
x <= y |
Όχι ίσα |
!= |
Όχι ίσο με |
x != y |
Λογικοί τελεστές |
ΚΑΙ |
&& |
Αληθές (1) μόνο εάν και οι δύο exp1 και exp2 είναι αληθείς. ψευδής (0) διαφορετικά |
exp1 && exp2 |
Ή |
|| |
Σωστό (1) εάν είτε exp1 είτε exp2 είναι αληθές. false (0) μόνο αν και τα δύο είναι ψευδή |
exp1 || exp2 |
ΔΕΝ |
! |
Λάθος (0) εάν το exp1 είναι αληθές. true (1) αν το exp1 είναι false |
!exp1 |
Πράγματα που πρέπει να θυμάστε σχετικά με τις λογικές εκφράσεις
x * = y |
είναι το ίδιο με |
x = x * y |
y - = z + 1 |
είναι το ίδιο με |
y = y - z + 1 |
α / = β |
είναι το ίδιο με |
a = a / b |
x + = y / 8 |
είναι το ίδιο με |
x = x + y / 8 |
και % = 3 |
είναι το ίδιο με |
y = y % 3 |
Ο χειριστής κόμματος
Το κόμμα χρησιμοποιείται συχνά στο C ως απλό σημείο στίξης, για να διαχωρίσει δηλώσεις μεταβλητών, ορίσματα συναρτήσεων κ.λπ. Σε ορισμένες περιπτώσεις, το κόμμα λειτουργεί ως τελεστής.
Μπορείτε να σχηματίσετε μια έκφραση διαχωρίζοντας δύο δευτερεύουσες εκφράσεις με κόμμα. Το αποτέλεσμα είναι το εξής:
- Και οι δύο εκφράσεις αξιολογούνται, με την αριστερή έκφραση να αξιολογείται πρώτη.
- Ολόκληρη η έκφραση αξιολογείται στην τιμή της σωστής έκφρασης.
Για παράδειγμα, η ακόλουθη πρόταση εκχωρεί την τιμή του b στο x, μετά αυξάνει το a και μετά αυξάνει το b: x = (a++, b++);
Προτεραιότητα τελεστή C (Σύνοψη τελεστών C)
Βαθμολογία και Συνεταιρισμός |
χειριστές |
1 (από αριστερά προς τα δεξιά) |
() [] -> . |
2 (δεξιά προς τα αριστερά) |
! ~ ++ -- * (indirection) & (address-of) (type) sizeof + (unary) - (unary) |
3 (από αριστερά προς τα δεξιά) |
* (πολλαπλασιασμός) / % |
4 (από αριστερά προς τα δεξιά) |
+ - |
5 (από αριστερά προς τα δεξιά) |
<< >> |
6 (από αριστερά προς τα δεξιά) |
<<= > >= |
7 (από αριστερά προς τα δεξιά) |
= = != |
8 (από αριστερά προς τα δεξιά) |
& (κατά bit AND ) |
9 (από αριστερά προς τα δεξιά) |
^ |
10 (από αριστερά προς τα δεξιά) |
| |
11 (από αριστερά προς τα δεξιά) |
&& |
12 (από αριστερά προς τα δεξιά) |
|| |
13 (δεξιά προς τα αριστερά) |
?: |
14 (δεξιά προς τα αριστερά) |
= += -= *= /= %= &= ^= |= <<= >>= |
15 (από αριστερά προς τα δεξιά) |
, |
() είναι ο τελεστής συνάρτησης. Το [] είναι ο τελεστής πίνακα. |
|
Ας πάρουμε ένα παράδειγμα χρήσης τελεστών:
/* Χρήση χειριστών */
int main()
{
int x = 0, y = 2, z = 1025;
float a = 0,0, b = 3,14159, c = -37,234;
/* αύξηση */
x = x + 1; /* Αυτό προσαυξάνεται x */
x++; /* Αυτό προσαυξάνεται x */
++x; /* Αυτό προσαυξάνεται x */
z = y++; /* z = 2, y = 3 */
z = ++y; /* z = 4, y = 4 */
/* φθίνουσα */
y = y - 1; /* Αυτό μειώνει το y */
y--; /* Αυτό μειώνει το y */
--y; /* Αυτό μειώνει το y */
y = 3;
z = y--; /* z = 3, y = 2 */
z = --y; /* z = 1, y = 1 */
/* αριθμητική op */
a = a + 12; /* Αυτό προσθέτει 12 σε ένα */
a += 12; /* Αυτό προσθέτει 12 ακόμη σε ένα */
a *= 3,2; /* Αυτό πολλαπλασιάζει το a επί 3,2 */
a -= b; /* Αυτό αφαιρεί το b από ένα */
a /= 10,0; /* Αυτό διαιρεί ένα με 10,0 */
/* έκφραση υπό όρους */
a = (b >= 3,0 ? 2,0 : 10,5 ); /* Αυτή η έκφραση */
if (b >= 3.0) /* Και αυτή η έκφραση */
a = 2,0; /* είναι πανομοιότυπα, και τα δύο */
αλλιώς /* θα προκαλέσει το ίδιο */
a = 10,5; /* αποτέλεσμα. */
c = (a > b ? a : b); /* c θα έχει το μέγιστο a ή b */
c = (a > b ? b : a); /* c θα έχει το min του a ή b */
printf("x=%d, y=%d, z= %d\n", x, y, z);
printf("a=%f, b=%f, c= %f", a, b, c);
επιστροφή 0;
}
και το αποτέλεσμα αυτού του προγράμματος θα εμφανιστεί στην οθόνη ως:
x=3, y=1, z=1
a=2,000000, b=3,141590, c=2,000000
Κάτι περισσότερο για τα printf() και Scanf()
Εξετάστε τις ακόλουθες δύο προτάσεις printf
printf(“\t %d\n”, num);
printf(“%5.2f”, κλάσμα);
Στην πρώτη πρόταση printf \t ζητά τη μετατόπιση της καρτέλας στην οθόνη, το όρισμα %d λέει στον μεταγλωττιστή ότι η τιμή του num πρέπει να εκτυπωθεί ως δεκαδικός ακέραιος. \n προκαλεί την έναρξη της νέας εξόδου από νέα γραμμή.
Στη δεύτερη πρόταση printf το %5.2f λέει στον μεταγλωττιστή ότι η έξοδος πρέπει να είναι σε κινητή υποδιαστολή, με πέντε θέσεις σε όλες και δύο θέσεις στα δεξιά της υποδιαστολής. Περισσότερα για τον χαρακτήρα ανάστροφης κάθετο παρουσιάζονται στον παρακάτω πίνακα:
Συνεχής |
Εννοια |
'\ένα' |
Ηχητική ειδοποίηση (καμπάνα) |
'\σι' |
Backspace |
'\φά' |
Τροφοδοσία φόρμας |
'\n' |
Νέα γραμμή |
'\r' |
Επιστροφή άμαξα |
'\ t' |
Οριζόντια καρτέλα |
'\v' |
Κάθετη καρτέλα |
'\' |
Μονό απόσπασμα |
'\"' |
Διπλό απόσπασμα |
'\?' |
Ερωτηματικό |
'\\' |
Πίσω κάθετο |
'\0' |
Ακυρος |
Ας εξετάσουμε την ακόλουθη δήλωση scanf
scanf("%d", &num);
Τα δεδομένα από το πληκτρολόγιο λαμβάνονται με τη λειτουργία σάρωσης. Στην παραπάνω μορφή, το σύμβολο & (συμπερασματικό) πριν από κάθε όνομα μεταβλητής είναι ένας τελεστής που καθορίζει τη διεύθυνση του ονόματος της μεταβλητής.
Κάνοντας αυτό, η εκτέλεση σταματά και περιμένει να πληκτρολογηθεί η τιμή της μεταβλητής num. Όταν εισαχθεί η ακέραια τιμή και πατηθεί το κλειδί επιστροφής, ο υπολογιστής προχωρά στην επόμενη δήλωση. Οι κωδικοί μορφής scanf και printf παρατίθενται στον ακόλουθο πίνακα:
Κώδικας |
Διαβάζει... |
%ντο |
Μονός χαρακτήρας |
%ρε |
Δεκαδικός ακέραιος αριθμός |
%και |
Τιμή κινητής υποδιαστολής |
%φά |
Τιμή κινητής υποδιαστολής |
%σολ |
Τιμή κινητής υποδιαστολής |
%h |
Σύντομος ακέραιος |
%εγώ |
Δεκαδικός, δεκαεξαδικός ή οκταδικός ακέραιος |
%ο |
Οκταδικός ακέραιος αριθμός |
%μικρό |
Σειρά |
%σε |
Ανυπόγραφος δεκαδικός ακέραιος |
%x |
Δεκαεξαδικός ακέραιος |
Δηλώσεις ελέγχου
Ένα πρόγραμμα αποτελείται από έναν αριθμό εντολών που συνήθως εκτελούνται με τη σειρά. Τα προγράμματα μπορεί να είναι πολύ πιο ισχυρά εάν μπορούμε να ελέγξουμε τη σειρά με την οποία εκτελούνται οι δηλώσεις.
Οι δηλώσεις χωρίζονται σε τρεις γενικούς τύπους:
- Εκχώρηση, όπου οι τιμές, συνήθως τα αποτελέσματα των υπολογισμών, αποθηκεύονται σε μεταβλητές.
- Είσοδος / Έξοδος, τα δεδομένα διαβάζονται ή εκτυπώνονται.
- Έλεγχος, το πρόγραμμα αποφασίζει για το τι θα κάνει στη συνέχεια.
Αυτή η ενότητα θα συζητήσει τη χρήση εντολών ελέγχου στο C. Θα δείξουμε πώς μπορούν να χρησιμοποιηθούν για τη σύνταξη ισχυρών προγραμμάτων από:
- Επανάληψη σημαντικών ενοτήτων του προγράμματος.
- Επιλογή μεταξύ προαιρετικών ενοτήτων ενός προγράμματος.
Η δήλωση αν αλλιώς
Αυτό χρησιμοποιείται για να αποφασίσετε εάν θα κάνετε κάτι σε ένα ειδικό σημείο ή για να αποφασίσετε μεταξύ δύο τρόπων δράσης.
Το παρακάτω τεστ αποφασίζει εάν ένας μαθητής έχει περάσει εξετάσεις με βαθμολογία επιτυχίας 45
εάν (αποτέλεσμα >= 45)
printf("Pass\n");
αλλού
printf("Αποτυχία\n");
Είναι δυνατή η χρήση του ανταλλακτικού χωρίς το άλλο.
εάν (θερμοκρασία < 0)
print("Frozen\n");
Κάθε έκδοση αποτελείται από μια δοκιμή, στην πρόταση που βρίσκεται σε αγκύλες μετά το if. Εάν το τεστ είναι αληθές τότε τηρείται η επόμενη πρόταση. Εάν είναι ψευδής, τότε η δήλωση που ακολουθεί την άλλη τηρείται εάν υπάρχει. Μετά από αυτό, το υπόλοιπο πρόγραμμα συνεχίζεται κανονικά.
Εάν επιθυμούμε να έχουμε περισσότερες από μία εντολές μετά το αν ή το άλλο, θα πρέπει να ομαδοποιηθούν μεταξύ των αγκύλων. Μια τέτοια ομαδοποίηση ονομάζεται σύνθετη πρόταση ή μπλοκ.
εάν (αποτέλεσμα >= 45)
{ printf("Πέρασε\n");
printf("Συγχαρητήρια\n");
}
αλλού
{ printf("Αποτυχία\n");
printf("Καλύτερη τύχη την επόμενη φορά\n");
}
Μερικές φορές επιθυμούμε να πάρουμε μια πολύπλευρη απόφαση με βάση πολλές προϋποθέσεις. Ο πιο γενικός τρόπος για να γίνει αυτό είναι χρησιμοποιώντας την παραλλαγή else if στη δήλωση if.
Αυτό λειτουργεί με καταρράκτη αρκετές συγκρίσεις. Μόλις ένα από αυτά δώσει ένα αληθινό αποτέλεσμα, εκτελείται η ακόλουθη πρόταση ή μπλοκ και δεν πραγματοποιούνται περαιτέρω συγκρίσεις. Στο παρακάτω παράδειγμα απονέμουμε βαθμούς ανάλογα με το αποτέλεσμα της εξέτασης.
εάν (αποτέλεσμα <=100 && αποτέλεσμα >= 75)
printf("Επιτυχία: Βαθμός A\n");
αλλιώς εάν (αποτέλεσμα >= 60)
printf("Επιτυχία: Βαθμός Β\n");
αλλιώς εάν (αποτέλεσμα >= 45)
printf("Επιτυχία: Βαθμός C\n");
αλλού
printf("Αποτυχία\n");
Σε αυτό το παράδειγμα, όλες οι συγκρίσεις δοκιμάζουν μια μεμονωμένη μεταβλητή που ονομάζεται αποτέλεσμα. Σε άλλες περιπτώσεις, κάθε δοκιμή μπορεί να περιλαμβάνει διαφορετική μεταβλητή ή κάποιο συνδυασμό δοκιμών. Το ίδιο μοτίβο μπορεί να χρησιμοποιηθεί με περισσότερα ή λιγότερα άλλα αν και το τελικό μόνο άλλο μπορεί να μείνει έξω.
Εναπόκειται στον προγραμματιστή να επινοήσει τη σωστή δομή για κάθε πρόβλημα προγραμματισμού. Για να κατανοήσουμε καλύτερα τη χρήση του if else ας δούμε το παράδειγμα
#include <stdio.h>
int main()
{
int num;
for(αριθμός = 0, αριθμός < 10, αριθμός = αριθμός + 1)
{
αν (αριθμός == 2)
printf("num είναι τώρα ίσο με %d\n", num);
εάν (αριθμός < 5)
printf("num είναι τώρα %d, που είναι μικρότερο από 5\n", num);
αλλού
printf("num είναι τώρα %d, που είναι μεγαλύτερο από 4\n", num);
} /* τέλος του βρόχου for */
επιστροφή 0;
}
Αποτέλεσμα του προγράμματος
Το num είναι τώρα 0, το οποίο είναι μικρότερο από 5
Το num είναι τώρα 1, το οποίο είναι μικρότερο από 5
Το num είναι τώρα ίσο με 2
Το num είναι τώρα 2, το οποίο είναι μικρότερο από 5
Το num είναι τώρα 3, που είναι μικρότερο από 5
Το num είναι τώρα 4, που είναι μικρότερο από 5
Το num είναι τώρα 5, το οποίο είναι μεγαλύτερο από 4
Το num είναι τώρα 6, που είναι μεγαλύτερο από 4
Το num είναι τώρα 7, που είναι μεγαλύτερο από 4
Το num είναι τώρα 8, που είναι μεγαλύτερο από 4
Το num είναι τώρα 9, που είναι μεγαλύτερο από 4
Η δήλωση διακόπτη
Αυτή είναι μια άλλη μορφή απόφασης πολλαπλών δρόμων. Είναι καλά δομημένο, αλλά μπορεί να χρησιμοποιηθεί μόνο σε ορισμένες περιπτώσεις όπου:
- Μόνο μία μεταβλητή ελέγχεται, όλοι οι κλάδοι πρέπει να εξαρτώνται από την τιμή αυτής της μεταβλητής. Η μεταβλητή πρέπει να είναι ακέραιος τύπος. (in, long, short ή char).
- Κάθε πιθανή τιμή της μεταβλητής μπορεί να ελέγξει έναν κλάδο. Ένας τελικός, προεπιλεγμένος κλάδος catch all, μπορεί προαιρετικά να χρησιμοποιηθεί για την παγίδευση όλων των απροσδιόριστων περιπτώσεων.
Το παράδειγμα που δίνεται παρακάτω θα ξεκαθαρίσει τα πράγματα. Αυτή είναι μια συνάρτηση που μετατρέπει έναν ακέραιο σε μια ασαφή περιγραφή. Είναι χρήσιμο όταν μας απασχολεί μόνο η μέτρηση μιας ποσότητας όταν είναι αρκετά μικρή.
εκτίμηση (αριθμός)
αριθμός int?
/* Υπολογίστε έναν αριθμό ως κανένας, ένα, δύο, πολλά, πολλά */
{ διακόπτης(αριθμός) {
περίπτωση 0:
printf("Κανένα\n");
διακοπή;
περίπτωση 1:
printf("One\n");
διακοπή;
περίπτωση 2:
printf("Two\n");
διακοπή;
περίπτωση 3:
περίπτωση 4:
περίπτωση 5:
printf("Several\n");
διακοπή;
προεπιλογή:
printf("Πολλά\n");
διακοπή;
}
}
Κάθε ενδιαφέρουσα περίπτωση παρατίθεται με μια αντίστοιχη ενέργεια. Η εντολή break αποτρέπει την εκτέλεση περαιτέρω εντολών αφήνοντας το διακόπτη. Εφόσον η περίπτωση 3 και η περίπτωση 4 δεν έχουν επόμενο διάλειμμα, συνεχίζουν να επιτρέπουν την ίδια ενέργεια για πολλές τιμές αριθμού.
Και οι δύο κατασκευές if και switch επιτρέπουν στον προγραμματιστή να κάνει μια επιλογή από έναν αριθμό πιθανών ενεργειών. Ας δούμε ένα παράδειγμα:
#include <stdio.h>
int main()
{
int num;
για (αριθμός = 3, αριθμός < 13, αριθμός = αριθμός + 1)
{
διακόπτης (αριθμός)
{
περίπτωση 3:
printf("Η τιμή είναι τρία\n");
διακοπή;
περίπτωση 4:
printf("Η τιμή είναι τέσσερα\n");
διακοπή;
περίπτωση 5:
περίπτωση 6:
περίπτωση 7:
περίπτωση 8:
printf("Η τιμή είναι μεταξύ 5 και 8\n");
διακοπή;
περίπτωση 11:
printf("Η τιμή είναι έντεκα\n");
διακοπή;
προεπιλογή:
printf("Είναι μία από τις απροσδιόριστες τιμές\n");
διακοπή;
} /* τέλος διακόπτη */
} /* τέλος του βρόχου for */
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι
Η τιμή είναι τρεις
Η τιμή είναι τέσσερα
Η τιμή είναι μεταξύ 5 και 8
Η τιμή είναι μεταξύ 5 και 8
Η τιμή είναι μεταξύ 5 και 8
Η τιμή είναι μεταξύ 5 και 8
Είναι μια από τις απροσδιόριστες αξίες
Είναι μια από τις απροσδιόριστες αξίες
Η τιμή είναι έντεκα
Είναι μια από τις απροσδιόριστες αξίες
Η δήλωση διαλείμματος
Έχουμε ήδη συναντήσει διάλειμμα στη συζήτηση της δήλωσης διακόπτη. Χρησιμοποιείται για έξοδο από έναν βρόχο ή έναν διακόπτη, ο έλεγχος περνά στην πρώτη δήλωση πέρα από τον βρόχο ή έναν διακόπτη.
Με τους βρόχους, το break μπορεί να χρησιμοποιηθεί για να εξαναγκάσει μια πρόωρη έξοδο από τον βρόχο ή για να εφαρμόσει έναν βρόχο με μια δοκιμή για έξοδο στη μέση του σώματος του βρόχου. Ένα διάλειμμα εντός ενός βρόχου θα πρέπει πάντα να προστατεύεται μέσα σε μια δήλωση if που παρέχει τη δοκιμή για τον έλεγχο της συνθήκης εξόδου.
Η δήλωση συνέχειας
Αυτό είναι παρόμοιο με το σπάσιμο, αλλά συναντάται λιγότερο συχνά. Λειτουργεί μόνο μέσα σε βρόχους όπου το αποτέλεσμα είναι να εξαναγκάσει ένα άμεσο άλμα στη δήλωση ελέγχου βρόχου.
- Σε ένα βρόχο while, μεταβείτε στη δήλωση δοκιμής.
- Σε έναν βρόχο do while, μεταβείτε στη δήλωση δοκιμής.
- Σε έναν βρόχο for, μεταβείτε στη δοκιμή και εκτελέστε την επανάληψη.
Όπως ένα διάλειμμα, η συνέχεια θα πρέπει να προστατεύεται από μια δήλωση if. Είναι απίθανο να το χρησιμοποιείτε πολύ συχνά. Για να κατανοήσουμε καλύτερα τη χρήση του διαλείμματος και να συνεχίσουμε, ας εξετάσουμε το ακόλουθο πρόγραμμα:
#include <stdio.h>
int main()
{
int αξία?
for(τιμή = 5 ; τιμή < 15 ; τιμή = τιμή + 1)
{
αν (τιμή == 8)
διακοπή;
printf("Στον βρόχο διακοπής, η τιμή είναι τώρα %d\n", τιμή);
}
for(τιμή = 5 ; τιμή < 15 ; τιμή = τιμή + 1)
{
αν (τιμή == 8)
συνεχίζω;
printf("Στον βρόχο συνέχειας, η τιμή είναι τώρα %d\n", τιμή);
}
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Στον βρόχο διακοπής, η τιμή είναι τώρα 5
Στον βρόχο διακοπής, η τιμή είναι τώρα 6
Στον βρόχο διακοπής, η τιμή είναι τώρα 7
Στον βρόχο συνέχειας, η τιμή είναι τώρα 5
Στον βρόχο συνέχειας, η τιμή είναι τώρα 6
Στον βρόχο συνέχειας, η τιμή είναι τώρα 7
Στον βρόχο συνέχειας, η τιμή είναι τώρα 9
Στον βρόχο συνέχειας, η τιμή είναι τώρα 10
Στον βρόχο συνέχειας, η τιμή είναι τώρα 11
Στον βρόχο συνέχειας, η τιμή είναι τώρα 12
Στον βρόχο συνέχειας, η τιμή είναι τώρα 13
Στον βρόχο συνέχειας, η τιμή είναι τώρα 14
Βρόχοι
Ο άλλος κύριος τύπος δήλωσης ελέγχου είναι ο βρόχος. Οι βρόχοι επιτρέπουν την επανάληψη μιας δήλωσης ή μπλοκ εντολών. Οι υπολογιστές είναι πολύ καλοί στο να επαναλαμβάνουν απλές εργασίες πολλές φορές. Ο βρόχος είναι ο τρόπος του C για να το πετύχει αυτό.
Το C σάς δίνει τη δυνατότητα επιλογής τριών τύπων βρόχου, while, do-while και for.
- Ο βρόχος while συνεχίζει να επαναλαμβάνει μια ενέργεια έως ότου ένα σχετικό τεστ επιστρέψει false. Αυτό είναι χρήσιμο όταν ο προγραμματιστής δεν γνωρίζει εκ των προτέρων πόσες φορές θα διασχιστεί ο βρόχος.
- Οι βρόχοι do while είναι παρόμοιοι, αλλά η δοκιμή πραγματοποιείται μετά την εκτέλεση του σώματος του βρόχου. Αυτό διασφαλίζει ότι το σώμα του βρόχου λειτουργεί τουλάχιστον μία φορά.
- Ο βρόχος for χρησιμοποιείται συχνά, συνήθως όπου ο βρόχος διασχίζεται σταθερό αριθμό φορών. Είναι πολύ ευέλικτο και οι αρχάριοι προγραμματιστές θα πρέπει να φροντίζουν να μην κάνουν κατάχρηση της ισχύος που προσφέρει.
Το while Loop
Ο βρόχος while επαναλαμβάνει μια δήλωση έως ότου η δοκιμή στην κορυφή αποδειχθεί ψευδής. Για παράδειγμα, εδώ είναι μια συνάρτηση που επιστρέφει το μήκος μιας συμβολοσειράς. Θυμηθείτε ότι η συμβολοσειρά αναπαρίσταται ως ένας πίνακας χαρακτήρων που τερματίζεται από έναν μηδενικό χαρακτήρα '\0'.
int string_length (συμβολοσειρά char[])
{ int i = 0;
ενώ (string[i] != '\0')
i++;
επιστροφή(i);
}
Η συμβολοσειρά μεταβιβάζεται στη συνάρτηση ως όρισμα. Το μέγεθος του πίνακα δεν έχει καθοριστεί, η συνάρτηση θα λειτουργήσει για μια συμβολοσειρά οποιουδήποτε μεγέθους.
Ο βρόχος while χρησιμοποιείται για την εξέταση των χαρακτήρων στη συμβολοσειρά έναν κάθε φορά μέχρι να βρεθεί ο μηδενικός χαρακτήρας. Στη συνέχεια, ο βρόχος βγαίνει και επιστρέφεται ο δείκτης του μηδενικού.
Ενώ ο χαρακτήρας δεν είναι μηδενικός, ο δείκτης αυξάνεται και η δοκιμή επαναλαμβάνεται. Θα εξετάσουμε σε βάθος τους πίνακες αργότερα. Ας δούμε ένα παράδειγμα για τον βρόχο while:
#include <stdio.h>
int main()
{
int count?
καταμέτρηση = 0;
ενώ (μέτρηση < 6)
{
printf("Η τιμή του count είναι %d\n", count);
count = μέτρηση + 1;
}
επιστροφή 0;
}
και το αποτέλεσμα εμφανίζεται ως εξής:
Η τιμή της καταμέτρησης είναι 0
Η τιμή της καταμέτρησης είναι 1
Η τιμή της καταμέτρησης είναι 2
Η τιμή της καταμέτρησης είναι 3
Η τιμή της καταμέτρησης είναι 4
Η τιμή της καταμέτρησης είναι 5
Το do while Loop
Αυτό είναι πολύ παρόμοιο με τον βρόχο while εκτός από το ότι η δοκιμή πραγματοποιείται στο τέλος του σώματος του βρόχου. Αυτό εγγυάται ότι ο βρόχος εκτελείται τουλάχιστον μία φορά πριν συνεχιστεί.
Μια τέτοια ρύθμιση χρησιμοποιείται συχνά όταν πρόκειται να διαβαστούν τα δεδομένα. Στη συνέχεια, το τεστ επαληθεύει τα δεδομένα και επανέρχεται για να διαβάσει ξανά εάν ήταν απαράδεκτο.
κάνω
{
printf("Εισαγάγετε 1 για ναι, 0 για όχι:");
scanf("%d", &input_value);
} ενώ (input_value != 1 && input_value != 0)
Για να κατανοήσουμε καλύτερα τον βρόχο do while, ας δούμε το ακόλουθο παράδειγμα:
#include <stdio.h>
int main()
{
int i?
i = 0;
κάνω
{
printf("Η τιμή του i είναι τώρα %d\n", i);
i = i + 1;
} while (i < 5);
επιστροφή 0;
}
Το αποτέλεσμα του προγράμματος εμφανίζεται ως εξής:
Η τιμή του i είναι τώρα 0
Η τιμή του i είναι τώρα 1
Η τιμή του i είναι τώρα 2
Η τιμή του i είναι τώρα 3
Η τιμή του i είναι τώρα 4
Το for Loop
Ο βρόχος for λειτουργεί καλά όταν ο αριθμός των επαναλήψεων του βρόχου είναι γνωστός πριν από την εισαγωγή του βρόχου. Η κεφαλή του βρόχου αποτελείται από τρία μέρη που χωρίζονται με ερωτηματικά.
- Το πρώτο εκτελείται πριν από την εισαγωγή του βρόχου. Αυτή είναι συνήθως η προετοιμασία της μεταβλητής βρόχου.
- Το δεύτερο είναι μια δοκιμή, ο βρόχος βγαίνει όταν αυτό επιστρέψει false.
- Η τρίτη είναι μια δήλωση που εκτελείται κάθε φορά που ολοκληρώνεται το σώμα του βρόχου. Αυτό είναι συνήθως μια αύξηση του μετρητή βρόχου.
Το παράδειγμα είναι μια συνάρτηση που υπολογίζει τον μέσο όρο των αριθμών που είναι αποθηκευμένοι σε έναν πίνακα. Η συνάρτηση παίρνει τον πίνακα και τον αριθμό των στοιχείων ως ορίσματα.
float average (float array[], int count)
{
float σύνολο = 0,0;
int i?
for(i = 0; i < μετρώ; i++)
σύνολο += πίνακας[i];
επιστροφή (σύνολο / μέτρηση)
}
Ο βρόχος for διασφαλίζει ότι προστίθεται ο σωστός αριθμός στοιχείων πίνακα πριν από τον υπολογισμό του μέσου όρου.
Οι τρεις δηλώσεις στην κορυφή ενός βρόχου for συνήθως κάνουν μόνο ένα πράγμα η καθεμία, ωστόσο οποιαδήποτε από αυτές μπορεί να μείνει κενή. Μια κενή πρώτη ή τελευταία πρόταση θα σημαίνει ότι δεν υπάρχει αρχικοποίηση ή προσαύξηση που εκτελείται. Μια κενή πρόταση σύγκρισης θα αντιμετωπίζεται πάντα ως αληθής. Αυτό θα κάνει τον βρόχο να τρέχει επ' αόριστον, εκτός εάν διακοπεί με κάποιο άλλο μέσο. Αυτό μπορεί να είναι μια δήλωση επιστροφής ή διακοπής.
Είναι επίσης δυνατό να συμπιέσετε πολλές δηλώσεις στην πρώτη ή στην τρίτη θέση, χωρίζοντάς τις με κόμματα. Αυτό επιτρέπει έναν βρόχο με περισσότερες από μία μεταβλητές ελέγχου. Το παρακάτω παράδειγμα επεξηγεί τον ορισμό ενός τέτοιου βρόχου, με τις μεταβλητές hi και lo να ξεκινούν από το 100 και το 0 αντίστοιχα και να συγκλίνουν.
Ο βρόχος for δίνει μια ποικιλία συντομογραφίας που θα χρησιμοποιηθούν σε αυτόν. Προσέξτε την ακόλουθη έκφραση, σε αυτήν την έκφραση ο μεμονωμένος βρόχος περιέχει δύο βρόχους for σε αυτόν. Εδώ το hi-- είναι ίδιο με το hi = hi - 1 και το lo++ είναι το ίδιο με το lo = lo + 1,
for(hi = 100, lo = 0; hi >= lo; hi--, lo++)
Ο βρόχος for είναι εξαιρετικά ευέλικτος και επιτρέπει τον καθορισμό πολλών τύπων συμπεριφοράς προγράμματος απλά και γρήγορα. Ας δούμε ένα παράδειγμα του βρόχου for
#include <stdio.h>
int main()
{
δείκτης int?
for(ευρετήριο = 0 ; δείκτης < 6 ; δείκτης = ευρετήριο + 1)
printf("Η τιμή του ευρετηρίου είναι %d\n", ευρετήριο);
επιστροφή 0;
}
Το αποτέλεσμα του προγράμματος εμφανίζεται ως εξής:
Η τιμή του δείκτη είναι 0
Η τιμή του δείκτη είναι 1
Η τιμή του δείκτη είναι 2
Η τιμή του δείκτη είναι 3
Η τιμή του δείκτη είναι 4
Η τιμή του δείκτη είναι 5
Η δήλωση goto
Το C έχει μια δήλωση goto που επιτρέπει την πραγματοποίηση μη δομημένων άλματα. Για να χρησιμοποιήσετε μια δήλωση goto, απλώς χρησιμοποιείτε τη δεσμευμένη λέξη goto ακολουθούμενη από το συμβολικό όνομα στο οποίο θέλετε να μεταβείτε. Στη συνέχεια, το όνομα τοποθετείται οπουδήποτε στο πρόγραμμα ακολουθούμενο από άνω και κάτω τελεία. Μπορείτε να πηδήξετε σχεδόν οπουδήποτε μέσα σε μια συνάρτηση, αλλά δεν επιτρέπεται να μεταπηδήσετε σε έναν βρόχο, αν και σας επιτρέπεται να πηδήξετε έξω από έναν βρόχο.
Αυτό το συγκεκριμένο πρόγραμμα είναι πραγματικά ένα χάος, αλλά είναι ένα καλό παράδειγμα του γιατί οι συγγραφείς λογισμικού προσπαθούν να εξαλείψουν τη χρήση της δήλωσης goto όσο το δυνατόν περισσότερο. Το μόνο μέρος σε αυτό το πρόγραμμα όπου είναι λογικό να χρησιμοποιηθεί το goto είναι, όπου το πρόγραμμα πηδά από τους τρεις ένθετους βρόχους σε ένα άλμα. Σε αυτήν την περίπτωση, θα ήταν μάλλον ακατάστατο να ρυθμίσετε μια μεταβλητή και να πηδήξετε διαδοχικά από κάθε έναν από τους τρεις ένθετους βρόχους, αλλά μια δήλωση goto σας βγάζει και από τις τρεις με πολύ συνοπτικό τρόπο.
Μερικά άτομα λένε ότι η δήλωση goto δεν πρέπει ποτέ να χρησιμοποιείται σε καμία περίπτωση, αλλά αυτό είναι στενόμυαλη σκέψη. Εάν υπάρχει ένα μέρος όπου ένα goto θα κάνει σαφώς πιο καθαρή ροή ελέγχου από κάποια άλλη κατασκευή, μη διστάσετε να το χρησιμοποιήσετε, ωστόσο, όπως είναι στο υπόλοιπο πρόγραμμα στην οθόνη σας. Ας δούμε το παράδειγμα:
#include <stdio.h>
int main()
{
int σκύλος, γάτα, γουρούνι?
Goto real_start;
κάπου:
printf("Αυτή είναι μια άλλη γραμμή του χάους.\n");
πρέπει να σταματήσει_it?
/* η παρακάτω ενότητα είναι η μόνη ενότητα με χρησιμοποιήσιμο goto */
real_start:
για(σκύλος = 1 ; σκύλος < 6 ; σκύλος = σκύλος + 1)
{
για(γάτα = 1 ; γάτα < 6 ; γάτα = γάτα + 1)
{
για(γουρούνι = 1 , χοίρος < 4 , χοίρος = χοίρος + 1)
{
printf("Dog = %d Cat = %d Pig = %d\n", dog, cat, pig);
αν ((σκύλος + γάτα + γουρούνι) > 8 ) φτάνει αρκετά.
}
}
}
αρκετά: printf("Αυτά είναι αρκετά ζώα προς το παρόν.\n");
/* αυτό είναι το τέλος της ενότητας με μια χρησιμοποιήσιμη δήλωση goto */
printf("\nΑυτή είναι η πρώτη γραμμή του κώδικα.\n");
πήγα εκεί?
όπου:
printf("Αυτή είναι η τρίτη γραμμή του κώδικα.\n");
πήγα κάπου?
εκεί:
printf("Αυτή είναι η δεύτερη γραμμή του κώδικα.\n");
πήγα που?
stop_it:
printf("Αυτή είναι η τελευταία γραμμή αυτού του χάους.\n");
επιστροφή 0;
}
Ας δούμε τα αποτελέσματα που εμφανίζονται
Σκύλος = 1 Γάτα = 1 Χοίρος = 1
Σκύλος = 1 Γάτα = 1 Χοίρος = 2
Σκύλος = 1 Γάτα = 1 Χοίρος = 3
Σκύλος = 1 Γάτα = 2 Γουρούνι = 1
Σκύλος = 1 Γάτα = 2 Χοίρος = 2
Σκύλος = 1 Γάτα = 2 Χοίρος = 3
Σκύλος = 1 Γάτα = 3 Χοίρος = 1
Σκύλος = 1 Γάτα = 3 Χοίρος = 2
Σκύλος = 1 Γάτα = 3 Χοίρος = 3
Σκύλος = 1 Γάτα = 4 Χοίρος = 1
Σκύλος = 1 Γάτα = 4 Χοίρος = 2
Σκύλος = 1 Γάτα = 4 Χοίρος = 3
Σκύλος = 1 Γάτα = 5 Χοίρος = 1
Σκύλος = 1 Γάτα = 5 Χοίρος = 2
Σκύλος = 1 Γάτα = 5 Χοίρος = 3
Αυτά είναι αρκετά ζώα προς το παρόν.
Αυτή είναι η πρώτη γραμμή του κώδικα.
Αυτή είναι η δεύτερη γραμμή του κώδικα.
Αυτή είναι η τρίτη γραμμή του κώδικα.
Αυτή είναι μια άλλη γραμμή του χάους.
Αυτή είναι η τελευταία γραμμή αυτού του χάους.
Δείκτες
Μερικές φορές θέλουμε να μάθουμε πού βρίσκεται μια μεταβλητή στη μνήμη. Ένας δείκτης περιέχει τη διεύθυνση μιας μεταβλητής που έχει μια συγκεκριμένη τιμή. Κατά τη δήλωση ενός δείκτη, ένας αστερίσκος τοποθετείται αμέσως πριν από το όνομα του δείκτη.
Η διεύθυνση της θέσης μνήμης όπου είναι αποθηκευμένη η μεταβλητή μπορεί να βρεθεί τοποθετώντας ένα συμπλεκτικό σύμβολο μπροστά από το όνομα της μεταβλητής.
int num; /* Κανονική ακέραια μεταβλητή */
int *numPtr; /* Δείκτης σε μια ακέραια μεταβλητή */
Το ακόλουθο παράδειγμα εκτυπώνει την τιμή της μεταβλητής και τη διεύθυνση στη μνήμη αυτής της μεταβλητής.
printf("Η τιμή %d αποθηκεύεται στη διεύθυνση %X\n", num, &num);
Για να εκχωρήσετε τη διεύθυνση της μεταβλητής num στον δείκτη numPtr, εκχωρείτε τη διεύθυνση της μεταβλητής num, όπως στο παράδειγμα που δίνεται παρακάτω:
numPtr = #
Για να μάθετε τι είναι αποθηκευμένο στη διεύθυνση που υποδεικνύεται από το numPtr, η μεταβλητή πρέπει να αποαναφερθεί. Η αποαναφορά επιτυγχάνεται με τον αστερίσκο με τον οποίο δηλώθηκε ο δείκτης.
printf("Η τιμή %d αποθηκεύεται στη διεύθυνση %X\n", *numPtr, numPtr);
Όλες οι μεταβλητές σε ένα πρόγραμμα βρίσκονται στη μνήμη. Οι δηλώσεις που δίνονται παρακάτω ζητούν από τον μεταγλωττιστή να κρατήσει 4 byte μνήμης σε έναν υπολογιστή 32 bit για τη μεταβλητή κινητής υποδιαστολής x και στη συνέχεια να βάλει την τιμή 6,5 σε αυτήν.
float x;
x = 6,5;
Καθώς η θέση διεύθυνσης στη μνήμη οποιασδήποτε μεταβλητής λαμβάνεται τοποθετώντας τον τελεστή & πριν από το όνομά του, επομένως το &x είναι η διεύθυνση του x. Το C μας επιτρέπει να πάμε ένα στάδιο παραπέρα και να ορίσουμε μια μεταβλητή, που ονομάζεται δείκτης που περιέχει τη διεύθυνση άλλων μεταβλητών. Μάλλον μπορούμε να πούμε ότι ο δείκτης δείχνει σε άλλη μεταβλητή. Για παράδειγμα:
float x;
float* px;
x = 6,5;
px = &x;
ορίζει το px ως δείκτη σε αντικείμενα τύπου float και τον ορίζει ίσο με τη διεύθυνση του x. Έτσι, το *px αναφέρεται στην τιμή του x:

Ας εξετάσουμε τις ακόλουθες δηλώσεις:
int var_x;
int* ptrX;
όπου_x = 6;
ptrX = &var_x;
*ptrX = 12;
printf("τιμή του x : %d", var_x);
Η πρώτη γραμμή κάνει τον μεταγλωττιστή να κρατήσει ένα κενό στη μνήμη για έναν ακέραιο. Η δεύτερη γραμμή λέει στον μεταγλωττιστή να κρατήσει χώρο για να αποθηκεύσει έναν δείκτη.
Ένας δείκτης είναι μια θέση αποθήκευσης για μια διεύθυνση. Η τρίτη γραμμή θα πρέπει να σας υπενθυμίζει τις δηλώσεις scanf. Ο τελεστής διεύθυνσης "&" λέει στον μεταγλωττιστή να πάει στο μέρος που αποθήκευσε το var_x και μετά να δώσει τη διεύθυνση της θέσης αποθήκευσης στο ptrX.
Ο αστερίσκος * μπροστά από μια μεταβλητή λέει στον μεταγλωττιστή να αποαναφέρει τον δείκτη και να μεταβεί στη μνήμη. Στη συνέχεια, μπορείτε να κάνετε αναθέσεις σε μεταβλητή που είναι αποθηκευμένη σε αυτήν τη θέση. Μπορείτε να αναφέρετε μια μεταβλητή και να έχετε πρόσβαση στα δεδομένα της μέσω ενός δείκτη. Ας δούμε ένα παράδειγμα δεικτών:
/* απεικόνιση της χρήσης δείκτη */
#include <stdio.h>
int main()
{
δείκτης int, *pt1, *pt2;
δείκτης = 39; /* οποιαδήποτε αριθμητική τιμή */
pt1 = &index; /* η διεύθυνση του ευρετηρίου */
pt2 = pt1;
printf("Η τιμή είναι %d %d %d\n", ευρετήριο, *pt1, *pt2);
*pt1 = 13; /* αυτό αλλάζει την τιμή του ευρετηρίου */
printf("Η τιμή είναι %d %d %d\n", ευρετήριο, *pt1, *pt2);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα εμφανιστεί ως εξής:
Η τιμή είναι 39 39 39
Η τιμή είναι 13 13 13
Ας δούμε ένα άλλο παράδειγμα για να κατανοήσουμε καλύτερα τη χρήση των δεικτών:
#include <stdio.h>
#include <string.h>
int main()
{
char strg[40], *εκεί, ένα, δύο;
int *pt, list[100], index;
strcpy(strg, "Αυτή είναι μια συμβολοσειρά χαρακτήρων.");
/* η συνάρτηση strcpy() είναι η αντιγραφή μιας συμβολοσειράς σε μια άλλη. θα διαβάσουμε για τη συνάρτηση strcpy() στο String Section αργότερα */
one = strg[0]; /* ένα και δύο είναι πανομοιότυπα */
δύο = *ctrl;
printf("Η πρώτη έξοδος είναι %c %c\n", ένα, δύο);
one = strg[8]; /* ένα και δύο είναι πανομοιότυπα */
δύο = *(ctrl+8);
printf("Η δεύτερη έξοδος είναι %c %c\n", ένα, δύο);
εκεί = ctrl+10; /* strg+10 είναι πανομοιότυπο με το &strg[10] */
printf("Η τρίτη έξοδος είναι %c\n", strg[10]);
printf("Η τέταρτη έξοδος είναι %c\n", *εκεί);
για (δείκτης = 0 ; δείκτης < 100 ; δείκτης++)
λίστα[ευρετήριο] = ευρετήριο + 100;
pt = λίστα + 27;
printf("Η πέμπτη έξοδος είναι %d\n", λίστα[27]);
printf("Η έκτη έξοδος είναι %d\n", *pt);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Η πρώτη έξοδος είναι TT
Η δεύτερη έξοδος είναι aa
Η τρίτη έξοδος είναι c
Η τέταρτη έξοδος είναι c
Η πέμπτη έξοδος είναι 127
Η έκτη έξοδος είναι 127
Πίνακες
Ένας πίνακας είναι μια συλλογή μεταβλητών του ίδιου τύπου. Τα μεμονωμένα στοιχεία πίνακα αναγνωρίζονται από έναν ακέραιο δείκτη. Στο C ο δείκτης αρχίζει από το μηδέν και γράφεται πάντα μέσα σε αγκύλες.
Έχουμε ήδη συναντήσει πίνακες μονής διάστασης που δηλώνονται έτσι
int αποτελέσματα[20];
Οι πίνακες μπορούν να έχουν περισσότερες διαστάσεις, οπότε μπορεί να δηλωθούν ως
int results_2d[20][5];
int results_3d[20][5][3];
Κάθε ευρετήριο έχει το δικό του σύνολο αγκύλων. Ένας πίνακας δηλώνεται στην κύρια συνάρτηση, συνήθως περιλαμβάνει λεπτομέρειες διαστάσεων. Είναι δυνατό να χρησιμοποιηθεί ένας άλλος τύπος που ονομάζεται δείκτης στη θέση ενός πίνακα. Αυτό σημαίνει ότι οι διαστάσεις δεν καθορίζονται αμέσως, αλλά μπορεί να εκχωρηθεί χώρος όπως απαιτείται. Αυτή είναι μια προηγμένη τεχνική που απαιτείται μόνο σε ορισμένα εξειδικευμένα προγράμματα.
Για παράδειγμα, εδώ είναι μια απλή συνάρτηση για την άθροιση όλων των ακεραίων σε έναν πίνακα μονής διάστασης.
int add_array(int array[], int size)
{
int i?
int σύνολο = 0;
for(i = 0; i < μέγεθος; i++)
σύνολο += πίνακας[i];
επιστροφή (σύνολο);
}
Το πρόγραμμα που δίνεται στη συνέχεια θα δημιουργήσει μια συμβολοσειρά, θα αποκτήσει πρόσβαση σε ορισμένα δεδομένα σε αυτήν, θα την εκτυπώσει. Αποκτήστε ξανά πρόσβαση χρησιμοποιώντας δείκτες και, στη συνέχεια, εκτυπώστε τη συμβολοσειρά. Θα πρέπει να τυπώσει "Hi!" και "012345678" σε διαφορετικές γραμμές. Ας δούμε την κωδικοποίηση του προγράμματος:
#include <stdio.h>
#define STR_LENGTH 10
void main()
{
char Str [STR_LENGTH];
char* pStr;
int i?
Str[0] = 'H';
Str[1] = 'i';
Str[2] = '!';
Str[3] = '\0'; // ειδικός χαρακτήρας συμβολοσειράς τέλους NULL
printf("Η συμβολοσειρά στο Str είναι : %s\n", Str);
pStr = &Str[0];
για (i = 0; i < STR_LENGTH; i++)
{
*pStr = '0'+i;
pStr++;
}
Str[STR_LENGTH-1] = '\0';
printf("Η συμβολοσειρά στο Str είναι : %s\n", Str);
}
Τα [] (τετράγωνα στηρίγματα) χρησιμοποιούνται για τη δήλωση του πίνακα. Η γραμμή του προγράμματος char Str [STR_LENGTH]; δηλώνει έναν πίνακα δέκα χαρακτήρων. Αυτοί είναι δέκα μεμονωμένοι χαρακτήρες, οι οποίοι είναι όλοι μαζί στη μνήμη στο ίδιο μέρος. Είναι δυνατή η πρόσβαση σε όλα μέσω του ονόματος της μεταβλητής μας Str μαζί με ένα [n] όπου n είναι ο αριθμός του στοιχείου.
Θα πρέπει πάντα να λαμβάνεται υπόψη όταν μιλάμε για πίνακα ότι όταν το C δηλώνει έναν πίνακα δέκα, τα στοιχεία στα οποία μπορείτε να αποκτήσετε πρόσβαση είναι αριθμημένα από το 0 έως το 9. Η πρόσβαση στο πρώτο στοιχείο αντιστοιχεί στην πρόσβαση στο 0ο στοιχείο. Έτσι, στην περίπτωση των Arrays να μετράτε πάντα από το 0 έως το μέγεθος του πίνακα - 1.
Επόμενη ειδοποίηση ότι βάζουμε τα γράμματα "Hi!" στον πίνακα, αλλά μετά βάζουμε ένα '\0' που πιθανώς αναρωτιέστε τι είναι αυτό. Το "\0" σημαίνει NULL και αντιπροσωπεύει το τέλος της συμβολοσειράς. Όλες οι συμβολοσειρές χαρακτήρων πρέπει να τελειώνουν με αυτόν τον ειδικό χαρακτήρα '\0'. Εάν δεν το κάνουν, και στη συνέχεια κάποιος καλέσει το printf στη συμβολοσειρά, τότε το printf θα ξεκινήσει από τη θέση μνήμης της συμβολοσειράς σας και θα συνεχίσει να εκτυπώνει πείτε του ότι συναντά '\0' και έτσι θα καταλήξετε με ένα σωρό σκουπίδια στο τέλος της συμβολοσειράς σας. Φροντίστε λοιπόν να τερματίσετε τις χορδές σας σωστά.
Πίνακες χαρακτήρων
Μια σταθερά συμβολοσειράς, όπως π.χ
"Είμαι μια χορδή"
είναι μια σειρά χαρακτήρων. Αντιπροσωπεύεται εσωτερικά στο C από τους χαρακτήρες ASCII στη συμβολοσειρά, π.χ., "I", κενό, "a", "m",…ή την παραπάνω συμβολοσειρά, και τερματίζεται με τον ειδικό μηδενικό χαρακτήρα "\0", ώστε τα προγράμματα να μπορούν να βρουν το τέλος της συμβολοσειράς.
Οι σταθερές συμβολοσειράς χρησιμοποιούνται συχνά για να κάνουν την έξοδο του κώδικα κατανοητή χρησιμοποιώντας το printf:
printf("Γεια, κόσμο\n");
printf("Η τιμή του a είναι: %f\n", a);
Οι σταθερές συμβολοσειράς μπορούν να συσχετιστούν με μεταβλητές. Το C παρέχει τη μεταβλητή τύπου χαρακτήρα, η οποία μπορεί να περιέχει έναν χαρακτήρα (1 byte) τη φορά. Μια συμβολοσειρά χαρακτήρων αποθηκεύεται σε έναν πίνακα τύπου χαρακτήρων, έναν χαρακτήρα ASCII ανά τοποθεσία.
Μην ξεχνάτε ποτέ ότι, καθώς οι συμβολοσειρές τερματίζονται συμβατικά από τον μηδενικό χαρακτήρα "\0", χρειαζόμαστε μια επιπλέον θέση αποθήκευσης στον πίνακα.
Το C δεν παρέχει κανέναν τελεστή που χειρίζεται ολόκληρες συμβολοσειρές ταυτόχρονα. Οι συμβολοσειρές χειρίζονται είτε μέσω δεικτών είτε μέσω ειδικών ρουτινών που είναι διαθέσιμες από την τυπική συμβολοσειρά βιβλιοθήκης συμβολοσειρών.h.
Η χρήση δεικτών χαρακτήρων είναι σχετικά εύκολη αφού το όνομα ενός πίνακα είναι απλώς ένας δείκτης στο πρώτο του στοιχείο. Εξετάστε το πρόγραμμα που δίνεται στη συνέχεια:
#include<stdio.h>
void main()
{
char text_1[100], text_2[100], text_3[100];
char *ta, *tb;
int i?
/* ορίστε το μήνυμα ως πίνακα */
/* χαρακτήρων; αρχικοποιήστε το */
/* στη σταθερή συμβολοσειρά "..." */
/* αφήστε τον μεταγλωττιστή να αποφασίσει σχετικά με */
/* το μέγεθός του χρησιμοποιώντας [] */
char message[] = "Γεια σας, είμαι μια χορδή, τι είναι
εσείς;";
printf("Αρχικό μήνυμα: %s\n", μήνυμα);
/* αντιγράψτε το μήνυμα στο text_1 */
i=0;
ενώ ( (κείμενο_1[i] = μήνυμα[i]) != '\0' )
i++;
printf("Κείμενο_1: %s\n", text_1);
/* χρήση ρητής αριθμητικής δείκτη */
your=μήνυμα;
tb=text_2;
ενώ ( ( *tb++ = *ta++ ) != '\0' )
;
printf("Κείμενο_2: %s\n", text_2);
}
Η έξοδος του προγράμματος θα είναι η εξής:
Αρχικό μήνυμα: Γεια, είμαι χορδή. τι εισαι
Κείμενο_1: Γεια σας, είμαι χορδή. τι εισαι
Κείμενο_2: Γεια σας, είμαι χορδή. τι εισαι
Η τυπική βιβλιοθήκη "string" περιέχει πολλές χρήσιμες λειτουργίες για τον χειρισμό συμβολοσειρών, τις οποίες θα μάθουμε στην ενότητα συμβολοσειράς αργότερα.
Πρόσβαση στα Στοιχεία
Για να αποκτήσετε πρόσβαση σε ένα μεμονωμένο στοιχείο στον πίνακα, ο αριθμός ευρετηρίου ακολουθεί το όνομα της μεταβλητής σε αγκύλες. Στη συνέχεια, η μεταβλητή μπορεί να αντιμετωπιστεί όπως οποιαδήποτε άλλη μεταβλητή στο C. Το ακόλουθο παράδειγμα εκχωρεί μια τιμή στο πρώτο στοιχείο του πίνακα.
x[0] = 16;
Το παρακάτω παράδειγμα εκτυπώνει την τιμή του τρίτου στοιχείου σε έναν πίνακα.
printf("%d\n", x[2]);
Το παρακάτω παράδειγμα χρησιμοποιεί τη συνάρτηση scanf για να διαβάσει μια τιμή από το πληκτρολόγιο στο τελευταίο στοιχείο ενός πίνακα με δέκα στοιχεία.
scanf("%d", &x[9]);
Αρχικοποίηση στοιχείων πίνακα
Οι πίνακες μπορούν να αρχικοποιηθούν όπως οποιεσδήποτε άλλες μεταβλητές με ανάθεση. Καθώς ένας πίνακας περιέχει περισσότερες από μία τιμές, οι μεμονωμένες τιμές τοποθετούνται σε σγουρές αγκύλες και διαχωρίζονται με κόμματα. Το ακόλουθο παράδειγμα προετοιμάζει έναν δεκαδιάστατο πίνακα με τις πρώτες δέκα τιμές του πίνακα τριών χρόνων.
int x[10] = {3, 6, 9, 12, 15, 18, 21, 24, 27, 30};
Αυτό εξοικονομεί την εκχώρηση των τιμών μεμονωμένα όπως στο παρακάτω παράδειγμα.
int x[10];
x[0] = 3;
x[1] = 6;
x[2] = 9;
x[3] = 12;
x[4] = 15;
x[5] = 18;
x[6] = 21;
x[7] = 24;
x[8] = 27;
x[9] = 30;
Γίνεται βρόχος μέσα από έναν πίνακα
Καθώς ο πίνακας ευρετηριάζεται διαδοχικά, μπορούμε να χρησιμοποιήσουμε τον βρόχο for για να εμφανίσουμε όλες τις τιμές ενός πίνακα. Το παρακάτω παράδειγμα εμφανίζει όλες τις τιμές ενός πίνακα:
#include <stdio.h>
int main()
{
int x[10];
int μετρητής?
/* Τυχαιοποίηση της γεννήτριας τυχαίων αριθμών */
srand((unsigned)time(NULL));
/* Εκχωρήστε τυχαίες τιμές στη μεταβλητή */
για (counter=0; counter<10; counter++)
x[counter] = rand();
/* Εμφάνιση των περιεχομένων του πίνακα */
για (counter=0; counter<10; counter++)
printf("το στοιχείο %d έχει την τιμή %d\n", μετρητής, x[counter]);
επιστροφή 0;
}
Αν και η έξοδος θα εκτυπώνει τις διαφορετικές τιμές κάθε φορά, το αποτέλεσμα θα εμφανίζεται κάπως έτσι:
Το στοιχείο 0 έχει την τιμή 17132
Το στοιχείο 1 έχει την τιμή 24904
Το στοιχείο 2 έχει την τιμή 13466
Το στοιχείο 3 έχει την τιμή 3147
Το στοιχείο 4 έχει την τιμή 22006
Το στοιχείο 5 έχει την τιμή 10397
Το στοιχείο 6 έχει την τιμή 28114
Το στοιχείο 7 έχει την τιμή 19817
Το στοιχείο 8 έχει την τιμή 27430
Το στοιχείο 9 έχει την τιμή 22136
Πολυδιάστατοι πίνακες
Ένας πίνακας μπορεί να έχει περισσότερες από μία διαστάσεις. Επιτρέποντας στον πίνακα να έχει περισσότερες από μία διαστάσεις, παρέχει μεγαλύτερη ευελιξία. Για παράδειγμα, τα υπολογιστικά φύλλα είναι χτισμένα σε έναν δισδιάστατο πίνακα. έναν πίνακα για τις γραμμές και έναν πίνακα για τις στήλες.
Το ακόλουθο παράδειγμα χρησιμοποιεί έναν δισδιάστατο πίνακα με δύο σειρές, καθεμία από τις οποίες περιέχει πέντε στήλες:
#include <stdio.h>
int main()
{
/* Δηλώστε έναν πολυδιάστατο πίνακα 2 x 5 */
int x[2][5] = { {1, 2, 3, 4, 5},
{2, 4, 6, 8, 10} };
int γραμμή, στήλη.
/* Εμφάνιση των σειρών */
για (σειρά=0; σειρά<2; σειρά++)
{
/* Εμφάνιση των στηλών */
για (στήλη=0; στήλη<5; στήλη++)
printf("%d\t", x[row][στήλη]);
putchar('\n');
}
επιστροφή 0;
}
Η έξοδος αυτού του προγράμματος θα εμφανιστεί ως εξής:
1 2 3 4 5
2 4 6 8 10
Χορδές
Μια συμβολοσειρά είναι μια ομάδα χαρακτήρων, συνήθως γράμματα του αλφαβήτου, Για να μορφοποιήσετε την οθόνη εκτύπωσης με τέτοιο τρόπο ώστε να φαίνεται ωραία, να έχει ουσιαστικά ονόματα και τίτλους και να είναι αισθητικά ευχάριστη για εσάς και τα άτομα που χρησιμοποιούν την έξοδο του προγράμματός σας.
Στην πραγματικότητα, έχετε ήδη χρησιμοποιήσει συμβολοσειρές στα παραδείγματα των προηγούμενων θεμάτων. Αλλά δεν είναι η πλήρης εισαγωγή των χορδών. Υπάρχουν πολλές πιθανές περιπτώσεις στον προγραμματισμό, όπου η χρήση μορφοποιημένων συμβολοσειρών βοηθά τον προγραμματιστή να αποφύγει τις πάρα πολλές επιπλοκές στο πρόγραμμα και φυσικά πάρα πολλά σφάλματα.
Ένας πλήρης ορισμός μιας συμβολοσειράς είναι μια σειρά δεδομένων τύπου χαρακτήρων που τερματίζονται από έναν μηδενικό χαρακτήρα ('\0').
Όταν ο C πρόκειται να χρησιμοποιήσει μια συμβολοσειρά δεδομένων με κάποιο τρόπο, είτε για να τη συγκρίνει με μια άλλη συμβολοσειρά, να την εξάγει, να την αντιγράψει σε άλλη συμβολοσειρά ή οτιδήποτε άλλο, οι συναρτήσεις ρυθμίζονται να κάνουν αυτό που καλούνται να κάνουν μέχρι να εντοπιστεί ένα μηδενικό.
Αντίθετα, δεν υπάρχει βασικός τύπος δεδομένων για μια συμβολοσειρά στο C. Οι συμβολοσειρές στο C υλοποιούνται ως μια σειρά χαρακτήρων. Για παράδειγμα, για να αποθηκεύσετε ένα όνομα, θα μπορούσατε να δηλώσετε έναν πίνακα χαρακτήρων αρκετά μεγάλο ώστε να αποθηκεύει το όνομα και, στη συνέχεια, να χρησιμοποιήσετε τις κατάλληλες συναρτήσεις βιβλιοθήκης για να χειριστείτε το όνομα.
Το ακόλουθο παράδειγμα εμφανίζει τη συμβολοσειρά στην οθόνη, που έχει εισαχθεί από τον χρήστη:
#include <stdio.h>
int main()
{
όνομα char[80]; /* Δημιουργία πίνακα χαρακτήρων
όνομα */
printf("Εισαγάγετε το όνομά σας: ");
παίρνει(όνομα);
printf("Το όνομα που εισαγάγατε ήταν %s\n", όνομα);
επιστροφή 0;
}
Η εκτέλεση του προγράμματος θα είναι:
Εισαγάγετε το όνομά σας: Tarun Tyagi
Το όνομα που εισαγάγατε ήταν Tarun Tyagi
Μερικές κοινές συναρτήσεις συμβολοσειράς
Η τυπική βιβλιοθήκη string.h περιέχει πολλές χρήσιμες συναρτήσεις για τον χειρισμό συμβολοσειρών. Μερικές από τις πιο χρήσιμες λειτουργίες παρουσιάζονται εδώ.
Η συνάρτηση strlen
Η συνάρτηση strlen χρησιμοποιείται για τον προσδιορισμό του μήκους μιας συμβολοσειράς. Ας μάθουμε τη χρήση του strlen με παράδειγμα:
#include <stdio.h>
#include <string.h>
int main()
{
όνομα char[80];
int μήκος?
printf("Εισαγάγετε το όνομά σας: ");
παίρνει(όνομα);
μήκος = strlen(όνομα);
printf("Το όνομά σας έχει %d χαρακτήρες\n", μήκος);
επιστροφή 0;
}
Και η εκτέλεση του προγράμματος θα είναι η εξής:
Εισαγάγετε το όνομά σας: Tarun Subhash Tyagi
Το όνομά σας έχει 19 χαρακτήρες
Πληκτρολογήστε το όνομά σας: Preeti Tarun
Το όνομά σας έχει 12 χαρακτήρες
Η συνάρτηση strcpy
Η συνάρτηση strcpy χρησιμοποιείται για την αντιγραφή μιας συμβολοσειράς σε μια άλλη. Ας μάθουμε τη χρήση αυτής της συνάρτησης με παράδειγμα:
#include <stdio.h>
#include <string.h>
int main()
{
char πρώτος[80];
char δεύτερο[80];
printf("Εισαγάγετε την πρώτη συμβολοσειρά: ");
παίρνει (πρώτα)?
printf("Εισαγωγή δεύτερης συμβολοσειράς: ");
παίρνει (δεύτερο);
printf("πρώτο: %s, και δεύτερο: %s Πριν από strcpy()\n "
, πρώτο, δεύτερο);
strcpy(δεύτερο, πρώτο);
printf("πρώτο: %s, και δεύτερο: %s Μετά από strcpy()\n",
πρώτο, δεύτερο)
επιστροφή 0;
}
και η έξοδος του προγράμματος θα είναι ως εξής:
Εισαγάγετε την πρώτη συμβολοσειρά: Tarun
Εισαγάγετε τη δεύτερη συμβολοσειρά: Tyagi
πρώτα: Tarun και δεύτερη: Tyagi Πριν από τη strcpy()
πρώτο: Tarun και δεύτερο: Tarun After strcpy()
Η συνάρτηση strcmp
Η συνάρτηση strcmp χρησιμοποιείται για τη σύγκριση δύο συμβολοσειρών μεταξύ τους. Το όνομα της μεταβλητής ενός πίνακα δείχνει τη διεύθυνση βάσης αυτού του πίνακα. Επομένως, εάν προσπαθήσουμε να συγκρίνουμε δύο συμβολοσειρές χρησιμοποιώντας τα ακόλουθα, θα συγκρίνουμε δύο διευθύνσεις, οι οποίες προφανώς δεν θα ήταν ποτέ ίδιες καθώς δεν είναι δυνατό να αποθηκευτούν δύο τιμές στην ίδια θέση.
if (first == second) /* Δεν μπορεί ποτέ να γίνει σύγκριση συμβολοσειρών */
Το ακόλουθο παράδειγμα χρησιμοποιεί τη συνάρτηση strcmp για να συγκρίνει δύο συμβολοσειρές:
#include <string.h>
int main()
{
char πρώτο[80], δεύτερο[80];
int t;
για(t=1;t<=2;t++)
{
printf("\nΕισαγάγετε μια συμβολοσειρά: ");
παίρνει (πρώτα)?
printf("Εισαγάγετε άλλη συμβολοσειρά: ");
παίρνει (δεύτερο);
if (strcmp(πρώτο, δεύτερο) == 0)
puts("Οι δύο χορδές είναι ίσες");
αλλού
puts("Οι δύο χορδές δεν είναι ίσες");
}
επιστροφή 0;
}
Και η εκτέλεση του προγράμματος θα είναι η εξής:
Εισαγάγετε μια συμβολοσειρά: Tarun
Εισαγάγετε μια άλλη συμβολοσειρά: tarun
Οι δύο χορδές δεν είναι ίσες
Εισαγάγετε μια συμβολοσειρά: Tarun
Εισαγάγετε μια άλλη συμβολοσειρά: Tarun
Οι δύο συμβολοσειρές είναι ίσες
Η συνάρτηση strcat
Η συνάρτηση strcat χρησιμοποιείται για τη σύνδεση μιας συμβολοσειράς στην άλλη. Ας δούμε πώς; Με τη βοήθεια του παραδείγματος:
#include <string.h>
int main()
{
char πρώτο[80], δεύτερο[80];
printf("Εισαγάγετε μια συμβολοσειρά: ");
παίρνει (πρώτα)?
printf("Εισαγάγετε άλλη συμβολοσειρά: ");
παίρνει (δεύτερο);
strcat(πρώτο, δεύτερο);
printf("Οι δύο συμβολοσειρές που ενώνονται μεταξύ τους: %s\n",
πρώτα);
επιστροφή 0;
}
Και η εκτέλεση του προγράμματος θα είναι η εξής:
Εισαγάγετε μια συμβολοσειρά: Δεδομένα
Εισαγάγετε μια άλλη συμβολοσειρά: Ανάκτηση
Οι δύο συμβολοσειρές ενώθηκαν μεταξύ τους: DataRecovery
Η συνάρτηση strtok
Η συνάρτηση strtok χρησιμοποιείται για την εύρεση του επόμενου διακριτικού σε μια συμβολοσειρά. Το διακριτικό καθορίζεται από μια λίστα πιθανών οριοθετητών.
Το ακόλουθο παράδειγμα διαβάζει μια γραμμή κειμένου από ένα αρχείο και προσδιορίζει μια λέξη χρησιμοποιώντας τους οριοθέτες, το διάστημα, την καρτέλα και τη νέα γραμμή. Στη συνέχεια, κάθε λέξη εμφανίζεται σε ξεχωριστή γραμμή:
#include <stdio.h>
#include <string.h>
int main()
{
ΑΡΧΕΙΟ *in;
char line[80];
char *delimiters = " \t\n";
char *token;
if ((in = fopen("C:\\text.txt", "r")) == NULL)
{
puts("Δεν μπορώ να ανοίξω το αρχείο εισόδου");
επιστροφή 0;
}
/* Διαβάστε κάθε γραμμή μία κάθε φορά */
ενώ(!feof(in))
{
/* Πάρτε μια γραμμή */
fgets(line, 80, in);
αν (!feof(in))
{
/* Χωρίστε τη γραμμή σε λέξεις */
token = strtok(γραμμή, οριοθέτες);
ενώ (κουπόνι != NULL)
{
puts(token);
/* Λάβετε την επόμενη λέξη */
token = strtok(NULL, οριοθέτες);
}
}
}
fclose(in);
επιστροφή 0;
}
Πάνω από το πρόγραμμα, στο = fopen("C:\\text.txt", "r"), ανοίγει και το υπάρχον αρχείο C:\\text.txt. Εάν δεν υπάρχει στην καθορισμένη διαδρομή ή για οποιονδήποτε λόγο, το αρχείο δεν μπορούσε να ανοίξει, εμφανίζεται ένα μήνυμα σφάλματος στην οθόνη.
Εξετάστε το ακόλουθο παράδειγμα, το οποίο χρησιμοποιεί μερικές από αυτές τις λειτουργίες:
#include <stdio.h>
#include <string.h>
void main()
{
char line[100], *sub_text;
/* αρχικοποίηση συμβολοσειράς */
strcpy(line,"γεια σας, είμαι μια συμβολοσειρά;");
printf("Γραμμή: %s\n", γραμμή);
/* προσθήκη στο τέλος της συμβολοσειράς */
strcat(γραμμή, "τι είσαι;");
printf("Γραμμή: %s\n", γραμμή);
/* βρείτε το μήκος της συμβολοσειράς */
/* strlen φέρνει πίσω */
/* μήκος ως τύπος size_t */
printf("Μήκος γραμμής: %d\n", (int)strlen(line));
/* εύρεση εμφάνισης υποσυμβολοσειρών */
if ( (sub_text = strchr ( γραμμή, 'W' ) )!= NULL )
printf("Συμβολοσειρά που ξεκινά με \"W\" ->%s\n",
sub_text);
if ( ( sub_text = strchr (γραμμή, 'w' ) )!= NULL )
printf("Συμβολοσειρά που ξεκινά με \"w\" ->%s\n",
sub_text);
if ( ( sub_text = strchr ( sub_text, 'u' ) )!= NULL )
printf("Συμβολοσειρά που ξεκινά με \"w\" ->%s\n",
sub_text);
}
Η έξοδος του προγράμματος θα εμφανιστεί ως εξής:
Γραμμή: γεια, είμαι χορδή.
Γραμμή: γεια, είμαι χορδή. τι εισαι
Μήκος γραμμής: 35
Συμβολοσειρά που ξεκινά με "w" ->τι είσαι;
Συμβολοσειρά που αρχίζει με "w" ->u;
Λειτουργίες
Ο καλύτερος τρόπος για να αναπτύξετε και να διατηρήσετε ένα μεγάλο πρόγραμμα είναι να το κατασκευάσετε από μικρότερα κομμάτια, καθένα από τα οποία είναι πιο εύκολο στη διαχείριση (μια τεχνική που μερικές φορές αναφέρεται ως Divide and Conquer). Οι λειτουργίες επιτρέπουν στον προγραμματιστή να διαμορφώσει το πρόγραμμα.
Οι λειτουργίες επιτρέπουν σε πολύπλοκα προγράμματα να χωρίζονται σε μικρά μπλοκ, καθένα από τα οποία είναι ευκολότερο να γραφτεί, να διαβαστεί και να διατηρηθεί. Έχουμε ήδη συναντήσει τη συνάρτηση main και χρησιμοποιήσαμε το printf από την τυπική βιβλιοθήκη. Μπορούμε φυσικά να φτιάξουμε τις δικές μας συναρτήσεις και αρχεία κεφαλίδων. Μια συνάρτηση έχει την ακόλουθη διάταξη:
όνομα συνάρτησης τύπου επιστροφής (λίστα ορισμάτων εάν χρειάζεται)
{
τοπικές δηλώσεις·
δηλώσεις ;
επιστροφής-τιμής?
}
Εάν παραληφθεί ο τύπος επιστροφής, το C ορίζει από προεπιλογή int. Η τιμή επιστροφής πρέπει να είναι του δηλωθέντος τύπου. Όλες οι μεταβλητές που δηλώνονται εντός συναρτήσεων ονομάζονται τοπικές μεταβλητές, καθώς είναι γνωστές μόνο στη συνάρτηση στην οποία έχουν οριστεί.
Ορισμένες συναρτήσεις έχουν μια λίστα παραμέτρων που παρέχει μια μέθοδο επικοινωνίας μεταξύ της συνάρτησης και της λειτουργικής μονάδας που κάλεσε τη συνάρτηση. Οι παράμετροι είναι επίσης τοπικές μεταβλητές, καθώς δεν είναι διαθέσιμες εκτός της συνάρτησης. Τα προγράμματα που καλύπτονται μέχρι στιγμής έχουν όλα κύρια, η οποία είναι μια λειτουργία.
Μια συνάρτηση μπορεί απλώς να εκτελέσει μια εργασία χωρίς να επιστρέψει καμία τιμή, οπότε έχει την ακόλουθη διάταξη:
void συνάρτησης-όνομα (λίστα ορισμάτων εάν είναι απαραίτητο)
{
τοπικές δηλώσεις ;
δηλώσεις?
}
Τα ορίσματα μεταβιβάζονται πάντα με τιμή στις κλήσεις της συνάρτησης C. Αυτό σημαίνει ότι τα τοπικά αντίγραφα των τιμών των ορισμάτων μεταβιβάζονται στις ρουτίνες. Οποιαδήποτε αλλαγή γίνει στα ορίσματα εσωτερικά στη συνάρτηση γίνεται μόνο στα τοπικά αντίγραφα των ορισμάτων.
Για να αλλάξετε ή να ορίσετε ένα όρισμα στη λίστα ορισμάτων, αυτό το όρισμα πρέπει να μεταβιβαστεί ως διεύθυνση. Χρησιμοποιείτε κανονικές μεταβλητές εάν η συνάρτηση δεν αλλάζει τις τιμές αυτών των ορισμάτων. ΠΡΕΠΕΙ να χρησιμοποιήσετε δείκτες εάν η συνάρτηση αλλάζει τις τιμές αυτών των ορισμάτων.
Ας μάθουμε με παραδείγματα:
#include <stdio.h>
ανταλλαγή κενών (int *a, int *b)
{
int temp?
temp = *a;
*a = *b;
*b = θερμοκρασία;
printf(" From function exchange: ");
printf("a = %d, b = %d\n", *a, *b);
}
void main()
{
int a, b;
a = 5;
b = 7;
printf("From main: a = %d, b = %d\n", a, b);
ανταλλαγή (&a, &b);
printf("Επιστροφή στην κύρια: ");
printf("a = %d, b = %d\n", a, b);
}
Και η έξοδος αυτού του προγράμματος θα εμφανιστεί ως εξής:
Από κύρια: a = 5, b = 7
Από ανταλλαγή συναρτήσεων: a = 7, b = 5
Πίσω στην κύρια: a = 7, b = 5
Ας δούμε ένα άλλο παράδειγμα. Το παρακάτω παράδειγμα χρησιμοποιεί μια συνάρτηση που ονομάζεται τετράγωνο και γράφει το τετράγωνο των αριθμών μεταξύ 1 και 10.
#include <stdio.h>
int τετράγωνο(int x); /* Πρωτότυπο λειτουργίας */
int main()
{
int μετρητής?
για (counter=1; counter<=10; counter++)
printf("Το τετράγωνο του %d είναι %d\n", μετρητής, τετράγωνο(μετρητής));
επιστροφή 0;
}
/* Ορισμός της συνάρτησης 'τετράγωνο' */
int τετράγωνο (int x)
{
επιστροφή x * x;
}
Η έξοδος αυτού του προγράμματος θα εμφανιστεί ως εξής:
Το τετράγωνο του 1 είναι 1
Το τετράγωνο του 2 είναι 4
Το τετράγωνο του 3 είναι 9
Το τετράγωνο του 4 είναι 16
Το τετράγωνο του 5 είναι 25
Το τετράγωνο του 6 είναι 36
Το τετράγωνο του 7 είναι 49
Το τετράγωνο του 8 είναι 64
Το τετράγωνο του 9 είναι 81
Το τετράγωνο του 10 είναι 100
Το τετράγωνο πρωτότυπου συνάρτησης δηλώνει μια συνάρτηση που παίρνει μια ακέραια παράμετρο και επιστρέφει έναν ακέραιο. Όταν ο μεταγλωττιστής φτάσει στην κλήση συνάρτησης στο τετράγωνο στο κύριο πρόγραμμα, μπορεί να ελέγξει την κλήση συνάρτησης σε σχέση με τον ορισμό της συνάρτησης.
Όταν το πρόγραμμα φτάσει στη γραμμή που καλεί τη συνάρτηση τετράγωνο, το πρόγραμμα μεταβαίνει στη συνάρτηση και την εκτελεί πριν συνεχίσει τη διαδρομή του μέσω του κύριου προγράμματος. Προγράμματα που δεν έχουν τύπο επιστροφής θα πρέπει να δηλώνονται χρησιμοποιώντας void. Έτσι, οι παράμετροι της συνάρτησης μπορεί να είναι Pass By Value ή Pass By Reference.
Μια αναδρομική συνάρτηση είναι μια συνάρτηση που καλεί τον εαυτό της. Και αυτή η διαδικασία ονομάζεται αναδρομή.
Λειτουργίες Pass By Value
Οι παράμετροι της συνάρτησης τετραγώνου στο προηγούμενο παράδειγμα μεταβιβάζονται με τιμή. Αυτό σημαίνει ότι μόνο ένα αντίγραφο της μεταβλητής έχει περάσει στη συνάρτηση. Τυχόν αλλαγές στην τιμή δεν θα αντανακλώνται πίσω στη λειτουργία κλήσης.
Το παρακάτω παράδειγμα χρησιμοποιεί τιμή pass-by-value και αλλάζει την τιμή της παραμέτρου που πέρασε, η οποία δεν έχει καμία επίδραση στη συνάρτηση κλήσης. Η συνάρτηση count_down έχει δηλωθεί ως άκυρη καθώς δεν υπάρχει τύπος επιστροφής.
#include <stdio.h>
void count_down(int x);
int main()
{
int μετρητής?
για (counter=1; counter<=10; counter++)
count_down(counter);
επιστροφή 0;
}
void count_down(int x)
{
int μετρητής?
για (counter = x; counter > 0; counter--)
{
printf("%d ", x);
x--;
}
putchar('\n');
}
Η έξοδος του προγράμματος θα εμφανιστεί ως εξής:
1
2 1
3 2 1
4 3 2 1
5 4 3 2 1
6 5 4 3 2 1
7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
Ας δούμε ένα άλλο Παράδειγμα C Pass By Value για να το κατανοήσουμε καλύτερα. Το ακόλουθο παράδειγμα μετατρέπει έναν αριθμό μεταξύ 1 και 30.000 που πληκτρολογεί ο χρήστης σε λέξεις.
#include <stdio.h>
void do_units(int num);
void do_tens(int num);
void do_teens(int num);
int main()
{
int num, υπόλοιπο?
κάνω
{
printf("Εισαγάγετε έναν αριθμό μεταξύ 1 και 30.000: ");
scanf("%d", &num);
} while (αριθμός < 1 || αριθμός > 30000);
υπόλοιπο = αριθμός;
printf("%d σε λέξεις = ", num);
do_tens(residue/1000);
εάν (αριθμός >= 1000)
printf("χιλιάδες");
υπόλειμμα %= 1000;
do_units(residue/100);
εάν (υπόλειμμα >= 100)
{
printf("εκατό");
}
εάν (αριθμός > 100 && αριθμός%100 > 0)
printf("και ");
υπόλειμμα %=100;
do_tens(residue);
putchar('\n');
επιστροφή 0;
}
void do_units(int num)
{
διακόπτης (αριθμός)
{
περίπτωση 1:
printf("one");
διακοπή;
περίπτωση 2:
printf("δύο");
διακοπή;
περίπτωση 3:
printf("τρία");
διακοπή;
περίπτωση 4:
printf("τέσσερα");
διακοπή;
περίπτωση 5:
printf("πέντε");
διακοπή;
περίπτωση 6:
printf("six");
διακοπή;
περίπτωση 7:
printf("επτά");
διακοπή;
περίπτωση 8:
printf("οκτώ");
διακοπή;
περίπτωση 9:
printf("εννέα");
}
}
void do_tens (int num)
{
διακόπτης (αριθμός/10)
{
περίπτωση 1:
do_teens(αριθμός);
διακοπή;
περίπτωση 2:
printf("είκοσι");
διακοπή;
περίπτωση 3:
printf("τριάντα");
διακοπή;
περίπτωση 4:
printf("σαράντα");
διακοπή;
περίπτωση 5:
printf("πενήντα");
διακοπή;
περίπτωση 6:
printf("εξήντα");
διακοπή;
περίπτωση 7:
printf("εβδομήντα");
διακοπή;
περίπτωση 8:
printf("ογδόντα");
διακοπή;
περίπτωση 9:
printf("ενενήντα");
}
εάν (αριθμός/10 != 1)
do_units(αριθμός%10);
}
void do_teens (int num)
{
διακόπτης (αριθμός)
{
περίπτωση 10:
printf("ten");
διακοπή;
περίπτωση 11:
printf("έντεκα");
διακοπή;
περίπτωση 12:
printf("δώδεκα");
διακοπή;
περίπτωση 13:
printf("δεκατρία");
διακοπή;
περίπτωση 14:
printf("δεκατέσσερα");
διακοπή;
περίπτωση 15:
printf("δεκαπέντε");
διακοπή;
περίπτωση 16:
printf("δεκαέξι");
διακοπή;
περίπτωση 17:
printf("δεκαεπτά");
διακοπή;
περίπτωση 18:
printf("δεκαοκτώ");
διακοπή;
περίπτωση 19:
printf("δεκαεννέα");
}
}
και η έξοδος του προγράμματος θα είναι η εξής:
Εισαγάγετε έναν αριθμό μεταξύ 1 και 30.000: 12345
12345 με λέξεις = δώδεκα χιλιάδες τριακόσιες σαράντα πέντε
Κλήση με αναφορά
Για να πραγματοποιήσετε κλήση προς αναφορά συνάρτησης, αντί να μεταβιβάσετε την ίδια τη μεταβλητή, περάστε τη διεύθυνση της μεταβλητής. Η διεύθυνση της μεταβλητής μπορεί να ληφθεί χρησιμοποιώντας τον τελεστή &. Το παρακάτω καλεί μια συνάρτηση swap που μεταβιβάζει τη διεύθυνση των μεταβλητών αντί για τις πραγματικές τιμές.
swap(&x, &y);
Αποαναφορά
Το πρόβλημα που έχουμε τώρα είναι ότι η συνάρτηση swap έχει περάσει τη διεύθυνση και όχι τη μεταβλητή, επομένως πρέπει να αποαναφερθούμε τις μεταβλητές έτσι ώστε να κοιτάμε τις πραγματικές τιμές και όχι τις διευθύνσεις των μεταβλητών για να τις ανταλλάξουμε.
Η αποαναφορά επιτυγχάνεται στο C χρησιμοποιώντας τη σημείωση του δείκτη (*). Με απλά λόγια, αυτό σημαίνει ότι τοποθετείτε ένα * πριν από κάθε μεταβλητή πριν τη χρησιμοποιήσετε, ώστε να αναφέρεται στην τιμή της μεταβλητής και όχι στη διεύθυνσή της. Το παρακάτω πρόγραμμα απεικονίζει την περαστική αναφορά για την εναλλαγή δύο τιμών.
#include <stdio.h>
void swap(int *x, int *y);
int main()
{
int x=6, y=10;
printf("Πριν από την εναλλαγή συνάρτησης, x = %d και y =
%d\n\n", x, y);
swap(&x, &y);
printf("Μετά την εναλλαγή συνάρτησης, x = %d και y =
%d\n\n", x, y);
επιστροφή 0;
}
void swap(int *x, int *y)
{
int temp = *x;
*x = *y;
*y = θερμοκρασία;
}
Ας δούμε την έξοδο του προγράμματος:
Πριν από την εναλλαγή συνάρτησης, x = 6 και y = 10
Μετά την εναλλαγή συνάρτησης, x = 10 και y = 6
Οι συναρτήσεις μπορεί να είναι αναδρομικές που είναι μια συνάρτηση που μπορεί να καλέσει τον εαυτό της. Κάθε κλήση προς τον εαυτό της απαιτεί να προωθείται η τρέχουσα κατάσταση της συνάρτησης στη στοίβα. Είναι σημαντικό να θυμάστε αυτό το γεγονός, καθώς είναι εύκολο να δημιουργήσετε μια υπερχείλιση στοίβας, δηλαδή έχει εξαντληθεί ο χώρος στη στοίβα για να τοποθετήσετε περισσότερα δεδομένα.
Το παρακάτω παράδειγμα υπολογίζει το Factorial ενός αριθμού χρησιμοποιώντας αναδρομή. Ένα παραγοντικό είναι ένας αριθμός που πολλαπλασιάζεται με κάθε άλλο ακέραιο κάτω από τον εαυτό του, μέχρι το 1. Για παράδειγμα, το παραγοντικό του αριθμού 6 είναι:
Παραγοντικός 6 = 6 * 5 * 4 * 3 * 2 * 1
Επομένως, το παραγοντικό του 6 είναι 720. Μπορεί να φανεί από το παραπάνω παράδειγμα ότι παραγοντικό 6 = 6 * παραγοντικό 5. Ομοίως, παραγοντικό 5 = 5 * παραγοντικό 4, και ούτω καθεξής.
Ακολουθεί ο γενικός κανόνας για τον υπολογισμό των παραγοντικών αριθμών.
παραγοντικό(n) = n * παραγοντικό(n-1)
Ο παραπάνω κανόνας τελειώνει όταν n = 1, καθώς το παραγοντικό του 1 είναι 1. Ας προσπαθήσουμε να τον κατανοήσουμε καλύτερα με τη βοήθεια του παραδείγματος:
#include <stdio.h>
long int παραγοντικό (int num);
int main()
{
int num;
long int f;
printf("Εισαγάγετε έναν αριθμό: ");
scanf("%d", &num);
f = παραγοντικό(αριθμός);
printf("factorial of %d is %ld\n", num, f);
επιστροφή 0;
}
long int παραγοντικό (int num)
{
αν (αριθμός == 1)
επιστροφή 1;
αλλού
επιστροφή αριθ. * παραγοντικός(αριθμός-1);
}
Ας δούμε την έξοδο της εκτέλεσης αυτού του προγράμματος:
Εισαγάγετε έναν αριθμό: 7
παραγοντικό του 7 είναι 5040
Εκχώρηση μνήμης σε C
Ο μεταγλωττιστής C έχει μια βιβλιοθήκη εκχώρησης μνήμης, που ορίζεται στο malloc.h. Η μνήμη δεσμεύεται χρησιμοποιώντας τη συνάρτηση malloc και επιστρέφει έναν δείκτη στη διεύθυνση. Χρειάζεται μία παράμετρος, το μέγεθος της μνήμης που απαιτείται σε byte.
Το ακόλουθο παράδειγμα εκχωρεί χώρο για τη συμβολοσειρά "γεια στον κόσμο".
ptr = (char *)malloc(strlen("Hello world") + 1);
Το επιπλέον ένα byte απαιτείται για να ληφθεί υπόψη ο χαρακτήρας τερματισμού συμβολοσειράς, '\0'. Το (char *) ονομάζεται cast και αναγκάζει τον τύπο επιστροφής να είναι char *.
Καθώς οι τύποι δεδομένων έχουν διαφορετικά μεγέθη και το malloc επιστρέφει το χώρο σε byte, είναι καλή πρακτική για λόγους φορητότητας να χρησιμοποιείται ο τελεστής sizeof κατά τον καθορισμό ενός μεγέθους προς εκχώρηση.
Το ακόλουθο παράδειγμα διαβάζει μια συμβολοσειρά στο buffer του πίνακα χαρακτήρων και στη συνέχεια εκχωρεί την ακριβή ποσότητα μνήμης που απαιτείται και την αντιγράφει σε μια μεταβλητή που ονομάζεται "ptr".
#include <string.h>
#include <malloc.h>
int main()
{
char *ptr, buffer[80];
printf("Εισαγάγετε μια συμβολοσειρά: ");
gets(buffer);
ptr = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(ptr, buffer);
printf("Εισαγάγατε: %s\n", ptr);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Εισαγάγετε μια συμβολοσειρά: Η Ινδία είναι η καλύτερη
Εισαγάγατε: Η Ινδία είναι η καλύτερη
Ανακατανομή μνήμης
Είναι πιθανό πολλές φορές ενώ προγραμματίζετε να θέλετε να ανακατανείμετε τη μνήμη. Αυτό γίνεται με τη συνάρτηση realloc. Η συνάρτηση realloc λαμβάνει δύο παραμέτρους, τη διεύθυνση βάσης της μνήμης που θέλετε να αλλάξετε το μέγεθος και τον χώρο που θέλετε να κρατήσετε και επιστρέφει έναν δείκτη στη διεύθυνση βάσης.
Ας υποθέσουμε ότι έχουμε κρατήσει χώρο για έναν δείκτη που ονομάζεται msg και θέλουμε να ανακατανείμουμε χώρο στον χώρο που καταλαμβάνει ήδη, συν το μήκος μιας άλλης συμβολοσειράς, τότε μπορούμε να χρησιμοποιήσουμε τα εξής.
msg = (char *)realloc(msg, (strlen(msg) + strlen(buffer) + 1)*sizeof(char));
Το παρακάτω πρόγραμμα απεικονίζει τη χρήση των malloc, realloc και free. Ο χρήστης εισάγει μια σειρά από συμβολοσειρές που ενώνονται μεταξύ τους. Το πρόγραμμα σταματά την ανάγνωση συμβολοσειρών όταν εισάγεται μια κενή συμβολοσειρά.
#include <string.h>
#include <malloc.h>
int main()
{
char buffer[80], *msg;
int firstTime=0;
κάνω
{
printf("\nΕισαγάγετε μια πρόταση: ");
gets(buffer);
αν (!πρώτη φορά)
{
msg = (char *)malloc((strlen(buffer) + 1) *
sizeof(char));
strcpy(msg, buffer);
firstTime = 1;
}
αλλού
{
msg = (char *)realloc(msg, (strlen(msg) +
strlen(buffer) + 1) * sizeof(char));
strcat(msg, buffer);
}
puts(msg);
} while(strcmp(buffer, ""));
δωρεάν (msg);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Πληκτρολογήστε μια πρόταση: Μια φορά κι έναν καιρό
Μια φορά κι έναν καιρό
Πληκτρολογήστε μια πρόταση: υπήρχε ένας βασιλιάς
Μια φορά κι έναν καιρό ήταν ένας βασιλιάς
Πληκτρολογήστε μια πρόταση: ο βασιλιάς ήταν
Μια φορά κι έναν καιρό ήταν ένας βασιλιάς ο βασιλιάς ήταν
Εισαγάγετε μια πρόταση:
Μια φορά κι έναν καιρό ήταν ένας βασιλιάς που ήταν ο βασιλιάς
Αποδέσμευση μνήμης
Όταν τελειώσετε με τη μνήμη που έχει εκχωρηθεί, δεν πρέπει ποτέ να ξεχάσετε να ελευθερώσετε τη μνήμη, καθώς θα απελευθερώσει πόρους και θα βελτιώσει την ταχύτητα. Για να αποδεσμεύσετε την εκχωρημένη μνήμη, χρησιμοποιήστε τη λειτουργία δωρεάν.
δωρεάν (ptr);
Δομές
Εκτός από τους βασικούς τύπους δεδομένων, το C διαθέτει μηχανισμό δομής που σας επιτρέπει να ομαδοποιήσετε στοιχεία δεδομένων που σχετίζονται μεταξύ τους με ένα κοινό όνομα. Αυτό αναφέρεται συνήθως ως τύπος που καθορίζεται από το χρήστη.
Η λέξη-κλειδί struct ξεκινά τον ορισμό της δομής και μια ετικέτα δίνει το μοναδικό όνομα στη δομή. Οι τύποι δεδομένων και τα ονόματα μεταβλητών που προστίθενται στη δομή είναι μέλη της δομής. Το αποτέλεσμα είναι ένα πρότυπο δομής που μπορεί να χρησιμοποιηθεί ως προσδιοριστής τύπου. Ακολουθεί μια δομή με ετικέτα μήνα.
μήνας κατασκευής
{
όνομα char[10];
char συντομογραφία[4];
int ημέρες?
};
Ένας τύπος δομής ορίζεται συνήθως κοντά στην αρχή ενός αρχείου χρησιμοποιώντας μια δήλωση typedef. Το typedef ορίζει και ονομάζει έναν νέο τύπο, επιτρέποντας τη χρήση του σε όλο το πρόγραμμα. Το typedef συνήθως εμφανίζεται αμέσως μετά τις δηλώσεις #define και #include σε ένα αρχείο.
Η λέξη-κλειδί typedef μπορεί να χρησιμοποιηθεί για τον ορισμό μιας λέξης που αναφέρεται στη δομή αντί για τον καθορισμό της λέξης-κλειδιού struct με το όνομα της δομής. Είναι συνηθισμένο να ονομάζουμε το typedef με κεφαλαία γράμματα. Εδώ είναι τα παραδείγματα ορισμού δομής.
typedef struct {
όνομα char[64];
μάθημα χαρακτήρων[128];
int ηλικία?
int έτος?
} μαθητής;
Αυτό ορίζει έναν νέο τύπο σπουδαστών μεταβλητές τύπου student μπορούν να δηλωθούν ως εξής.
φοιτητής st_rec;
Παρατηρήστε πόσο παρόμοιο είναι αυτό με τη δήλωση int ή float. Το όνομα της μεταβλητής είναι st_rec, έχει μέλη που ονομάζονται όνομα, μάθημα, ηλικία και έτος. Ομοίως,
typedef struct στοιχείο
{
char δεδομένα?
struct στοιχείο *next;
} ΣΤΟΙΧΕΙΑ;
Μια μεταβλητή του στοιχείου δομής τύπου που ορίζεται από το χρήστη μπορεί τώρα να δηλωθεί ως εξής.
STACKELEMENT *στοίβα;
Εξετάστε την ακόλουθη δομή:
struct μαθητής
{
char *όνομα;
int βαθμός?
};
Ένας δείκτης για τη δομή του μαθητή μπορεί να οριστεί ως εξής.
struct student *hnc;
Κατά την πρόσβαση σε έναν δείκτη σε μια δομή, ο τελεστής δείκτη μέλους, -> χρησιμοποιείται αντί για τον τελεστή τελείας. Για να προσθέσετε έναν βαθμό σε μια δομή,
s.βαθμός = 50;
Μπορείτε να ορίσετε έναν βαθμό στη δομή ως εξής.
s->βαθμός = 50;
Όπως και με τους βασικούς τύπους δεδομένων, εάν θέλετε οι αλλαγές που πραγματοποιούνται σε μια συνάρτηση στις περασμένες παραμέτρους να είναι επίμονες, πρέπει να περάσετε μέσω αναφοράς (διαβιβάστε τη διεύθυνση). Ο μηχανισμός είναι ακριβώς ο ίδιος με τους βασικούς τύπους δεδομένων. Περάστε τη διεύθυνση και ανατρέξτε στη μεταβλητή χρησιμοποιώντας συμβολισμό δείκτη.
Έχοντας ορίσει τη δομή, μπορείτε να δηλώσετε ένα στιγμιότυπο της και να εκχωρήσετε τιμές στα μέλη χρησιμοποιώντας τον συμβολισμό κουκκίδων. Το ακόλουθο παράδειγμα επεξηγεί τη χρήση της δομής μήνα.
#include <stdio.h>
#include <string.h>
μήνας κατασκευής
{
όνομα char[10];
char συντομογραφία[4];
int ημέρες?
};
int main()
{
struct μήνα m;
strcpy(m.name, "Ιανουάριος");
strcpy(m.συντομογραφία, "Ιαν");
m.days = 31;
printf("%s συντομεύεται ως %s και έχει %d ημέρες\n", m.name, m.abbreviation, m.days);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Ο Ιανουάριος συντομεύεται ως Ιαν και έχει 31 ημέρες
Όλοι οι μεταγλωττιστές ANSI C σάς επιτρέπουν να αντιστοιχίσετε μια δομή σε μια άλλη, εκτελώντας ένα αντίγραφο κατά μέλη. Εάν είχαμε δομές μήνα που ονομάζονταν m1 και m2, τότε θα μπορούσαμε να εκχωρήσουμε τις τιμές από m1 σε m2 με τα εξής:
- Δομή με μέλη του δείκτη.
- Δομή Αρχικοποιεί.
- Μεταβίβαση μιας δομής σε μια συνάρτηση.
- Δείκτες και Δομές.
Δομές με μέλη του δείκτη στο C
Η διατήρηση συμβολοσειρών σε πίνακα σταθερού μεγέθους είναι αναποτελεσματική χρήση της μνήμης. Μια πιο αποτελεσματική προσέγγιση θα ήταν η χρήση δεικτών. Οι δείκτες χρησιμοποιούνται σε δομές με τον ίδιο ακριβώς τρόπο που χρησιμοποιούνται στους κανονικούς ορισμούς δεικτών. Ας δούμε ένα παράδειγμα:
#include <string.h>
#include <malloc.h>
μήνας κατασκευής
{
char *όνομα;
char *συντομογραφία;
int ημέρες?
};
int main()
{
struct μήνα m;
m.name = (char *)malloc((strlen("Ιανουάριος")+1) *
sizeof(char));
strcpy(m.name, "Ιανουάριος");
m.abbreviation = (char *)malloc((strlen("Jan")+1) *
sizeof(char));
strcpy(m.συντομογραφία, "Ιαν");
m.days = 31;
printf("%s συντομεύεται ως %s και έχει %d ημέρες\n",
m.name, m.abbreviation, m.days);
επιστροφή 0;
}
Η έξοδος του προγράμματος θα είναι η εξής:
Ο Ιανουάριος συντομεύεται ως Ιαν και έχει 31 ημέρες
Structure Initializers σε C
Για την παροχή ενός συνόλου αρχικών τιμών για τη δομή, μπορούν να προστεθούν Initialisers στη δήλωση δήλωσης. Καθώς οι μήνες ξεκινούν από το 1, αλλά οι πίνακες ξεκινούν από το μηδέν στο C, ένα επιπλέον στοιχείο στη θέση μηδέν που ονομάζεται ανεπιθύμητη ενέργεια, έχει χρησιμοποιηθεί στο ακόλουθο παράδειγμα.
#include <stdio.h>
#include <string.h>
μήνας κατασκευής
{
char *όνομα;
char *συντομογραφία;
int ημέρες?
} month_details[] =
{
"Junk", "Junk", 0,
"Ιανουάριος", "Ιανουάριος", 31,
"Φεβρουάριος", "Φεβρουάριος", 28,
"Μάρτιος", "Μαρτ", 31,
"Απρίλιος", "Απρίλιος", 30,
"Μάιος", "Μάιος", 31,
"Ιούνιος", "Ιούνιος", 30,
"Ιούλιος", "Ιούλιος", 31,
"Αύγουστος", "Αύγουστος", 31,
"Σεπτέμβριος", "Σεπτέμβριος", 30,
"Οκτώβριος", "Οκτώβριος", 31,
"Νοέμβριος", "Νοέμβριος", 30,
"Δεκέμβριος", "Δεκέμβριος", 31
};
int main()
{
int μετρητής?
για (counter=1; counter<=12; counter++)
printf("%s συντομεύεται ως %s και έχει %d ημέρες\n",
month_details[counter].name,
month_details[counter].συντομογραφία,
month_details[counter].days);
επιστροφή 0;
}
Και η έξοδος θα εμφανιστεί ως εξής:
Ο Ιανουάριος συντομεύεται ως Ιαν και έχει 31 ημέρες
Ο Φεβρουάριος συντομεύεται ως Φεβ και έχει 28 ημέρες
Ο Μάρτιος συντομεύεται ως Μαρ και έχει 31 ημέρες
Ο Απρίλιος συντομεύεται ως Απρίλιος και έχει 30 ημέρες
Ο Μάιος συντομεύεται ως Μάιος και έχει 31 ημέρες
Ο Ιούνιος συντομεύεται ως Ιούνιος και έχει 30 ημέρες
Ο Ιούλιος συντομεύεται ως Ιούλιος και έχει 31 ημέρες
Ο Αύγουστος συντομεύεται ως Αύγουστος και έχει 31 ημέρες
Ο Σεπτέμβριος συντομεύεται ως Σεπ και έχει 30 ημέρες
Ο Οκτώβριος συντομεύεται ως Οκτώβριος και έχει 31 ημέρες
Ο Νοέμβριος συντομεύεται ως Νοέμβριος και έχει 30 ημέρες
Ο Δεκέμβριος συντομεύεται ως Δεκέμβριος και έχει 31 ημέρες
Μεταβίβαση δομών σε συναρτήσεις στο C
Οι δομές μπορούν να μεταβιβαστούν ως παράμετροι σε μια συνάρτηση, όπως και οποιοσδήποτε από τους βασικούς τύπους δεδομένων. Το ακόλουθο παράδειγμα χρησιμοποιεί μια δομή που ονομάζεται ημερομηνία που έχει μεταβιβαστεί σε μια συνάρτηση isLeapYear για να προσδιορίσει εάν το έτος είναι δίσεκτο.
Κανονικά θα περνούσατε μόνο την τιμή ημέρας, αλλά ολόκληρη η δομή μεταβιβάζεται για να απεικονίσει τη μετάβαση δομών σε συναρτήσεις.
#include <stdio.h>
#include <string.h>
μήνας κατασκευής
{
char *όνομα;
char *συντομογραφία;
int ημέρες?
} month_details[] =
{
"Junk", "Junk", 0,
"Ιανουάριος", "Ιανουάριος", 31,
"Φεβρουάριος", "Φεβρουάριος", 28,
"Μάρτιος", "Μαρτ", 31,
"Απρίλιος", "Απρίλιος", 30,
"Μάιος", "Μάιος", 31,
"Ιούνιος", "Ιούνιος", 30,
"Ιούλιος", "Ιούλιος", 31,
"Αύγουστος", "Αύγουστος", 31,
"Σεπτέμβριος", "Σεπτέμβριος", 30,
"Οκτώβριος", "Οκτώβριος", 31,
"Νοέμβριος", "Νοέμβριος", 30,
"Δεκέμβριος", "Δεκέμβριος", 31
};
ημερομηνία κατασκευής
{
int ημέρα?
int μήνα?
int έτος?
};
int isLeapYear(ημερομηνία δομής d);
int main()
{
ημερομηνία κατασκευής d;
printf("Εισαγάγετε την ημερομηνία (π.χ.: 11/11/1980): ");
scanf("%d/%d/%d", &d.day, &d.month, &d.year);
printf("Η ημερομηνία %d %s %d είναι ", d.day,
μήνας_λεπτομέρειες[δ.μήνας].όνομα, δ.έτος);
if (isLeapYear(d) == 0)
printf("not");
puts("ένα δίσεκτο έτος");
επιστροφή 0;
}
int isLeapYear (ημερομηνία δομής δ)
{
αν ((d.έτος % 4 == 0 && d.έτος % 100 != 0) ||
δ.έτος % 400 == 0)
επιστροφή 1;
επιστροφή 0;
}
Και η εκτέλεση του προγράμματος θα είναι η εξής:
Εισαγάγετε την ημερομηνία (π.χ.: 11/11/1980): 9/12/1980
Η ημερομηνία 9 Δεκεμβρίου 1980 είναι δίσεκτο
Το ακόλουθο παράδειγμα εκχωρεί δυναμικά μια σειρά από δομές για την αποθήκευση των ονομάτων και του βαθμού των μαθητών. Στη συνέχεια, οι βαθμοί εμφανίζονται πίσω στον χρήστη με αύξουσα σειρά.
#include <string.h>
#include <malloc.h>
struct μαθητής
{
char *όνομα;
int βαθμός?
};
void swap(struct student *x, struct student *y);
int main()
{
struct Student *group;
char buffer[80];
int ψευδής?
int εσωτερικό, εξωτερικό?
int μετρητής, numStudents;
printf("Πόσοι μαθητές υπάρχουν στην ομάδα: ");
scanf("%d", &numStudents);
ομάδα = (δομή μαθητή *)malloc(numStudents *
sizeof(struct student));
για (counter=0; counter<numStudents; counter++)
{
spurious = getchar();
printf("Εισαγάγετε το όνομα του μαθητή: ");
gets(buffer);
group[counter].name = (char *)malloc((strlen(buffer)+1) * sizeof(char));
strcpy(group[counter].name, buffer);
printf("Εισαγάγετε βαθμό: ");
scanf("%d", &group[counter].grade);
}
για (εξωτερικό=0; εξωτερικό<numStudents; εξωτερικό++)
για (inner=0; inner<εξωτερικό; inner++)
αν (ομάδα[εξωτερική].βαθμός <
group[inner].grade)
swap(&group[εξωτερική], &group[inner]);
puts("Η ομάδα σε αύξουσα σειρά βαθμών ...");
για (counter=0; counter<numStudents; counter++)
printf("%s πέτυχε βαθμό %d \n",
group[counter].name,
group[counter].grade);
επιστροφή 0;
}
void swap (struct student *x, struct student *y)
{
struct φοιτητής θερμοκρασία?
temp.name = (char *)malloc((strlen(x->όνομα)+1) *
sizeof(char));
strcpy(temp.name, x->name);
temp.grade = x->βαθμός;
x->βαθμός = y->βαθμός;
x->όνομα = (char *)malloc((strlen(y->όνομα)+1) *
sizeof(char));
strcpy(x->όνομα, y->όνομα);
y->grade = temp.grade;
y->όνομα = (char *)malloc((strlen(temp.name)+1) *
sizeof(char));
strcpy(y->όνομα, temp.name);
}
Η εκτέλεση της εξόδου θα είναι η εξής:
Πόσοι μαθητές υπάρχουν στην ομάδα: 4
Πληκτρολογήστε το όνομα του μαθητή: Anuraaj
Εισαγάγετε βαθμό: 7
Πληκτρολογήστε το όνομα του μαθητή: Honey
Εισαγάγετε βαθμό: 2
Πληκτρολογήστε το όνομα του μαθητή: Meetushi
Εισαγάγετε βαθμό: 1
Πληκτρολογήστε το όνομα του μαθητή: Deepti
Εισαγάγετε βαθμό: 4
Η ομάδα με αύξουσα σειρά βαθμών ...
Ο Meetushi πέτυχε τον Βαθμό 1
Το Μέλι πέτυχε τον Βαθμό 2
Ο Deepti πέτυχε τον Βαθμό 4
Ο Anuraaj πέτυχε τον Βαθμό 7
Ενωση
Μια ένωση σάς επιτρέπει έναν τρόπο να βλέπετε τα ίδια δεδομένα με διαφορετικούς τύπους ή να χρησιμοποιείτε τα ίδια δεδομένα με διαφορετικά ονόματα. Τα συνδικάτα είναι παρόμοια με τις δομές. Μια ένωση δηλώνεται και χρησιμοποιείται με τους ίδιους τρόπους που είναι μια δομή.
Ένα σωματείο διαφέρει από μια δομή στο ότι μόνο ένα από τα μέλη του μπορεί να χρησιμοποιηθεί κάθε φορά. Ο λόγος για αυτό είναι απλός. Όλα τα μέλη ενός σωματείου καταλαμβάνουν την ίδια περιοχή μνήμης. Είναι στρωμένα το ένα πάνω στο άλλο.
Οι ενώσεις ορίζονται και δηλώνονται με τον ίδιο τρόπο όπως οι δομές. Η μόνη διαφορά στις δηλώσεις είναι ότι η λέξη-κλειδί union χρησιμοποιείται αντί για struct. Για να ορίσετε μια απλή ένωση μιας μεταβλητής char και μιας ακέραιας μεταβλητής, θα γράψετε τα εξής:
ένωση κοινοποιήθηκε {
char c;
int i?
};
Αυτή η ένωση, κοινόχρηστη, μπορεί να χρησιμοποιηθεί για τη δημιουργία περιπτώσεων μιας ένωσης που μπορεί να περιέχει είτε μια τιμή χαρακτήρα c είτε μια ακέραια τιμή i. Αυτή είναι μια συνθήκη OR. Σε αντίθεση με μια δομή που θα κρατούσε και τις δύο τιμές, η ένωση μπορεί να κρατήσει μόνο μία τιμή κάθε φορά.
Μια ένωση μπορεί να αρχικοποιηθεί στη δήλωσή της. Επειδή μόνο ένα μέλος μπορεί να χρησιμοποιηθεί κάθε φορά και μόνο ένα μπορεί να αρχικοποιηθεί. Για να αποφευχθεί η σύγχυση, μόνο το πρώτο μέλος της ένωσης μπορεί να αρχικοποιηθεί. Ο ακόλουθος κώδικας δείχνει μια παρουσία της κοινής ένωσης που δηλώνεται και αρχικοποιείται:
union shared generic_variable = {`@'};
Παρατηρήστε ότι η ένωση generic_variable αρχικοποιήθηκε ακριβώς όπως θα αρχικοποιηθεί το πρώτο μέλος μιας δομής.
Τα μεμονωμένα μέλη της ένωσης μπορούν να χρησιμοποιηθούν με τον ίδιο τρόπο που μπορούν να χρησιμοποιηθούν τα μέλη της δομής χρησιμοποιώντας τον τελεστή μέλους (.). Ωστόσο, υπάρχει μια σημαντική διαφορά στην πρόσβαση στα μέλη του σωματείου.
Μόνο ένα μέλος του σωματείου πρέπει να έχει πρόσβαση κάθε φορά. Επειδή ένα σωματείο αποθηκεύει τα μέλη του το ένα πάνω στο άλλο, είναι σημαντικό να έχετε πρόσβαση μόνο σε ένα μέλος κάθε φορά.
Λέξη-κλειδί ένωσης
ετικέτα ένωσης {
union_member(s);
/* επιπλέον δηλώσεις μπορούν να πάνε εδώ */
}παράδειγμα;
Η λέξη-κλειδί ένωση χρησιμοποιείται για τη δήλωση συνδικάτων. Μια ένωση είναι μια συλλογή από μία ή περισσότερες μεταβλητές (union_members) που έχουν ομαδοποιηθεί κάτω από ένα μόνο όνομα. Επιπλέον, καθένα από αυτά τα μέλη της ένωσης καταλαμβάνει την ίδια περιοχή μνήμης.
Η λέξη-κλειδί ένωση προσδιορίζει την αρχή ενός ορισμού ένωσης. Ακολουθείται από μια ετικέτα που είναι το όνομα που δίνεται στην ένωση. Μετά την ετικέτα είναι τα μέλη του σωματείου κλεισμένα σε σιδεράκια.
Ένα παράδειγμα, η πραγματική δήλωση μιας ένωσης, μπορεί επίσης να οριστεί. Εάν ορίσετε τη δομή χωρίς την παρουσία, είναι απλώς ένα πρότυπο που μπορεί να χρησιμοποιηθεί αργότερα σε ένα πρόγραμμα για τη δήλωση δομών. Ακολουθεί η μορφή ενός προτύπου:
ετικέτα ένωσης {
union_member(s);
/* επιπλέον δηλώσεις μπορούν να πάνε εδώ */
};
Για να χρησιμοποιήσετε το πρότυπο, θα χρησιμοποιούσατε την ακόλουθη μορφή: παράδειγμα ετικέτας ένωσης;
Για να χρησιμοποιήσετε αυτήν τη μορφή, πρέπει να έχετε δηλώσει προηγουμένως μια ένωση με τη δεδομένη ετικέτα.
/* Δηλώστε ένα πρότυπο ένωσης που ονομάζεται ετικέτα */
ετικέτα ένωσης {
int num;
char alps?
}
/* Χρησιμοποιήστε το πρότυπο ένωσης */
union tag mixed_variable;
/* Δηλώστε μια ένωση και ένα παράδειγμα μαζί */
union generic_type_tag {
char c;
int i?
float f;
διπλό d?
} γενικό;
/* Αρχικοποίηση μιας ένωσης. */
union date_tag {
char πλήρης_ημερομηνία[9];
struct part_date_tag {
μήνας χαρακτήρων[2];
char break_value1;
char day[2];
char break_value2;
char έτος[2];
} part_date;
}date = {"09/12/80"};
Ας το καταλάβουμε καλύτερα με τη βοήθεια παραδειγμάτων:
#include <stdio.h>
int main()
{
ένωση
{
int αξία? /* Αυτό είναι το πρώτο μέρος της ένωσης */
struct
{
char πρώτα? /* Αυτές οι δύο τιμές είναι το δεύτερο μέρος του */
char δεύτερο?
} μισό;
} αριθμός;
μακρύς δείκτης?
για (δείκτης = 12 ; δείκτης < 300000L ; δείκτης += 35231L)
{
αριθμός.τιμή = ευρετήριο;
printf("%8x %6x %6x\n", αριθμός.τιμή,
αριθμός.μισό.πρώτα,
αριθμός.μισό.δευτερόλεπτο);
}
επιστροφή 0;
}
Και η έξοδος του προγράμματος θα εμφανιστεί ως εξής:
cc 0
89ab fab ff89
134a 4a 13
9ce9 ffe9 ff9c
2688 ff88 26
b027 27 ffb0
39c6 ffc6 39
c365 65 ffc3
4d04 4 4d
Μια πρακτική χρήση μιας ένωσης στην ανάκτηση δεδομένων
Ας δούμε τώρα μια πρακτική χρήση της ένωσης είναι ο προγραμματισμός ανάκτησης δεδομένων. Ας πάρουμε ένα μικρό παράδειγμα. Το παρακάτω πρόγραμμα είναι το μικρό μοντέλο προγράμματος σάρωσης κατεστραμμένου τομέα για μονάδα δισκέτας (α: ), ωστόσο δεν είναι το πλήρες μοντέλο λογισμικού σάρωσης κατεστραμμένου τομέα.
Ας εξετάσουμε το πρόγραμμα:
#include<dos.h>
#include<conio.h>
int main()
{
int rp, head, track, sektor, status;
char *buf;
ένωση REGS μέσα, έξω?
struct SREGS s;
clrscr();
/* Επαναφέρετε το σύστημα του δίσκου για προετοιμασία στο δίσκο */
printf("\n Επαναφορά του συστήματος δίσκου....");
for(rp=0;rp<=2;rp++)
{
in.h.ah = 0;
in.h.dl = 0x00;
int86(0x13,&in,&out);
}
printf("\n\n\n Τώρα δοκιμάζουμε το δίσκο για κακούς τομείς...");
/* σάρωση για κατεστραμμένους τομείς */
for(track=0;track<=79;track++)
{
for(head=0;head<=1;head++)
{
για(τομέας=1;τομέας<=18;τομέας++)
{
in.h.ah = 0x04;
in.h.al = 1;
in.h.dl = 0x00;
in.h.ch = κομμάτι;
in.h.dh = κεφάλι;
in.h.cl = τομέας;
in.x.bx = FP_OFF(buf);
s.es = FP_SEG(buf);
int86x(0x13,&in,&out,&s);
if(out.x.cflag)
{
status=out.h.ah;
printf("\n track:%d Head:%d Sector:%d Status ==0x%X",track,head,sector,status);
}
}
}
}
printf("\n\n\nΤέλος");
επιστροφή 0;
}
Τώρα ας δούμε πώς θα είναι η έξοδος του εάν υπάρχει κακός τομέας στη δισκέτα:
Επαναφορά του συστήματος δίσκου....
Τώρα δοκιμάζουμε το δίσκο για κακούς τομείς....
track:0 Head:0 Sector:4 Κατάσταση ==0xA
track:0 Head:0 Sector:5 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:4 Κατάσταση ==0xA
track:1 Head:0 Sector:5 Κατάσταση ==0xA
track:1 Head:0 Sector:6 Κατάσταση ==0xA
track:1 Head:0 Sector:7 Κατάσταση ==0xA
track:1 Head:0 Sector:8 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:11 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:12 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:13 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:14 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:15 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:16 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:17 Κατάσταση ==0xA
κομμάτι:1 Επικεφαλίδα:0 Τομέας:18 Κατάσταση ==0xA
track:1 Head:1 Sector:5 Κατάσταση ==0xA
track:1 Head:1 Sector:6 Κατάσταση ==0xA
track:1 Head:1 Sector:7 Κατάσταση ==0xA
track:1 Head:1 Sector:8 Κατάσταση ==0xA
track:1 Head:1 Sector:9 Κατάσταση ==0xA
track:1 Head:1 Sector:10 Κατάσταση ==0xA
track:1 Head:1 Sector:11 Status ==0xA
track:1 Head:1 Sector:12 Status ==0xA
track:1 Head:1 Sector:13 Status ==0xA
track:1 Head:1 Sector:14 Status ==0xA
track:1 Head:1 Sector:15 Κατάσταση ==0xA
track:1 Head:1 Sector:16 Κατάσταση ==0xA
track:1 Head:1 Sector:17 Κατάσταση ==0xA
track:1 Head:1 Sector:18 Κατάσταση ==0xA
κομμάτι:2 Επικεφαλίδα:0 Τομέας:4 Κατάσταση ==0xA
κομμάτι:2 Επικεφαλίδα:0 Τομέας:5 Κατάσταση ==0xA
κομμάτι:14 Επικεφαλίδα:0 Τομέας:6 Κατάσταση ==0xA
Γινώμενος
Μπορεί να είναι λίγο δύσκολο να κατανοήσουμε τις λειτουργίες και τις διακοπές που χρησιμοποιούνται σε αυτό το πρόγραμμα για την επαλήθευση του δίσκου για κατεστραμμένους τομείς και την επαναφορά του συστήματος του δίσκου κ.λπ., αλλά δεν χρειάζεται να ανησυχείτε, θα μάθουμε όλα αυτά τα πράγματα στο BIOS και θα διακόψουμε τις ενότητες προγραμματισμού αργότερα στα επόμενα κεφάλαια.
Χειρισμός αρχείων στο C
Η πρόσβαση στο αρχείο στο C επιτυγχάνεται με τη συσχέτιση μιας ροής με ένα αρχείο. Το C επικοινωνεί με αρχεία χρησιμοποιώντας έναν νέο τύπο δεδομένων που ονομάζεται δείκτης αρχείου. Αυτός ο τύπος ορίζεται στο stdio.h και γράφεται ως FILE *. Ένας δείκτης αρχείου που ονομάζεται output_file δηλώνεται σε μια δήλωση όπως
ΑΡΧΕΙΟ *output_file;
Οι λειτουργίες αρχείων του fopen
Το πρόγραμμά σας πρέπει να ανοίξει ένα αρχείο για να έχει πρόσβαση σε αυτό. Αυτό γίνεται χρησιμοποιώντας τη συνάρτηση fopen, η οποία επιστρέφει τον απαιτούμενο δείκτη αρχείου. Εάν το αρχείο δεν μπορεί να ανοίξει για οποιονδήποτε λόγο, τότε θα επιστραφεί η τιμή NULL. Συνήθως θα χρησιμοποιείτε το fopen ως εξής
if ((output_file = fopen("output_file", "w")) == NULL)
fprintf(stderr, "Δεν μπορώ να ανοίξω %s\n",
"output_file");
Το fopen παίρνει δύο ορίσματα, και τα δύο είναι συμβολοσειρές, το πρώτο είναι το όνομα του αρχείου που θα ανοίξει, το δεύτερο είναι ένας χαρακτήρας πρόσβασης, ο οποίος είναι συνήθως ένας από τους r, a ή w κ.λπ. Τα αρχεία μπορούν να ανοίγουν σε διάφορους τρόπους, όπως φαίνεται στον παρακάτω πίνακα.
Λειτουργίες αρχείων |
r |
Ανοίξτε ένα αρχείο κειμένου για ανάγνωση. |
Σε |
Δημιουργήστε ένα αρχείο κειμένου για γραφή. Εάν το αρχείο υπάρχει, αντικαθίσταται. |
ένα |
Ανοίξτε ένα αρχείο κειμένου σε λειτουργία προσάρτησης. Το κείμενο προστίθεται στο τέλος του αρχείου. |
rb |
Ανοίξτε ένα δυαδικό αρχείο για ανάγνωση. |
wb |
Δημιουργήστε ένα δυαδικό αρχείο για εγγραφή. Εάν το αρχείο υπάρχει, αντικαθίσταται. |
αβ |
Ανοίξτε ένα δυαδικό αρχείο σε λειτουργία προσάρτησης. Τα δεδομένα προστίθενται στο τέλος του αρχείου. |
r+ |
Ανοίξτε ένα αρχείο κειμένου για ανάγνωση και γραφή. |
σε+ |
Δημιουργήστε ένα αρχείο κειμένου για ανάγνωση και γραφή. Εάν το αρχείο υπάρχει, αντικαθίσταται. |
α+ |
Ανοίξτε ένα αρχείο κειμένου για ανάγνωση και γραφή στο τέλος. |
r+b ή rb+ |
Ανοίξτε το δυαδικό αρχείο για ανάγνωση και γραφή. |
w+b ή wb+ |
Δημιουργήστε ένα δυαδικό αρχείο για ανάγνωση και γραφή. Εάν το αρχείο υπάρχει, αντικαθίσταται. |
α+β ή αβ+ |
Ανοίξτε ένα αρχείο κειμένου για ανάγνωση και γραφή στο τέλος. |
Οι λειτουργίες ενημέρωσης χρησιμοποιούνται με τις λειτουργίες fseek, fsetpos και rewind. Η συνάρτηση fopen επιστρέφει έναν δείκτη αρχείου ή NULL εάν παρουσιαστεί σφάλμα.
Το ακόλουθο παράδειγμα ανοίγει ένα αρχείο, tarun.txt σε λειτουργία μόνο για ανάγνωση. Είναι καλή πρακτική προγραμματισμού για να ελέγξετε ότι το αρχείο υπάρχει.
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Δεν μπορώ να ανοίξω το αρχείο");
επιστροφή 0;
}
Κλείσιμο αρχείων
Τα αρχεία κλείνονται χρησιμοποιώντας τη συνάρτηση fclose. Η σύνταξη έχει ως εξής:
fclose(in);
Ανάγνωση Αρχείων
Η συνάρτηση feof χρησιμοποιείται για τον έλεγχο του τέλους του αρχείου. Οι συναρτήσεις fgetc, fscanf και fgets χρησιμοποιούνται για την ανάγνωση δεδομένων από το αρχείο.
Το ακόλουθο παράδειγμα παραθέτει τα περιεχόμενα ενός αρχείου στην οθόνη, χρησιμοποιώντας το fgetc για να διαβάσετε το αρχείο έναν χαρακτήρα κάθε φορά.
#include <stdio.h>
int main()
{
ΑΡΧΕΙΟ *in;
κλειδί int?
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Δεν μπορώ να ανοίξω το αρχείο");
επιστροφή 0;
}
ενώ (!feof(in))
{
κλειδί = fgetc(in);
/* Ο τελευταίος χαρακτήρας που διαβάστηκε είναι το τέλος του δείκτη του αρχείου, επομένως μην τον εκτυπώσετε */
αν (!feof(in))
putchar(κλειδί);
}
fclose(in);
επιστροφή 0;
}
Η συνάρτηση fscanf μπορεί να χρησιμοποιηθεί για την ανάγνωση διαφορετικών τύπων δεδομένων από το αρχείο όπως στο παρακάτω παράδειγμα, με την προϋπόθεση ότι τα δεδομένα στο αρχείο έχουν τη μορφή της συμβολοσειράς μορφής που χρησιμοποιείται με το fscanf.
fscanf(in, "%d/%d/%d", &day, &month, &year);
Η συνάρτηση fgets χρησιμοποιείται για την ανάγνωση ενός αριθμού χαρακτήρων από ένα αρχείο. Το stdin είναι η τυπική ροή αρχείων εισόδου και η συνάρτηση fgets μπορεί να χρησιμοποιηθεί για τον έλεγχο της εισόδου.
Εγγραφή σε Αρχεία
Τα δεδομένα μπορούν να εγγραφούν στο αρχείο χρησιμοποιώντας fputc και fprintf. Το παρακάτω παράδειγμα χρησιμοποιεί τις συναρτήσεις fgetc και fputc για να δημιουργήσει ένα αντίγραφο ενός αρχείου κειμένου.
#include <stdio.h>
int main()
{
ΑΡΧΕΙΟ *in, *out;
κλειδί int?
if ((in = fopen("tarun.txt", "r")) == NULL)
{
puts("Δεν μπορώ να ανοίξω το αρχείο");
επιστροφή 0;
}
out = fopen("copy.txt", "w");
ενώ (!feof(in))
{
κλειδί = fgetc(in);
αν (!feof(in))
fputc(κλειδί, έξω);
}
fclose(in);
fclose(out);
επιστροφή 0;
}
Η συνάρτηση fprintf μπορεί να χρησιμοποιηθεί για την εγγραφή μορφοποιημένων δεδομένων σε ένα αρχείο.
fprintf(out, "Ημερομηνία: %02d/%02d/%02d\n",
ημέρα, μήνας, έτος).
Επιχειρήματα γραμμής εντολών με το C
Ο ορισμός του ANSI C για τη δήλωση της συνάρτησης main( ) είναι είτε:
int main() ή int main(int argc, char **argv)
Η δεύτερη έκδοση επιτρέπει τη μετάδοση ορισμάτων από τη γραμμή εντολών. Η παράμετρος argc είναι ένας μετρητής ορίσματος και περιέχει τον αριθμό των παραμέτρων που πέρασαν από τη γραμμή εντολών. Η παράμετρος argv είναι το διάνυσμα ορίσματος που είναι ένας πίνακας δεικτών σε συμβολοσειρές που αντιπροσωπεύουν τις πραγματικές παραμέτρους που έχουν περάσει.
Το ακόλουθο παράδειγμα επιτρέπει τη μεταβίβαση οποιουδήποτε αριθμού ορισμάτων από τη γραμμή εντολών και τα εκτυπώνει. Το argv[0] είναι το πραγματικό πρόγραμμα. Το πρόγραμμα πρέπει να εκτελείται από μια γραμμή εντολών.
#include <stdio.h>
int main(int argc, char **argv)
{
int μετρητής?
puts("Τα ορίσματα του προγράμματος είναι:");
για (counter=0; counter<argc; counter++)
puts(argv[counter]);
επιστροφή 0;
}
Εάν το όνομα του προγράμματος ήταν count.c, θα μπορούσε να κληθεί ως εξής από τη γραμμή εντολών.
μετρήστε 3
ή
μετρήστε 7
ή
καταμέτρηση 192 κ.λπ.
Το επόμενο παράδειγμα χρησιμοποιεί τις ρουτίνες χειρισμού αρχείων για να αντιγράψει ένα αρχείο κειμένου σε ένα νέο αρχείο. Για παράδειγμα, το όρισμα της γραμμής εντολών θα μπορούσε να ονομαστεί ως:
txtcpy one.txt two.txt
#include <stdio.h>
int main(int argc, char **argv)
{
ΑΡΧΕΙΟ *in, *out;
κλειδί int?
εάν (argc < 3)
{
puts("Χρήση: txtcpy προορισμός πηγής\n");
puts("Η πηγή πρέπει να είναι υπάρχον αρχείο");
puts("Εάν υπάρχει το αρχείο προορισμού, θα είναι
αντικατασταθεί");
επιστροφή 0;
}
if ((in = fopen(argv[1], "r")) == NULL)
{
puts("Δεν είναι δυνατό να ανοίξει το αρχείο προς αντιγραφή");
επιστροφή 0;
}
if ((out = fopen(argv[2], "w")) == NULL)
{
puts("Δεν μπορώ να ανοίξω το αρχείο εξόδου");
επιστροφή 0;
}
ενώ (!feof(in))
{
κλειδί = fgetc(in);
αν (!feof(in))
fputc(κλειδί, έξω);
}
fclose(in);
fclose(out);
επιστροφή 0;
}
Bitwise Manipulators
Σε επίπεδο υλικού, τα δεδομένα αντιπροσωπεύονται ως δυαδικοί αριθμοί. Η δυαδική αναπαράσταση του αριθμού 59 είναι 111011. Το bit 0 είναι το λιγότερο σημαντικό bit και σε αυτήν την περίπτωση το bit 5 είναι το πιο σημαντικό bit.
Κάθε σύνολο bit υπολογίζεται ως 2 στην ισχύ του συνόλου bit. Οι τελεστές bitwise σάς επιτρέπουν να χειρίζεστε ακέραιες μεταβλητές σε επίπεδο bit. Το παρακάτω δείχνει τη δυαδική αναπαράσταση του αριθμού 59.
δυαδική αναπαράσταση του αριθμού 59 |
bit 5 4 3 2 1 0 |
2 ισχύς n 32 16 8 4 2 1 |
σετ 1 1 1 0 1 1 |
Με τρία bit, είναι δυνατή η αναπαράσταση των αριθμών 0 έως 7. Ο παρακάτω πίνακας δείχνει τους αριθμούς 0 έως 7 στη δυαδική τους μορφή.
Δυαδικά ψηφία |
000 |
0 |
001 |
1 |
010 |
2 |
011 |
3 |
100 |
4 |
101 |
5 |
110 |
6 |
111 |
7 |
Ο παρακάτω πίνακας παραθέτει τους τελεστές bitwise που μπορούν να χρησιμοποιηθούν για τον χειρισμό δυαδικών αριθμών.
Δυαδικά ψηφία |
& |
Bitwise ΚΑΙ |
| |
Bitwise Ή |
^ |
Bitwise Exclusive OR |
~ |
Συμπλήρωμα bitwise |
<< |
Bitwise Shift Left |
>> |
Bitwise Shift Right |
Bitwise ΚΑΙ
Το bitwise AND είναι True μόνο εάν έχουν οριστεί και τα δύο bit. Το παρακάτω παράδειγμα δείχνει το αποτέλεσμα ενός bitwise AND στους αριθμούς 23 και 12.
10111 (23)
01100 (12) ΚΑΙ
____________________
00100 (αποτέλεσμα = 4) |
Μπορείτε να χρησιμοποιήσετε μια τιμή μάσκας για να ελέγξετε εάν έχουν οριστεί ορισμένα bit. Εάν θέλαμε να ελέγξουμε εάν τα bit 1 και 3 έχουν οριστεί, θα μπορούσαμε να κρύψουμε τον αριθμό με το 10 (την τιμή των bit 1 και 3) και να ελέγξουμε το αποτέλεσμα με τη μάσκα.
#include <stdio.h>
int main()
{
int num, mask = 10;
printf("Εισαγάγετε έναν αριθμό: ");
scanf("%d", &num);
αν ((αριθμός & μάσκα) == μάσκα)
puts("Τα μπιτ 1 και 3 έχουν οριστεί");
αλλού
puts("Τα μπιτ 1 και 3 δεν έχουν οριστεί");
επιστροφή 0;
}
Bitwise Ή
Το bitwise OR είναι αληθές εάν έχουν οριστεί κάποιο από τα bit. Το παρακάτω δείχνει το αποτέλεσμα ενός bitwise OR στους αριθμούς 23 και 12.
10111 (23)
01100 (12) Ή
_____________________
11111 (αποτέλεσμα = 31) |
Μπορείτε να χρησιμοποιήσετε μια μάσκα για να βεβαιωθείτε ότι έχουν ρυθμιστεί ένα bit ή bits. Το ακόλουθο παράδειγμα διασφαλίζει ότι το bit 2 έχει οριστεί.
#include <stdio.h>
int main()
{
int num, mask = 4;
printf("Εισαγάγετε έναν αριθμό: ");
scanf("%d", &num);
num |= μάσκα;
printf("Μετά τη διασφάλιση του ορισμού του bit 2: %d\n", num);
επιστροφή 0;
}
Bitwise Exclusive OR
Το Bitwise Exclusive OR είναι True αν έχουν οριστεί ένα από τα bit, αλλά όχι και τα δύο. Το παρακάτω δείχνει το αποτέλεσμα ενός Bitwise Exclusive OR στους αριθμούς 23 και 12.
10111 (23)
01100 (12) Αποκλειστικό Ή (XOR)
_________________________________
11011 (αποτέλεσμα = 27) |
Το Exclusive OR έχει μερικές ενδιαφέρουσες ιδιότητες. Εάν έχετε Αποκλειστικό Ή έναν αριθμό από μόνος του, αυτός ορίζεται στο μηδέν, καθώς τα μηδενικά θα παραμείνουν μηδέν και τα μηδενικά δεν μπορούν να οριστούν και τα δύο, επομένως ορίζονται στο μηδέν.
Ως αποτέλεσμα αυτού, εάν έχετε Αποκλειστικό Ή έναν αριθμό με άλλο αριθμό, στη συνέχεια Αποκλειστικό Ή το αποτέλεσμα με τον άλλο αριθμό ξανά, το αποτέλεσμα είναι ο αρχικός αριθμός. Μπορείτε να το δοκιμάσετε με τους αριθμούς που χρησιμοποιούνται στο παραπάνω παράδειγμα.
23 Ή 12 = 27
27 Ή 12 = 23
27 Ή 23 = 12
Αυτή η δυνατότητα μπορεί να χρησιμοποιηθεί για κρυπτογράφηση. Το παρακάτω πρόγραμμα χρησιμοποιεί ένα κλειδί κρυπτογράφησης 23 για να απεικονίσει την ιδιότητα σε έναν αριθμό που έχει εισαχθεί από τον χρήστη.
#include <stdio.h>
int main()
{
int num, κλειδί = 23;
printf("Εισαγάγετε έναν αριθμό: ");
scanf("%d", &num);
num ^= κλειδί;
printf("Το αποκλειστικό Ή με %d δίνει %d\n", κλειδί, num);
num ^= κλειδί;
printf("Το αποκλειστικό Ή με %d δίνει %d\n", κλειδί, num);
επιστροφή 0;
}
Bitwise Compliment
Το Bitwise Compliment είναι ένας τελεστής κομπλιμέντου που ενεργοποιεί ή απενεργοποιεί το bit. Αν είναι 1, θα οριστεί στο 0, αν είναι 0 θα οριστεί στο 1.
#include <stdio.h>
int main()
{
int num = 0xFFFF;
printf("Το κομπλιμέντο του %X είναι %X\n", num, ~num);
επιστροφή 0;
}
Bitwise Shift Left
Ο τελεστής Bitwise Shift Left μετατοπίζει τον αριθμό αριστερά. Τα πιο σημαντικά bit χάνονται καθώς ο αριθμός μετακινείται προς τα αριστερά και τα κενά λιγότερο σημαντικά bit είναι μηδέν. Το παρακάτω δείχνει τη δυαδική αναπαράσταση του 43.
0101011 (δεκαδικός αριθμός 43)
Μετατοπίζοντας τα bit προς τα αριστερά, χάνουμε το πιο σημαντικό bit (σε αυτήν την περίπτωση, ένα μηδέν) και ο αριθμός συμπληρώνεται με ένα μηδέν στο λιγότερο σημαντικό bit. Ακολουθεί ο αριθμός που προκύπτει.
1010110 (δεκαδικός αριθμός 86)
Bitwise Shift Right
Ο τελεστής Bitwise Shift Right μετατοπίζει τον αριθμό δεξιά. Το μηδέν εισάγεται στα κενά πιο σημαντικά bit και τα κενά λιγότερο σημαντικά bit χάνονται. Το παρακάτω δείχνει τη δυαδική αναπαράσταση του αριθμού 43.
0101011 (δεκαδικός αριθμός 43)
Μετατοπίζοντας τα bit προς τα δεξιά, χάνουμε το λιγότερο σημαντικό bit (στην περίπτωση αυτή, ένα) και ο αριθμός συμπληρώνεται με ένα μηδέν στο πιο σημαντικό bit. Ακολουθεί ο αριθμός που προκύπτει.
0010101 (δεκαδικός αριθμός 21)
Το παρακάτω πρόγραμμα χρησιμοποιεί τα Bitwise Shift Right και Bitwise AND για να εμφανίσει έναν αριθμό ως δυαδικό αριθμό 16 bit. Ο αριθμός μετατοπίζεται διαδοχικά προς τα δεξιά από το 16 προς τα κάτω στο μηδέν και το Bitwise AND γίνεται με 1 για να δούμε αν το bit έχει οριστεί. Μια εναλλακτική μέθοδος θα ήταν η χρήση διαδοχικών μασκών με τον τελεστή Bitwise OR.
#include <stdio.h>
int main()
{
int μετρητής, αρ.
printf("Εισαγάγετε έναν αριθμό: ");
scanf("%d", &num);
printf("%d είναι δυαδικό: ", num);
για (counter=15; counter>=0; counter--)
printf("%d", (αριθμός >> μετρητής) & 1);
putchar('\n');
επιστροφή 0;
}
Λειτουργίες για δυαδικές – δεκαδικές μετατροπές
Οι δύο συναρτήσεις που δίνονται στη συνέχεια είναι για μετατροπή δυαδικού σε δεκαδικό και δεκαδικό σε δυαδικό. Η συνάρτηση που δίνεται δίπλα στη μετατροπή ενός δεκαδικού αριθμού σε αντίστοιχο δυαδικό αριθμό υποστηρίζει έως και 32 – Bit Binary αριθμό. Μπορείτε να χρησιμοποιήσετε αυτό ή το πρόγραμμα που δόθηκε πριν για μετατροπή σύμφωνα με τις απαιτήσεις σας.
Συνάρτηση για μετατροπή δεκαδικού σε δυαδικό:
void Decimal_to_Binary(void)
{
int input =0;
int i?
int count = 0;
int δυαδικό [32]; /* 32 bit, MAXIMUM 32 στοιχεία */
printf ("Εισαγάγετε τον δεκαδικό αριθμό για μετατροπή σε
Δυαδικό :");
scanf ("%d", &input);
κάνω
{
i = είσοδος%2; /* MOD 2 για να πάρεις 1 ή 0*/
binary[count] = i; /* Φόρτωση στοιχείων στον δυαδικό πίνακα */
είσοδος = είσοδος/2; /* Διαιρέστε την είσοδο με το 2 σε μείωση μέσω δυαδικού */
count++; /* Μετρήστε πόσα στοιχεία χρειάζονται*/
}while (input > 0);
/* Αντίστροφη και έξοδος δυαδικών ψηφίων */
printf ("Η δυαδική αναπαράσταση είναι: ");
κάνω
{
printf ("%d", δυαδικό[count - 1]);
κόμης--;
} while (count > 0);
printf ("\n");
}
Συνάρτηση για μετατροπή δυαδικού σε δεκαδικό:
Η ακόλουθη συνάρτηση είναι να μετατρέψει οποιονδήποτε Δυαδικό αριθμό στον αντίστοιχο δεκαδικό του αριθμό:
void Binary_to_Decimal(void)
{
char binaryhold[512];
char *binary;
int i=0;
int dec = 0;
int z;
printf ("Παρακαλώ εισάγετε τα δυαδικά ψηφία.\n");
printf ("Τα δυαδικά ψηφία είναι είτε 0 είτε μόνο 1");
printf ("Δυαδική καταχώρηση : ");
binary = παίρνει (binaryhold);
i=strlen(δυαδικό);
για (z=0; z<i; ++z)
{
dec=dec*2+(δυαδικό[z]=='1'; 1:0); /* εάν το Binary[z] είναι
ίσο με 1,
μετά 1 άλλο 0 */
}
printf ("\n");
printf ("Η δεκαδική τιμή του %s είναι %d",
δυαδικό, δεκ.)
printf ("\n");
}
Εντοπισμός σφαλμάτων και δοκιμή
Συντακτικά λάθη
Η σύνταξη αναφέρεται στη γραμματική, τη δομή και τη σειρά των στοιχείων σε μια δήλωση. Ένα συντακτικό σφάλμα παρουσιάζεται όταν παραβιάζουμε τους κανόνες, όπως ξεχνάμε να τελειώσουμε μια πρόταση με ερωτηματικό. Όταν κάνετε μεταγλώττιση του προγράμματος, ο μεταγλωττιστής θα παράγει μια λίστα με τυχόν συντακτικά σφάλματα που μπορεί να συναντήσει.
Ένας καλός μεταγλωττιστής θα παράγει τη λίστα με μια περιγραφή του σφάλματος και μπορεί να παρέχει μια πιθανή λύση. Η διόρθωση των σφαλμάτων μπορεί να έχει ως αποτέλεσμα την εμφάνιση περαιτέρω σφαλμάτων κατά την εκ νέου μεταγλώττιση. Ο λόγος για αυτό είναι ότι τα προηγούμενα σφάλματα άλλαξαν τη δομή του προγράμματος, πράγμα που σημαίνει ότι τα περαιτέρω σφάλματα καταργήθηκαν κατά τη διάρκεια της αρχικής μεταγλώττισης.
Ομοίως, ένα μόνο λάθος μπορεί να οδηγήσει σε πολλά σφάλματα. Δοκιμάστε να βάλετε ένα ερωτηματικό στο τέλος της κύριας συνάρτησης ενός προγράμματος που μεταγλωττίζεται και εκτελείται σωστά. Όταν το μεταγλωττίσετε εκ νέου, θα λάβετε μια τεράστια λίστα σφαλμάτων, και όμως είναι μόνο ένα άστοχο ερωτηματικό.
Εκτός από τα συντακτικά σφάλματα, οι μεταγλωττιστές ενδέχεται επίσης να εκδίδουν προειδοποιήσεις. Μια προειδοποίηση δεν είναι σφάλμα, αλλά μπορεί να προκαλέσει προβλήματα κατά την εκτέλεση του προγράμματός σας. Για παράδειγμα, η αντιστοίχιση ενός αριθμού κινητής υποδιαστολής διπλής ακρίβειας σε έναν αριθμό κινητής υποδιαστολής μονής ακρίβειας μπορεί να οδηγήσει σε απώλεια ακρίβειας. Δεν είναι συντακτικό σφάλμα, αλλά μπορεί να οδηγήσει σε προβλήματα. Σε αυτό το συγκεκριμένο παράδειγμα, θα μπορούσατε να δείξετε πρόθεση μεταφέροντας τη μεταβλητή στον κατάλληλο τύπο δεδομένων.
Εξετάστε το ακόλουθο παράδειγμα όπου x είναι ένας αριθμός κινητής υποδιαστολής μονής ακρίβειας και y είναι ένας αριθμός κινητής υποδιαστολής διπλής ακρίβειας. Το y μεταφέρεται ρητά σε ένα float κατά τη διάρκεια της ανάθεσης, κάτι που θα εξαλείφει τυχόν προειδοποιήσεις του μεταγλωττιστή.
x = (float)y;
Λάθη λογικής
Τα λογικά σφάλματα συμβαίνουν όταν υπάρχει σφάλμα στη λογική. Για παράδειγμα, μπορείτε να ελέγξετε ότι ένας αριθμός είναι μικρότερος από 4 και μεγαλύτερος από 8. Αυτό δεν θα μπορούσε ποτέ να ισχύει, αλλά εάν είναι συντακτικά σωστό, το πρόγραμμα θα μεταγλωττιστεί με επιτυχία. Εξετάστε το ακόλουθο παράδειγμα:
αν (x < 4 && x > 8)
puts ("Δεν θα συμβεί ποτέ!");
Η σύνταξη είναι σωστή, επομένως το πρόγραμμα θα μεταγλωττιστεί, αλλά η δήλωση puts δεν θα εκτυπωθεί ποτέ καθώς η τιμή του x δεν θα μπορούσε να είναι μικρότερη από τέσσερα και μεγαλύτερη από οκτώ ταυτόχρονα.
Τα περισσότερα λογικά σφάλματα ανακαλύπτονται μέσω της αρχικής δοκιμής του προγράμματος. Όταν δεν συμπεριφέρεται όπως περιμένατε, επιθεωρείτε τις λογικές δηλώσεις πιο προσεκτικά και τις διορθώνετε. Αυτό ισχύει μόνο για προφανή λογικά λάθη. Όσο μεγαλύτερο είναι το πρόγραμμα, τόσο περισσότερες διαδρομές θα υπάρχουν μέσα από αυτό, τόσο πιο δύσκολο γίνεται να επαληθευτεί ότι το πρόγραμμα συμπεριφέρεται όπως αναμένεται.
Δοκιμές
Στη διαδικασία ανάπτυξης λογισμικού, τα σφάλματα μπορούν να εισαχθούν σε οποιαδήποτε στάδια κατά την ανάπτυξη. Αυτό οφείλεται στο γεγονός ότι οι μέθοδοι επαλήθευσης των προηγούμενων φάσεων ανάπτυξης λογισμικού είναι χειροκίνητες. Ως εκ τούτου, ο κώδικας που αναπτύχθηκε κατά τη δραστηριότητα κωδικοποίησης είναι πιθανό να έχει ορισμένα σφάλματα απαιτήσεων και σφάλματα σχεδιασμού, επιπλέον των σφαλμάτων που εισάγονται κατά τη δραστηριότητα κωδικοποίησης. Κατά τη διάρκεια της δοκιμής, το πρόγραμμα που πρόκειται να δοκιμαστεί εκτελείται με ένα σύνολο δοκιμαστικών περιπτώσεων και η έξοδος του προγράμματος για τις δοκιμαστικές περιπτώσεις αξιολογείται για να προσδιοριστεί εάν ο προγραμματισμός εκτελείται αναμένεται.
Έτσι, η δοκιμή είναι η διαδικασία ανάλυσης ενός στοιχείου λογισμικού για την ανίχνευση της διαφοράς μεταξύ των υφιστάμενων και των απαιτούμενων συνθηκών (δηλ. σφάλματα) και για την αξιολόγηση των χαρακτηριστικών των στοιχείων λογισμικού. Έτσι, η δοκιμή είναι η διαδικασία ανάλυσης ενός προγράμματος με σκοπό την εύρεση σφαλμάτων.
Μερικές αρχές δοκιμών
- Η δοκιμή δεν μπορεί να δείξει την απουσία ελαττωμάτων, μόνο την παρουσία τους.
- Όσο νωρίτερα γίνει ένα λάθος, τόσο πιο δαπανηρό είναι.
- Όσο αργότερα εντοπιστεί ένα σφάλμα, τόσο πιο ακριβό είναι.
Τώρα ας συζητήσουμε μερικές τεχνικές δοκιμών:
Δοκιμή λευκού κουτιού
Η δοκιμή λευκού κουτιού είναι μια τεχνική κατά την οποία όλες οι διαδρομές μέσω του προγράμματος ελέγχονται με κάθε δυνατή τιμή. Αυτή η προσέγγιση απαιτεί κάποια γνώση για το πώς πρέπει να συμπεριφέρεται το πρόγραμμα. Για παράδειγμα, εάν το πρόγραμμά σας δεχόταν μια ακέραια τιμή μεταξύ 1 και 50, μια δοκιμή λευκού πλαισίου θα ελέγχει το πρόγραμμα και με τις 50 τιμές για να βεβαιωθεί ότι ήταν σωστό για καθεμία και, στη συνέχεια, θα δοκίμαζε κάθε άλλη πιθανή τιμή που μπορεί να λάβει ένας ακέραιος και θα ελέγξει ότι συμπεριφέρθηκε όπως αναμένεται. Λαμβάνοντας υπόψη τον αριθμό των στοιχείων δεδομένων που μπορεί να έχει ένα τυπικό πρόγραμμα, οι πιθανές μεταθέσεις καθιστούν τη δοκιμή λευκού κουτιού εξαιρετικά δύσκολη για μεγάλα προγράμματα.
Η δοκιμή λευκού κουτιού μπορεί να εφαρμοστεί σε κρίσιμες λειτουργίες ασφαλείας ενός μεγάλου προγράμματος και πολλά από τα υπόλοιπα ελέγχονται χρησιμοποιώντας τη δοκιμή μαύρου κουτιού, που συζητείται παρακάτω. Λόγω του αριθμού των μεταθέσεων, η δοκιμή λευκού κουτιού συνήθως εκτελείται χρησιμοποιώντας μια ζώνη δοκιμής, όπου εύρη τιμών τροφοδοτούνται στο πρόγραμμα γρήγορα μέσω ενός ειδικού προγράμματος, καταγράφοντας εξαιρέσεις από την αναμενόμενη συμπεριφορά. Η δοκιμή λευκού κουτιού αναφέρεται μερικές φορές ως δομική, καθαρή ή ανοιχτή δοκιμή κουτιού.
Δοκιμή μαύρου κουτιού
Η δοκιμή μαύρου κουτιού είναι παρόμοια με τη δοκιμή λευκού κουτιού, εκτός από τη δοκιμή κάθε πιθανής τιμής, ελέγχονται οι επιλεγμένες τιμές. Σε αυτόν τον τύπο δοκιμής, ο ελεγκτής γνωρίζει τις εισροές και ποια θα πρέπει να είναι τα αναμενόμενα αποτελέσματα, αλλά όχι απαραίτητα πώς έφτασε σε αυτά το πρόγραμμα. Η δοκιμή μαύρου κουτιού αναφέρεται μερικές φορές ως λειτουργική δοκιμή.
Οι δοκιμές για τη δοκιμή μαύρου κουτιού αναπτύσσονται συνήθως αμέσως μετά την ολοκλήρωση των προδιαγραφών του προγράμματος. Οι περιπτώσεις δοκιμής βασίζονται σε τάξεις ισοδυναμίας.
Τάξεις ισοδυναμίας
Για κάθε είσοδο, μια κλάση ισοδυναμίας ορίζει έγκυρες και μη έγκυρες καταστάσεις. Υπάρχουν συνήθως τρία σενάρια που πρέπει να προγραμματιστούν κατά τον καθορισμό κλάσεων ισοδυναμίας.
Εάν τα δεδομένα εισόδου καθορίζουν ένα εύρος ή μια συγκεκριμένη τιμή, θα οριστούν μια έγκυρη κατάσταση και δύο μη έγκυρες καταστάσεις. Για παράδειγμα, εάν ένας αριθμός πρέπει να είναι μεταξύ 1 και 20, η έγκυρη κατάσταση θα είναι μεταξύ 1 και 20, θα υπάρχει μη έγκυρη κατάσταση για τιμές μικρότερες από 1 και μη έγκυρη κατάσταση μεγαλύτερη από 20.
Εάν τα δεδομένα εισόδου εξαιρούν ένα εύρος ή μια συγκεκριμένη τιμή, θα οριστούν δύο έγκυρες καταστάσεις και μία μη έγκυρη κατάσταση. Για παράδειγμα, εάν ένας αριθμός δεν πρέπει να είναι μεταξύ 1 και 20, οι έγκυρες καταστάσεις θα είναι μικρότερες από 1 και μεγαλύτερες από 20 και οι μη έγκυρες καταστάσεις θα είναι μεταξύ 1 και 20.
Εάν η είσοδος καθορίζει μια Boolean τιμή, θα υπάρχουν μόνο δύο καταστάσεις: μία έγκυρη και μία άκυρη.
Ανάλυση οριακών τιμών
Η ανάλυση οριακών τιμών λαμβάνει υπόψη μόνο τις τιμές στο όριο των δεδομένων εισόδου. Για παράδειγμα, στην περίπτωση ενός αριθμού από το 1 έως το 20, οι δοκιμαστικές περιπτώσεις μπορεί να είναι 1, 20, 0 και 21. Η ιδέα είναι ότι εάν το πρόγραμμα λειτουργεί όπως αναμένεται με αυτές τις τιμές, και άλλες τιμές θα λειτουργούν όπως αναμένεται.
Ο παρακάτω πίνακας παρέχει μια επισκόπηση των τυπικών ορίων που μπορεί να θέλετε να ορίσετε.
Εύρος δοκιμής |
Τύπος εισόδου |
Τιμές δοκιμής |
Σειρά |
- x[κάτω_όριο]-1
- x[κάτω_όριο]
- x[upper_bound]
- x[upper_bound]+1
|
Boolean |
|
Ανάπτυξη σχεδίου δοκιμής
Ορίστε τις τάξεις ισοδυναμίας και καθορίστε τα όρια για κάθε τάξη. Αφού ορίσετε τα όρια για την τάξη, γράψτε μια λίστα με αποδεκτές και μη αποδεκτές τιμές στο όριο και ποια θα πρέπει να είναι η αναμενόμενη συμπεριφορά. Ο ελεγκτής μπορεί στη συνέχεια να εκτελέσει το πρόγραμμα με τις οριακές τιμές και να υποδείξει τι συνέβη όταν η οριακή τιμή δοκιμάστηκε σε σχέση με το απαιτούμενο αποτέλεσμα.
Παρακάτω είναι ένα τυπικό σχέδιο δοκιμής που χρησιμοποιείται για την επικύρωση ηλικιών εισόδου όπου οι αποδεκτές τιμές κυμαίνονται από 10 έως 110.
Κατηγορία ισοδυναμίας |
Εγκυρος |
Ανακριβής |
Μεταξύ 10 και 110 |
> 110 |
|
< 10 |
Έχοντας καθορίσει την τάξη ισοδυναμίας μας, μπορούμε τώρα να αναπτύξουμε ένα σχέδιο δοκιμών για την ηλικία.
Σχέδιο δοκιμής |
Αξία |
Κατάσταση |
Αναμενόμενο αποτέλεσμα |
Πραγματικό αποτέλεσμα |
10 |
Εγκυρος |
Συνεχίστε την εκτέλεση για να λάβετε το όνομα |
|
110 |
Εγκυρος |
Συνεχίστε την εκτέλεση για να λάβετε το όνομα |
|
9 |
Ανακριβής |
Ρωτήστε ξανά την ηλικία |
|
111 |
Ανακριβής |
Ρωτήστε ξανά την ηλικία |
|
Η στήλη "Πραγματικό αποτέλεσμα" παραμένει κενή καθώς θα συμπληρωθεί κατά τη διάρκεια της δοκιμής. Εάν το αποτέλεσμα είναι το αναμενόμενο, η στήλη θα ελεγχθεί. Εάν όχι, θα πρέπει να εισάγετε ένα σχόλιο που να δείχνει τι συνέβη.