Η οργάνωση σύνθετων δεδομένων σε ομάδες με σκοπό την απλοποίηση του χειρισμού τους, αποτελούν τις λεγόμενες δομές δεδομένων. Μια σχετικά απλή δομή δεδομένων είναι ο πίνακας. Η δημιουργία πίνακα διευκολύνει την ταυτόχρονη παρουσία στην μνήμη του υπολογιστικού συστήματος μεγάλου πλήθους δεδομένων που συνδέονται μεταξύ τους με κάποια λογική σχέση.
Πίνακας είναι ένα σύνολο μεταβλητών του ίδιου τύπου που έχουν κοινό όνομα. Η διάκριση των μεταβλητών που αποτελούν τον πίνακα γίνεται με τη χρήση ενός αριθμού που προσδιορίζει τη θέση κάθε μεταβλητής ή στοιχείου και ονομάζεται δείκτης του πίνακα. Ο δείκτης του πίνακα είναι ουσιαστικά ένας ακέραιος αριθμός που συνοδεύει το κοινό όνομα όλων των μεταβλητών και τοποθετείται μέσα σε αγκύλες. Παράδειγμα: ένας πίνακας πέντε στοιχείων, μπορεί και αποτελείται από τις μεταβλητές που γράφονται με τον χαρακτηριστικό τρόπο: α[0], α[1], α[2], α[3] και α[4]
Ένας πίνακας θα πρέπει να οριστεί μέσα σε μια συνάρτηση, για να μπορεί να χρησιμοποιηθεί, προσδιορίζοντας τον τύπο και το μέγεθος του, με την εξής εντολή:
τύπος όνομαπινακα[Ν]
όπου «τύπος» ο τύπος του κάθε στοιχείου του πίνακα, «όνομαπίνακα» είναι το όνομα του πίνακα και Ν είναι ο αριθμός των στοιχείων του πίνακα. Τα στοιχεία του πίνακα είναι διατεταγμένα στη σειρά και ο δείκτης των στοιχείων παίρνει τιμές 0, 1, 2, … ,Ν-1 Ακολουθούν παραδείγματα ορισμού πινάκων:
char name[20];
int box[8];
double α[5];
Η πρώτη έκφραση ορίζει ένα πίνακα είκοσι στοιχείων τύπου χαρακτήρα, με όνομα name[], η δεύτερη έκφραση ορίζει ένα πίνακα ακέραιων τιμών με οκτώ στοιχεία με όνομα box[] και η τρίτη έκφραση ορίζει ένα πίνακα πραγματικών αριθμών διπλής ακρίβειας, πέντε στοιχείων και με όνομα α[].
Ο ορισμός ενός πίνακα είναι μια άμεση εντολή στον μεταγλωττιστή, να δεσμεύσει ένα καθορισμένο αριθμό θέσεων μνήμης για τον πίνακα αυτό. Κάθε στοιχείο του πίνακα καταλαμβάνει το ίδιο μήκος με οποιοδήποτε άλλο στοιχείο του. Το συνολικό μέγεθος ενός πίνακα σε bytes καθορίζεται από τον τύπο του και είναι ίσο με το γινόμενο του πλήθους των στοιχείων του πίνακα επί το μέγεθος των στοιχείων του σε bytes.
Για τον ακριβή προσδιορισμό του πραγματικού μεγέθους του πίνακα που καταλαμβάνει στην μνήμη σε bytes, χρησιμοποιείται ο τελεστής sizeof(). Για παράδειγμα:
int boxes[200], n;
n=sizeof(boxes); // το πραγματικό μέγεθος του πίνακα σε bytes
Σημειώστε ότι δεν χρησιμοποιούμε τις αγκύλες στο όνομα του πίνακα που βάλαμε σαν όρισμα στον τελεστή sizeof(). Σε αντίθετη περίπτωση δίνει το μέγεθος σε bytes του κάθε στοιχείου του.
Απόδοση αρχικών τιμών
Όπως και στις απλές μεταβλητές, τα στοιχεία ενός πίνακα μπορούν να λάβουν αρχικές τιμές με δυο τρόπους, είτε ταυτόχρονα με τον ορισμό του πίνακα είτε στο κυρίως σώμα του προγράμματος. Όταν αποδίδουμε αρχικές τιμές κατά τον ορισμό του πίνακα, οι τιμές που αποδίδονται στα στοιχεία του πίνακα σχηματίζουν μια λίστα δεδομένων που περικλείονται σε άγκιστρα { … }. Για παράδειγμα οι επόμενες εντολές αποδίδουν στους πίνακες name[] και box[] αρχικές τιμές
char name[8]={‘N’, ‘I’, ‘K’, ‘O’, ‘L’, ‘A’, ‘O’, ‘S’};
int box[4]={2, 15, 6, 10};
Όταν ο ορισμός ενός πίνακα συνοδεύεται με την απόδοση αρχικών τιμών σ’ αυτόν, τότε δεν είναι υποχρεωτικό να προσδιορίζουμε το πλήθος των στοιχείων του. Ο μεταγλωττιστής της C καθορίζει το αναγκαίο μέγεθος μνήμης μετρώντας τα δεδομένα που δίδονται μέσα στα άγκιστρα. Για παράδειγμα η ακόλουθη έκφραση είναι απόλυτα σωστή:
double numbers[ ] = {0.2, 10.5, 6.3, 8.0};
Σημείωση: Η απόδοση αρχικών τιμών στον πίνακα με αυτό τον τρόπο μπορεί να γίνει μόνο στην εντολή ορισμού του. Μετά τον ορισμό του πίνακα, η απόδοση αρχικών τιμών μπορεί να γίνει μόνο αποδίδοντας την τιμή κάθε στοιχείου χωριστά. Δείτε το ακόλουθο παράδειγμα:
//Λάθος
int num[4];
num[] = {5, 6, 7, 8};
//
//Σωστό
int num[4];
num[0] = 5; num[1] = 6;
num[2] = 7; num[3] = 8;
Αν ορίσουμε ένα πίνακα αλλά αποδώσουμε αρχικές τιμές μόνο σε μερικά από τα στοιχεία του, ο μεταγλωττιστής συμπληρώνει με μηδενικές τιμές τα υπόλοιπα στοιχεία του πίνακα. Για παράδειγμα ο ορισμός: int x[5] = {5, 6, 7}; εξασφαλίζει ότι τα στοιχεία του πίνακα x[ ] έχουν τιμές x[0]=5, x[1]=6, x[2]=7, x[3]=0, x[4]=0.
Όταν ορίζουμε ένα πίνακα είτε αποδίδοντας αρχικές τιμές είτε όχι, τα στοιχεία του μπορούν να μετέχουν σε αριθμητικές και λογικές παραστάσεις όπως με τις απλές μεταβλητές, όπως φαίνεται στο ακόλουθο παράδειγμα:
int num[50];
for(uint8_t i=0; i<50; i++) num[i]=i*i;
//
int box[] = {10, 11, 5}, k, b;
k = 2*box[0]+ 10*box[1]+box[2]*box[2];
b = (box[0] > 2) || (box[2] <= box[1]);
Πολυδιάστατοι πίνακες
Ένας πίνακας είναι πολυδιάστατος αν για τον προσδιορισμό της θέσης κάποιου στοιχείου του απαιτούνται περισσότεροι από ένας ακέραιοι αριθμοί. Το πλήθος των ακεραίων που καθορίζουν μονοσήμαντα τα στοιχεία ενός πίνακα ονομάζεται διάσταση του πίνακα.
Στις προηγούμενες παραγράφους γνωρίσαμε τους μονοδιάστατους πίνακες που όπως είδαμε αποτελούν ουσιαστικά λίστες δεδομένων. Στους πολυδιάστατους πίνακες δουλεύουμε συνήθως με πίνακες δύο και τριών διαστάσεων που εκφράζουν πολύπλοκες δομές δεδομένων. Αν δηλαδή φανταστούμε ότι ο μονοδιάστατος πίνακας είναι μια γραμμική παράθεση δεδομένων, τότε ο δισδιάστατος πίνακας αντιπροσωπεύει μια επιφάνεια ενώ ο τρισδιάστατος ένα όγκο.
Για τον ορισμό (δήλωση) πολυδιάστατων πινάκων πρέπει να προσδιορίσουμε το πλήθος των στοιχείων σε κάθε διάσταση. Το πλήθος γράφεται μέσα σε αγκύλες που ακολούθου τον τύπο και το όνομα του πίνακα. Αν για παράδειγμα θέλουμε να ορίσουμε ένα ακέραιο δισδιάστατο πίνακα με όνομα num[ ] και διαστάσεις 4 γραμμές και 3 στήλες γράφουμε:
int num[4][3];
Ο ορισμός αυτός δίνει εντολή στο μεταγλωττιστή της γλώσσας C να εξασφαλίσει 12 θέσεις επι 2 bytes για κάθε ακέραιο μέλος του πίνακα, για την αποθήκευση του πίνακα στη μνήμη.
Όπως και στους μονοδιάστατους πίνακες ο ορισμός ενός πολυδιάστατου πίνακα μπορεί να συνοδεύεται από την απόδοση αρχικών τιμών. Για παράδειγμα μπορούμε να έχουμε:
int num[4][3] = {{1,2,3}, {4,5,6}, {7,8,9}, {10, 11, 12}};
Επειδή πολλές φορές τα δεδομένα είναι πάρα πολλά για να χωρέσουν σε μια γραμμή του προγράμματος η γλώσσα C επιτρέπει τη διάταξη τους σε περισσότερες γραμμές ως εξής:
int num[4][3] = { {1, 2, 3},
{4, 5, 6},
{7, 8, 9},
{10, 11, 12} };
Ο μεταγλωττιστής της C μπορεί να αναγνωρίσει και να διαβάσει τα δεδομένα απόδοσης αρχικών τιμών ακόμα και αν δίνονται σαν απλή λίστα σταθερών, έτσι οι προηγούμενοι ορισμοί είναι ισοδύναμοι με τον:
int num[4][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
Με ανάλογο τρόπο με τα όσα είπαμε για τους μονοδιάστατους πίνακες, η απόδοση αρχικών τιμών σε μερικά μόνο στοιχεία ενός πολυδιάστατου πίνακα έχει ως αποτέλεσμα το μηδενισμό όλων των υπόλοιπων στοιχείων του.
Πίνακες χαρακτήρων και αλφαριθμητικά
Ένα αλφαριθμητικό (ή συμβολοσειρά) είναι μια ακολουθία χαρακτήρων μέσα σε διπλά εισαγωγικά. Ένα αλφαριθμητικό παριστάνεται στη μνήμη του υπολογιστή σαν ένα πίνακα χαρακτήρων με τελευταίο χαρακτήρα το κενό ‘\0’ . Οι εντολές χειρισμού αλφαριθμητικών βασίζονται στον κενό χαρακτήρα ‘\0’ που σηματοδοτεί το τέλος του αλφαριθμητικού και έτσι με αυτό τον τρόπο η CPU μπορεί να εκτελεί εντολές με αλφαριθμητικά, τα οποία παριστάνονται με πίνακες χαρακτήρων.
Ο ορισμός και η απόδοση αρχικών τιμών σ’ ένα αλφαριθμητικό ακολουθεί τους ίδιους κανόνες ορισμού πινάκων δεδομένων. Για παράδειγμα, η εντολή
char city[10] = “Trikala”;
ορίζει ένα πίνακα χαρακτήρων με 10 στοιχεία που γεμίζει την μνήμη ως εξής:

Οι δυο τελευταίες θέσεις του πίνακα περιέχουν πιθανώς κάποιες τιμές αλλά δεν λαμβάνουν μέρος στην επεξεργασία του αλφαριθμητικού αφού βρίσκονται μετά τον χαρακτήρα ‘\0’ που σημειώνει το τέλος του.
Σημείωση: στην απόδοση αρχικών τιμών σ’ ένα αλφαριθμητικό το μέγεθος του πίνακα πρέπει να είναι μεγάλο ώστε να δέχεται ολόκληρο το αλφαριθμητικό μαζί με τον επιπλέον χαρακτήρα ‘\0’. Στο προηγούμενο παράδειγμα το ελάχιστο μέγεθος του πίνακα είναι 8 δηλαδή 7 θέσεις για τους χαρακτήρες του ονόματος “Trikala” συν 1 για τον χαρακτήρα ‘\0’
Η γλώσσα C προσφέρει την δυνατότητα στον προγραμματιστή να ορίσει ένα αλφαριθμητικό χωρίς να προσδιορίσει το μήκος του:
char city[ ] = “Trikala”;
Όταν ο μεταγλωττιστής συναντήσει ένα τέτοιο ορισμό, μετρά το πλήθος χαρακτήρων του αλφαριθμητικού, προσθέτει τη μονάδα για τον κενό χαρακτήρα και δεσμεύει τον αντίστοιχο χώρο στη μνήμη του υπολογιστή και στην συνέχεια τοποθετεί τους χαρακτήρες του αλφαριθμητικού και τελευταίο τον κενό χαρακτήρα ‘\0’.
Σημειώστε ότι, για την απόδοση αρχικών τιμών στο αλφαριθμητικό χρησιμοποιούμε τα εισαγωγικά “ “ αντί των αγκίστρων και των αποστρόφων για καθέναν των χαρακτήρων του. Η διαφορά αυτή τονίζει την διαφορετική φύση του αλφαριθμητικού από ένα γενικό πίνακα χαρακτήρων. Το προηγούμενο αλφαριθμητικό, μπορεί να οριστεί σαν ένα γενικό πίνακα χαρακτήρων ως εξής:
char city[7] = {‘T’, ‘r’, ‘i’, ‘k’, ‘a’, ‘l’, ‘a’};