C Syntax

[thumb|300px|Απόσπασμα κώδικα C από τον [Πυρήνας Linux|πυρήνα του Linux]]

Η **σύνταξη της C** είναι η μορφή που πρέπει να έχει το κείμενο ώστε να αποτελεί έγκυρο κώδικα της γλώσσας προγραμματισμού C. Οι κανόνες σύνταξης της γλώσσας είναι σχεδιασμένοι ώστε να επιτρέπουν τη συγγραφή κώδικα που είναι περιεκτικός, έχει στενή σχέση με τον παραγόμενο αντικειμενικό κώδικα (object code) και ταυτόχρονα παρέχει σχετικά υψηλού επιπέδου αφαίρεση δεδομένων (data abstraction). Η C ήταν η πρώτη ευρέως επιτυχημένη γλώσσα υψηλού επιπέδου για τη φορητή ανάπτυξη λειτουργικών συστημάτων. Η σύνταξη της C κάνει χρήση της αρχής του maximal munch.

Ως γλώσσα ελεύθερης μορφής (free-form language), ο κώδικας C μπορεί να μορφοποιηθεί με διαφορετικούς τρόπους χωρίς να επηρεάζεται η συντακτική του φύση. Η σύνταξη της C επηρέασε τη σύνταξη πολλών μεταγενέστερων γλωσσών, συμπεριλαμβανομένων των C++, Java και C#.

## Δομή υψηλού επιπέδου
Ο κώδικας C αποτελείται από οδηγίες του προεπεξεργαστή, τύπους, μεταβλητές και συναρτήσεις της κύριας γλώσσας, οργανωμένα σε ένα ή περισσότερα αρχεία πηγής. Η κατασκευή (building) του κώδικα περιλαμβάνει συνήθως την προεπεξεργασία και στη συνέχεια τη μεταγλώττιση (compiling) κάθε αρχείου πηγής σε ένα αντικειμενικό αρχείο (object file). Στη συνέχεια, τα αντικειμενικά αρχεία συνδέονται (linked) για τη δημιουργία μιας εκτελέσιμης εικόνας.

Οι μεταβλητές και οι συναρτήσεις μπορούν να δηλωθούν ξεχωριστά από τον ορισμό τους. Μια *δήλωση* (declaration) προσδιορίζει το όνομα ενός στοιχείου ορισμένου από τον χρήστη και κάποιες πληροφορίες για το πώς το στοιχείο μπορεί να χρησιμοποιηθεί κατά το χρόνο εκτέλεσης. Ένας *ορισμός* (definition) είναι μια πλήρης περιγραφή ενός στοιχείου που περιλαμβάνει τη δήλωση καθώς και πρόσθετες πληροφορίες. Για παράδειγμα, μια δήλωση συνάρτησης υποδεικνύει το όνομα και προαιρετικά τον τύπο και τα ορίσματα. Ένας ορισμός συνάρτησης περιλαμβάνει τον κώδικα υλοποίησης.

### Σημείο εισόδου
thumb|300px|Κώδικας C για ένα πρόγραμμα που εκτυπώνει "Hello, World!"
Για ένα «φιλοξενούμενο» (hosted) περιβάλλον, ένα πρόγραμμα ξεκινά από μια συνάρτηση σημείου εισόδου με το όνομα . Η συνάρτηση πρέπει να δηλώνεται σύμφωνα με ένα από τα ακόλουθα πρωτότυπα:


```c
int main();
int main(void);
int main(int argc, char* argv[]);
int main(int argc, char** argv);
```


Η τιμή επιστροφής, τύπου , χρησιμεύει ως δείκτης κατάστασης προς το περιβάλλον φιλοξενίας. Ορισμένη στο , η βιβλιοθήκη παρέχει τις μακροεντολές  και . 

Ένα ελάχιστο πρόγραμμα αποτελείται από μια κενή συνάρτηση :

```c
int main() {}
```


Σε αντίθεση με άλλες συναρτήσεις, η γλώσσα απαιτεί το πρόγραμμα να ενεργεί σαν να επιστρέφει 0 ακόμη και αν δεν καταλήγει σε δήλωση  (από το πρότυπο C99).

### Ορίσματα γραμμής εντολών
Τα ορίσματα μεταβιβάζονται ως δύο τιμές: τον αριθμό των ορισμάτων () και έναν πίνακα από συμβολοσειρές (), με το όνομα του προγράμματος ως πρώτο στοιχείο.


```c
#include <stdio.h>

int main(int argc, char* argv[]) {
    printf("argc\t= %d\n", argc);
    for (int i = 0; i < argc; ++i) {
        printf("argv[%i]\t= %s\n", i, argv[i]);
    }
}
```


## Δεσμευμένες λέξεις
Οι ακόλουθες 43 λέξεις είναι δεσμευμένες (reserved) — δεν επιτρέπεται να χρησιμοποιηθούν ως αναγνωριστικά (identifiers).

* `alignas`
* `alignof`
* `auto`
* `bool`
* `break`
* `case`
* `char`
* `const`
* `constexpr`
* `continue`
* `default`
* `do`
* `double`
* `else`
* `enum`
* `extern`
* `float`
* `for`
* `goto`
* `if`
* `inline`
* `int`
* `long`
* `register`
* `restrict`
* `return`
* `short`
* `signed`
* `sizeof`
* `static`
* `static_assert`
* `struct`
* `switch`
* `thread_local`
* `typedef`
* `typeof`
* `typeof_unqual`
* `union`
* `unsigned`
* `void`
* `volatile`
* `while`

Οι ακόλουθες 14 λέξεις-κλειδιά αντικαθίστανται συχνά από μια μακροεντολή ή μια κατάλληλη λέξη από την παραπάνω λίστα. Ορισμένες από αυτές θεωρούνται παρωχημένες (deprecated) από το πρότυπο C23.

* `_Alignas` (παρωχημένο)
* `_Alignof` (παρωχημένο)
* `_Atomic`
* `_BitInt`
* `_Bool` (παρωχημένο)
* `_Complex`
* `_Countof`
* `_Decimal32`
* `_Decimal64`
* `_Decimal128`
* `_Generic`
* `_Noreturn` (παρωχημένο)
* `_Static_assert` (παρωχημένο)
* `_Thread_local` (παρωχημένο)

Η λέξη-κλειδί `_Imaginary` αφαιρέθηκε στην έκδοση C2Y.

Οι ακόλουθες 3 λέξεις αναφέρονται σε κυριολεκτικές τιμές (literals) που χρησιμοποιούνται από τη γλώσσα:

* `nullptr`
* `true`
* `false`

Οι διάφορες υλοποιήσεις ενδέχεται να δεσμεύουν επιπλέον λέξεις-κλειδιά, οι οποίες συνήθως ξεκινούν με μία ή δύο κάτω παύλες. Οι παρακάτω θεωρούνται επεκτάσεις (extensions):
* `asm` (για ενσωματωμένο κώδικα Assembly)
* `fortran` (για εξωτερική σύνδεση με Fortran)

### Οδηγίες προεπεξεργαστή
Οι ακόλουθες 19 οδηγίες αφορούν τον προεπεξεργαστή της C.

* `#if`
* `#elif`
* `#else`
* `#endif`
* `#ifdef`
* `#ifndef`
* `#elifdef`
* `#elifndef`
* `#define`
* `#undef`
* `#include`
* `#embed`
* `#line`
* `#error`
* `#warning`
* `#pragma`
* `#__has_include`
* `#__has_embed`
* `#__has_c_attribute`

Ο τελεστής `_Pragma` παρέχει μια εναλλακτική σύνταξη για τη λειτουργικότητα που προσφέρει η οδηγία .

## Σχόλια
Τα σχόλια είναι πληροφοριακό κείμενο για τον προγραμματιστή που αγνοείται από τον μεταγλωττιστή. Στη C υποστηρίζονται δύο είδη σύνταξης: τα σχόλια γραμμής και τα σχόλια μπλοκ. Ένα σχόλιο γραμμής ξεκινά με  και τελειώνει στο τέλος της ίδιας γραμμής. Ένα σχόλιο μπλοκ ξεκινά με  και τελειώνει με , και μπορεί να εκτείνεται σε οποιοδήποτε αριθμό γραμμών.

Τα σχόλια δεν μπορούν να είναι εμφωλευμένα (nested). Για παράδειγμα, το  μέσα σε ένα σχόλιο γραμμής δεν αντιμετωπίζεται ως έναρξη σχολίου μπλοκ, και το  μέσα σε ένα σχόλιο μπλοκ δεν ξεκινά σχόλιο γραμμής. Η σύνταξη σχολίων γραμμής (στυλ C++) εισήχθη στο πρότυπο C99 και δεν ήταν διαθέσιμη στις αρχικές εκδόσεις K&R ή ANSI C.


```c
int i; // σχόλιο γραμμής
/* σχόλιο
   μπλοκ */
int ii = /* πάντα μηδέν */ 0;
```


Επειδή τα σχόλια δεν εμφωλεύονται, ο παρακάτω κώδικας δεν είναι έγκυρος, καθώς ο μεταγλωττιστής θα θεωρήσει ότι το σχόλιο τελειώνει στην πρώτη εμφάνιση του  (γραμμή 5), αφήνοντας την υπόλοιπη γραμμή 6 ως λανθασμένο κώδικα:


```c
/*
Έναρξη σχολίου
/*
Εσωτερικό μπλοκ (πρόθεση προγραμματιστή)
*/
Ο μεταγλωττιστής θεωρεί αυτή τη γραμμή ως κώδικα!
*/
```


## Αναγνωριστικά
Η σύνταξη υποστηρίζει αναγνωριστικά (identifiers) ορισμένα από τον χρήστη. Ένα αναγνωριστικό πρέπει να ξεκινά με γράμμα (A-Z, a-z) ή κάτω παύλα (_). Οι επόμενοι χαρακτήρες μπορεί να είναι γράμματα, αριθμοί (0-9) ή κάτω παύλες και δεν πρέπει να είναι δεσμευμένη λέξη. Τα αναγνωριστικά έχουν ευαισθησία ως προς τα κεφαλαία/πεζά γράμματα (case sensitive), καθιστώντας τα ,  και  διακριτά μεταξύ τους.

## Σειρά αξιολόγησης
Το πρότυπο ορίζει ότι οι εκφράσεις μπορούν να αξιολογηθούν με οποιαδήποτε σειρά μεταξύ των σημείων ακολουθίας (sequence points). Τα σημεία ακολουθίας ορίζονται ως εξής:

* *Τέλος εντολής* (Statement end).
* *Τελεστής διαχωρισμού*: το κόμμα (τα κόμματα που διαχωρίζουν ορίσματα συναρτήσεων δεν αποτελούν σημεία ακολουθίας).
* *Τελεστές βραχυκυκλώματος*: το λογικό «και» () και το λογικό «ή» ().
* *Τριαδικός τελεστής* (): Αξιολογεί πρώτα την πρώτη υποέκφραση και μετά τη δεύτερη ή την τρίτη (ποτέ και τις δύο).
* Είσοδος και έξοδος από μια *κλήση συνάρτησης*.

Στην περίπτωση της βραχυκυκλωμένης αξιολόγησης (short-circuit evaluation), η δεύτερη έκφραση ενδέχεται να μην αξιολογηθεί. Για παράδειγμα, στην έκφραση, αν η πρώτη συνάρτηση επιστρέψει μη μηδενική τιμή (αληθές), η  δεν θα κληθεί ποτέ.

Τα ορίσματα σε μια κλήση συνάρτησης μπορούν να αξιολογηθούν με οποιαδήποτε σειρά. Ο παρακάτω κώδικας έχει απροσδιόριστη συμπεριφορά (undefined behavior):

```c
printf("%s %s\n", argv[i = 0], argv[++i]);
```


## Συμπερίληψη κώδικα
### Κεφαλίδες (Headers)
Η συμπερίληψη κώδικα από άλλα αρχεία γίνεται με την οδηγία , η οποία αντιγράφει το περιεχόμενο του αρχείου απευθείας στο σημείο της δήλωσης. Παραδοσιακά, ο κώδικας C χωρίζεται σε αρχεία κεφαλίδας (με επέκταση ) και αρχεία πηγής (με επέκταση ). Η κεφαλίδα περιέχει τις δηλώσεις των συμβόλων, ενώ το αρχείο πηγής περιέχει την πλήρη υλοποίηση. Αυτός ο διαχωρισμός αποτρέπει την επανειλημμένη μεταγλώττιση του ίδιου κώδικα, μειώνοντας τους χρόνους δόμησης. Καθώς η C δεν διαθέτει χώρους ονομάτων (namespaces), όλα τα ονόματα συμβόλων είναι καθολικά και θα υπάρξει σύγκρουση αν το ίδιο όνομα χρησιμοποιηθεί για πολλαπλά αντικείμενα στην ίδια μονάδα μετάφρασης.

Για την αποφυγή πολλαπλής συμπερίληψης της ίδιας κεφαλίδας χρησιμοποιούνται οι φύλακες συμπερίληψης ( guards) ή η οδηγία .


```c
#pragma once

// Συμπερίληψη πρότυπης βιβλιοθήκης (αναζήτηση σε καταλόγους συστήματος)
#include <stdio.h>
#include <stdlib.h>

// Τοπικές κεφαλίδες (αναζήτηση σε σχετική διαδρομή)
#include "Personalities.h"
#include "Math/SpecialFunctions.h"

// Εξωτερικές βιβλιοθήκες
#include <sqlite3.h>
```


### Ενσωμάτωση (Embed)
Από το πρότυπο C23, η οδηγία  επιτρέπει την άμεση ενσωμάτωση δυαδικών δεδομένων (binary content) σε ένα αρχείο, ακόμη και αν αυτά δεν αποτελούν έγκυρο κώδικα C. Αυτό είναι ιδιαίτερα χρήσιμο για την ενσωμάτωση εικόνων, αρχείων ρυθμίσεων ή άλλων πόρων απευθείας στο εκτελέσιμο.


```c
const unsigned char iconDisplayData[] = {
    #embed "art.png"
};

// Οποιοσδήποτε τύπος που αρχικοποιείται από ακέραιες σταθερές είναι αποδεκτός
const char resetBlob[] = {
    #embed "data.bin"
};

int main() {
    return
#embed </dev/urandom> limit(1)
    ;
}
```


### Ενότητες Clang (Clang C modules)
Ο μεταγλωττιστής Clang προσφέρει μια μη τυποποιημένη δυνατότητα που ονομάζεται «ενότητες» (modules). Παρόμοιες με τις ενότητες της C++, χρησιμοποιούνται για τη βελτίωση του χρόνου μεταγλώττισης, επιτρέποντας στο σύστημα να μεταγλωττίζει μια μονάδα μετάφρασης μόνο μία φορά.

## Σύστημα τύπων
### Πρωτογενείς τύποι
Η γλώσσα υποστηρίζει πρωτογενείς αριθμητικούς τύπους για ακέραιες και πραγματικές τιμές, οι οποίες συνήθως αντιστοιχίζονται απευθείας στην αρχιτεκτονική του συνόλου εντολών της ΚΜΕ (CPU). Οι ακέραιοι τύποι αποθηκεύουν τιμές σε ένα υποσύνολο των ακεραίων, ενώ οι πραγματικοί τύποι αποθηκεύουν τιμές σε ένα υποσύνολο των πραγματικών αριθμών σε μορφή κινητής υποδιαστολής. Ένας μιγαδικός τύπος δεδομένων αποθηκεύει δύο πραγματικές τιμές.

Οι ακέραιοι τύποι διαθέτουν παραλλαγές με πρόσημο () και χωρίς πρόσημο (). Εάν δεν προσδιοριστεί τίποτα, θεωρείται ότι ο τύπος είναι . Ωστόσο, για ιστορικούς λόγους, ο τύπος  είναι διακριτός τόσο από τον  όσο και από τον . Μπορεί να έχει ή να μην έχει πρόσημο, ανάλογα με τον μεταγλωττιστή και το σύνολο χαρακτήρων.

#### Ακέραιοι τύποι
Οι ακέραιοι τύποι διατίθενται σε διαφορετικά σταθερά μεγέθη. Ο τύπος  καταλαμβάνει ακριβώς ένα byte (τη μικρότερη διευθυνσιοδοτήσιμη μονάδα αποθήκευσης), η οποία είναι συνήθως εύρους 8 bit. Οι υπογεγραμμένοι ακέραιοι τύποι χρησιμοποιούν πάντα την αναπαράσταση συμπλήρωμα ως προς δύο, από την έκδοση C23 και μετά.

Ο ακόλουθος πίνακας παραθέτει τους τυπικούς ακέραιους τύπους με το ελάχιστο επιτρεπτό εύρος σε bit.

Το εύρος και η αναπαράσταση κάθε τύπου επιλέγονται με βάση την αρχιτεκτονική του μηχανήματος. Το εύρος του τύπου  ποικίλλει ιδιαίτερα· συχνά αντιστοιχεί στο "φυσικό" μέγεθος λέξης (word size) της πλατφόρμας. Η πρότυπη κεφαλίδα  ορίζει μακροεντολές για τις ελάχιστες και μέγιστες τιμές αυτών των τύπων. Για ακριβέστερο καθορισμό εύρους, οι προγραμματιστές μπορούν να χρησιμοποιούν τους τύπους από την κεφαλίδα (π.χ. ).

Οι ακέραιες σταθερές μπορούν να οριστούν στο δεκαδικό σύστημα (π.χ. ), στο οκταδικό με το πρόθεμα  (π.χ. ) ή στο δεκαεξαδικό με το πρόθεμα  (π.χ. ). Ένας χαρακτήρας σε μονά εισαγωγικά (π.χ. ) αντιπροσωπεύει την ακέραια τιμή αυτού του χαρακτήρα στο σύνολο χαρακτήρων εκτέλεσης.

#### Αριθμημένος τύπος
Ο αριθμημένος τύπος (enumerated type), ο οποίος ορίζεται με τη λέξη-κλειδί , είναι ένας τύπος σχεδιασμένος να αναπαριστά τιμές μέσα από μια σειρά ονομαστικών σταθερών. Κάθε μία από τις σταθερές αυτές είναι τύπου . Ο ίδιος ο τύπος  είναι συμβατός με τον  ή με υπογεγραμμένους/μη υπογεγραμμένους ακέραιους τύπους, αλλά κάθε υλοποίηση ορίζει τους δικούς της κανόνες για την επιλογή του κατάλληλου τύπου.

Οι σταθερές  χρησιμοποιούνται συχνά αντί της οδηγίας  του προεπεξεργαστή για τη δημιουργία ονομαστικών σταθερών. Τέτοιες σταθερές είναι γενικά ασφαλέστερες στη χρήση από τις μακροεντολές, καθώς παραμένουν εντός του χώρου ονομάτων των αναγνωριστικών.

Ένας αριθμημένος τύπος δηλώνεται με τον προσδιοριστή  και ένα προαιρετικό όνομα (ετικέτα), ακολουθούμενο από μια λίστα σταθερών μέσα σε άγκιστρα. Από προεπιλογή, στην πρώτη σταθερά εκχωρείται η τιμή μηδέν και κάθε επόμενη τιμή αυξάνεται κατά ένα. Μπορούν επίσης να εκχωρηθούν συγκεκριμένες τιμές στις σταθερές κατά τη δήλωση.

Παράδειγμα δήλωσης:

```c
enum Color { 
    RED,    // 0
    GREEN,  // 1
    BLUE = 5, 
    YELLOW  // 6
} paint_color;
```


Σε αντίθεση με τη C++, οι απαριθμήσεις στη C δεν έχουν εμβέλεια (scoped), καθώς η C δεν διαθέτει την έννοια των namespaces. Στη C, τα  μπορούν να μετατραπούν σιωπηρά σε αριθμητικούς τύπους, γεγονός που θεωρείται μη ασφαλές ως προς τους τύπους (type-unsafe).


```c
typedef enum Color {
    RED,
    ORANGE,
    YELLOW,
    GREEN,
    BLUE,
    INDIGO,
    VIOLET
} Color;

Color c = RED; // Έγκυρο στη C
Color d = Color::RED; // Έγκυρο στη C++, αλλά ΟΧΙ στη C
```


Από το πρότυπο C23, είναι πλέον δυνατός ο χειροκίνητος καθορισμός του υποκείμενου τύπου για ένα , όπως συμβαίνει και στη C++.

```c
enum CardSuit: char { 
    HEARTS, 
    CLUBS, 
    SPADES, 
    DIAMONDS
};
```


#### Τύποι κινητής υποδιαστολής
Μια μορφή κινητής υποδιαστολής χρησιμοποιείται για την αναπαράσταση αριθμών με κλασματικό μέρος. Ωστόσο, δεν αναπαριστούν τους περισσότερους ρητούς αριθμούς με ακρίβεια, αλλά αποτελούν μια κοντινή προσέγγιση. Υπάρχουν τρεις τυπικοί τύποι πραγματικών τιμών (και από το πρότυπο C23 τρεις επιπλέον δεκαδικοί τύποι): μονής ακρίβειας (), διπλής ακρίβειας () και διπλής εκτεταμένης ακρίβειας (). Καθένας από αυτούς μπορεί να αναπαριστά τιμές σε διαφορετική μορφή, συχνά σε μία από τις μορφές IEEE κινητής υποδιαστολής.

Οι σταθερές κινητής υποδιαστολής μπορούν να γραφτούν σε δεκαδική μορφή (π.χ. ). Μπορεί επίσης να χρησιμοποιηθεί η επιστημονική σημειογραφία προσθέτοντας  ή  ακολουθούμενο από έναν δεκαδικό εκθέτη (π.χ. , που έχει την τιμή 1.23 × 102 = 123.0). Απαιτείται είτε υποδιαστολή είτε εκθέτης (διαφορετικά, ο αριθμός αναλύεται ως ακέραια σταθερά).

Οι δεκαεξαδικές σταθερές κινητής υποδιαστολής έχουν το πρόθεμα  και χρησιμοποιούν το  ή  για τον καθορισμό δυαδικού εκθέτη (π.χ. , που έχει την τιμή 2.5, αφού Ah × 2−2 = 10 ÷ 4). Οι σταθερές μπορούν να έχουν την κατάληξη  ή  για τον τύπο ,  ή  για τον τύπο , ή να παραμείνουν χωρίς κατάληξη για τον τύπο .

Η πρότυπη κεφαλίδα  ορίζει τις ελάχιστες και μέγιστες τιμές των τύπων κινητής υποδιαστολής της υλοποίησης, καθώς και άλλους σχετικούς περιορισμούς.

Το πρότυπο C23 εισάγει τρεις πρόσθετους «δεκαδικούς» (σε αντίθεση με τους δυαδικούς) τύπους πραγματικής κινητής υποδιαστολής: ,  και . Ιστορικά, η βάση (radix) της C ήταν το δυαδικό σύστημα (βάση 2), πράγμα που σημαίνει ότι αριθμοί όπως το 1/2 ή το 1/4 είναι ακριβείς, αλλά όχι το 1/10 ή το 1/3. Με τη δεκαδική κινητή υποδιαστολή, αριθμοί όπως το 1/10 και το 1/100 είναι ακριβείς, αλλά και πάλι όχι το 1/3.

### Κατηγορία αποθήκευσης
Ο ακόλουθος πίνακας περιγράφει τους προσδιοριστές που ορίζουν διάφορες ιδιότητες αποθήκευσης, συμπεριλαμβανομένης της διάρκειας ζωής (static, automatic ή dynamic).

:1 Δέσμευση και αποδέσμευση μέσω των συναρτήσεων της βιβλιοθήκης  και .

Οι μεταβλητές που δηλώνονται μέσα σε ένα μπλοκ έχουν από προεπιλογή αυτόματη αποθήκευση, όπως και αυτές που δηλώνονται ρητά με τους προσδιοριστές  ή . Ο προσδιοριστής  είναι συνήθως πλεονασματικός. Αντικείμενα που δηλώνονται έξω από όλα τα μπλοκ ή ρητά με τον προσδιοριστή , έχουν στατική διάρκεια ζωής και αρχικοποιούνται στο μηδέν από τον μεταγλωττιστή.

Τα αντικείμενα με αυτόματη αποθήκευση είναι τοπικά στο μπλοκ τους και καταστρέφονται με την έξοδο από αυτό. Ο προσδιοριστής  υποδεικνύει στον μεταγλωττιστή να δώσει προτεραιότητα στην αποθήκευση της μεταβλητής σε καταχωρητές της ΚΜΕ για ταχύτερη πρόσβαση. Τα αντικείμενα αυτής της κατηγορίας δεν μπορούν να χρησιμοποιηθούν με τον τελεστή διεύθυνσης ().

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

Ο προσδιοριστής  ( πριν από τη C23), ο οποίος εισήχθη στο πρότυπο C11, χρησιμοποιείται για τη δήλωση μεταβλητών που είναι τοπικές σε ένα συγκεκριμένο νήμα εκτέλεσης.

Από την έκδοση C23, η λέξη-κλειδί  μπορεί επίσης να χρησιμοποιηθεί για τη δήλωση μεταβλητών με εξαγωγή τύπου (type inference), παρόμοια με τη C++.

### Προσδιοριστές τύπου
Οι τύποι μπορούν να τροποποιηθούν με προσδιοριστές (type qualifiers) για να υποδηλώσουν ειδικές ιδιότητες. Ο προσδιοριστής  υποδηλώνει ότι μια τιμή δεν μεταβάλλεται μετά την αρχικοποίησή της. Ομοίως, ο  (από τη C23) είναι μια ισχυρότερη μορφή του , όπου η τιμή πρέπει να είναι γνωστή κατά το χρόνο μεταγλώττισης. Ο προσδιοριστής  υποδεικνύει στον μεταγλωττιστή ότι η τιμή μπορεί να αλλάξει από εξωτερικούς παράγοντες (π.χ. υλικό ή άλλα νήματα), εμποδίζοντας ανεπιθύμητες βελτιστοποιήσεις κατά την ανάγνωση ή εγγραφή της.

### Ελλιπείς τύποι
Ένας ελλιπής τύπος (incomplete type) είναι μια δομή (struct) ή ένωση (union) της οποίας τα μέλη δεν έχουν ακόμη οριστεί, ένας τύπος πίνακα του οποίου οι διαστάσεις δεν έχουν καθοριστεί, ή ο τύπος . Τέτοιοι τύποι δεν μπορούν να δεσμεύσουν μνήμη (καθώς το μέγεθός τους είναι άγνωστο), αλλά μπορούν να χρησιμοποιηθούν για τον ορισμό δεικτών.

Χρησιμοποιούνται συχνά για την υλοποίηση αναδρομικών δομών ή για την απόκρυψη δεδομένων (data hiding):

```c
struct Integer* pt; // Δήλωση δείκτη σε ελλιπή τύπο
```


### Δείκτες

Στη δήλωση μιας μεταβλητής, ο αστερίσκος () σημαίνει «δείκτης σε». Για παράδειγμα, η  ορίζει μια μεταβλητή  που είναι δείκτης σε ακέραιο. Μια τιμή δείκτη συνδέει δύο πληροφορίες: μια διεύθυνση μνήμης και έναν τύπο δεδομένων.

#### Αναφορά και Αποαναφορά
Ο τελεστής  (διεύθυνση του) επιστρέφει τη διεύθυνση μνήμης ενός αντικειμένου. Ο αστερίσκος  πριν από το όνομα μιας μεταβλητής δείκτη (όταν δεν βρίσκεται σε δήλωση) αποαναφέρεται (dereference), επιτρέποντας την πρόσβαση στην τιμή που βρίσκεται στη διεύθυνση που δείχνει.


```c
int a = 10;
int* p = &a; // Ο p δείχνει στη διεύθυνση του a
int b = *p;  // Ο b παίρνει την τιμή 10 μέσω του p
```


### Πίνακες

#### Ορισμός πίνακα
Οι πίνακες αποθηκεύουν διαδοχικά στοιχεία του ίδιου τύπου. Ο ακόλουθος κώδικας δηλώνει έναν πίνακα 100 στοιχείων τύπου :


```c
int a[100];
```


Εάν δηλωθεί καθολικά, το μέγεθος πρέπει να είναι σταθερά. Εάν δηλωθεί μέσα σε συνάρτηση, το μέγεθος μπορεί να είναι μια έκφραση (Variable Length Array - VLA). Ο αριθμός των στοιχείων μπορεί να υπολογιστεί με την έκφραση .

#### Πρόσβαση σε στοιχεία
Η πρόσβαση στα στοιχεία γίνεται με τη χρήση αγκυλών, με τον δείκτη (index) να ξεκινά από το 0.

```c
a[0] = 5; // Ανάθεση τιμής στο πρώτο στοιχείο
int x = a[99]; // Πρόσβαση στο τελευταίο στοιχείο
```


#### Πρόσβαση σε στοιχεία
Η κύρια μέθοδος πρόσβασης στα στοιχεία ενός πίνακα είναι ο τελεστής δείκτη (subscript operator). Για παράδειγμα, η έκφραση  έχει πρόσβαση στο στοιχείο με δείκτη . Η δεικτοδότηση των πινάκων ξεκινά από το 0. Καθώς η C δεν παρέχει αυτόματο έλεγχο ορίων (bounds checking), η χρήση δείκτη εκτός των ορίων του πίνακα οδηγεί σε απροσδιόριστη συμπεριφορά.

Λόγω της στενής σχέσης πινάκων και δεικτών, η διεύθυνση κάθε στοιχείου μπορεί να εκφραστεί και μέσω αριθμητικής δεικτών.

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

#### Πίνακες μεταβλητού μεγέθους
Το πρότυπο C99 εισήγαγε τους πίνακες μεταβλητού μεγέθους (Variable-Length Arrays - VLA) σε εμβέλεια μπλοκ. Το μέγεθος τέτοιων πινάκων καθορίζεται κατά το χρόνο εκτέλεσης. Από την έκδοση C11, η δυνατότητα αυτή είναι προαιρετική για τους μεταγλωττιστές.


```c
int n = 20; 
int a[n]; // Το n καθορίζεται στο runtime
a[3] = 10;
```


#### Πολυδιάστατοι πίνακες
Η C υποστηρίζει πολυδιάστατους πίνακες, οι οποίοι αποθηκεύονται στη μνήμη κατά γραμμή (row-major order). Ένας δισδιάστατος πίνακας είναι ουσιαστικά ένας μονοδιάστατος πίνακας, του οποίου κάθε στοιχείο είναι επίσης ένας πίνακας.


```c
int array2d[ROWS][COLUMNS];
// Πρόσβαση στο στοιχείο της 5ης γραμμής και 4ης στήλης:
int val = array2d[4][3];
```


Ένας πολυδιάστατος πίνακας καταλαμβάνει μια συνεχή περιοχή της μνήμης και δεν πρέπει να συγχέεται με έναν πίνακα δεικτών προς πίνακες (Iliffe vector), όπου οι υπο-πίνακες μπορεί να βρίσκονται σε διαφορετικές θέσεις στη μνήμη.

### Κείμενο
Αν και η γλώσσα παρέχει τύπους για δεδομένα χαρακτήρων, δεν ορίζει έναν εγγενή τύπο δεδομένων για συμβολοσειρές (strings). Αντίθετα, χρησιμοποιείται η συμβολοσειρά τερματιζόμενη με μηδενικό (null-terminated string). Μια συμβολοσειρά είναι μια σειρά χαρακτήρων που καταλήγει στον χαρακτήρα  (μηδενική τιμή).

#### Συμβολοσειρές σταθερής τιμής (String literals)
Μια συμβολοσειρά σταθερής τιμής περικλείεται σε διπλά εισαγωγικά, π.χ. . Ο μεταγλωττιστής προσθέτει αυτόματα τον μηδενικό χαρακτήρα τερματισμού στο τέλος.

Η γλώσσα υποστηρίζει τη συγχώνευση γειτονικών συμβολοσειρών κατά τη μεταγλώττιση, κάτι που επιτρέπει τον διαχωρισμό μεγάλων συμβολοσειρών σε πολλές γραμμές κώδικα:


```c
printf("Hello " "world\n"); // Ισοδύναμο με "Hello world\n"
```


#### Σταθερές χαρακτήρων
Η σταθερά χαρακτήρα (character constant) περικλείεται σε μονά εισαγωγικά, π.χ. , και είναι τύπου . Για να κατανοήσουμε τη διαφορά μεταξύ μιας σταθεράς συμβολοσειράς και μιας σταθεράς χαρακτήρα, σημειώστε ότι η  αποτελείται από δύο χαρακτήρες (τον 'A' και τον '\0'), ενώ η  αντιπροσωπεύει έναν μόνο χαρακτήρα (την ακέραια τιμή 65 στο σύστημα ASCII).

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

Όπως και οι συμβολοσειρές, οι σταθερές χαρακτήρων μπορούν να δεχθούν προθέματα, όπως το , το οποίο είναι τύπου  και αντιπροσωπεύει τον χαρακτήρα "A" σε κωδικοποίηση ευρέος χαρακτήρα.

#### Ακολουθίες διαφυγής (Backslash escapes)
Οι χαρακτήρες ελέγχου δεν μπορούν να συμπεριληφθούν απευθείας σε μια συμβολοσειρά. Αντ' αυτού, κωδικοποιούνται μέσω μιας ακολουθίας διαφυγής που ξεκινά με μια ανάστροφη κάθετο ().

Οι κυριότερες ακολουθίες διαφυγής περιλαμβάνουν:

Σημειώστε ότι στην πρότυπη συνάρτηση , χρησιμοποιείται η ακολουθία  για την εκτύπωση του χαρακτήρα του επί τοις εκατό ().

#### Συμβολοσειρές ευρέων χαρακτήρων
Καθώς ο τύπος  έχει μέγεθος 1 byte, μπορεί να αναπαραστήσει έως 255 διακριτούς χαρακτήρες, αριθμός που δεν επαρκεί για διεθνή σύνολα χαρακτήρων. Για την υποστήριξη αυτών, η C εισήγαγε τους ευρείς χαρακτήρες (wide characters), τύπου , οι οποίοι γράφονται με το πρόθεμα , π.χ. .

Το μέγεθος του  εξαρτάται από την υλοποίηση (συνήθως 2 ή 4 bytes). Στα συστήματα Microsoft Windows χρησιμοποιείται συνήθως η κωδικοποίηση UTF-16, ενώ στα συστήματα Unix προτιμάται η UTF-32.

Σήμερα, η γενικά προτεινόμενη μέθοδος υποστήριξης διεθνών χαρακτήρων είναι μέσω της κωδικοποίησης UTF-8, η οποία αποθηκεύεται σε απλούς πίνακες  και είναι συμβατή με το σύστημα ASCII.

#### Συμβολοσειρές μεταβλητού εύρους
Μια κοινή εναλλακτική λύση αντί του  είναι η χρήση μιας κωδικοποίησης μεταβλητού εύρους, όπου ένας λογικός χαρακτήρας μπορεί να εκτείνεται σε πολλές θέσεις της συμβολοσειράς. Οι συμβολοσειρές αυτές μπορούν να ενσωματωθούν σε σταθερές τιμές είτε αυτούσιες (με κίνδυνο σύγχυσης του μεταγλωττιστή), είτε χρησιμοποιώντας αριθμητικές ακολουθίες διαφυγής (π.χ.  για το χαρακτήρα "" σε UTF-8). Η κωδικοποίηση UTF-8 σχεδιάστηκε ειδικά για συμβατότητα με τις συναρτήσεις της πρότυπης βιβλιοθήκης της C, καθώς δεν περιέχει ενσωματωμένους μηδενικούς χαρακτήρες (nulls) και επιτρέπει τον εύκολο επανασυγχρονισμό της ροής δεδομένων.

### Δομές (Structures)
Μια **δομή** (structure ή **struct**) είναι ένας περιέκτης που αποτελείται από μια ακολουθία ονομαστικών μελών διαφορετικών τύπων, παρόμοια με την εγγραφή (record) άλλων γλωσσών. Το πρώτο πεδίο ξεκινά από τη διεύθυνση της δομής και τα μέλη αποθηκεύονται σε διαδοχικές θέσεις στη μνήμη. Ωστόσο, ο μεταγλωττιστής μπορεί να εισάγει κενά πλήρωσης (padding) μεταξύ ή μετά τα μέλη για λόγους απόδοσης ή ευθυγράμμισης δεδομένων (alignment). Το μέγεθος μιας δομής περιλαμβάνει και αυτά τα κενά πλήρωσης.

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

Το παρακάτω παράδειγμα δηλώνει μια δομή με το όνομα  που περιέχει τρία μέλη, καθώς και ένα στιγμιότυπο με το όνομα :


```c
struct MyStruct {
    int x;
    float y;
    char* z;
} tee;
```


Τα μέλη μιας δομής δεν μπορούν να έχουν ελλιπή τύπο ή τύπο συνάρτησης. Συνεπώς, ένα μέλος δεν μπορεί να είναι στιγμιότυπο της δομής που δηλώνεται εκείνη τη στιγμή (γιατί είναι ελλιπής τύπος), αλλά μπορεί να είναι δείκτης προς τον τύπο της δομής.

Αφού δηλωθεί ο τύπος, μπορούμε να δημιουργήσουμε νέα στιγμιότυπα:

```c
struct MyStruct r;
```


Πολλοί προγραμματιστές χρησιμοποιούν τη λέξη-κλειδί `[[typedef]]` για να δημιουργήσουν ένα ψευδώνυμο (alias) της δομής, ώστε να μην χρειάζεται η λέξη  σε κάθε δήλωση μεταβλητής:


```c
typedef struct { 
    int i;
} Integer;

Integer n; // Χρήση του ψευδωνύμου αντί για struct ...
```


#### Πρόσβαση σε μέλη
Η πρόσβαση σε ένα μέλος γίνεται με τη χρήση της τελείας (dot notation). Για παράδειγμα, χρησιμοποιώντας τη δήλωση της  από παραπάνω, το μέλος  είναι προσβάσιμο ως .

Όταν η πρόσβαση στη δομή γίνεται μέσω δείκτη, χρησιμοποιείται ο τελεστής  (βέλος). Αν έχουμε έναν δείκτη , το μέλος  είναι προσβάσιμο ως . Αυτό είναι συντακτική γλυκαντική (syntactic sugar) για την έκφραση .

#### Ανάθεση και λειτουργίες
Η ανάθεση τιμής σε ένα μέλος γίνεται όπως σε μια απλή μεταβλητή. Μια δομή μπορεί επίσης να ανατεθεί εξ ολοκλήρου σε μια άλλη δομή του ίδιου τύπου (αντιγραφή κατά τιμή), να περαστεί ως όρισμα σε συνάρτηση ή να επιστραφεί από αυτήν. 

Η γλώσσα δεν υποστηρίζει την απευθείας σύγκριση δύο δομών (π.χ. ). Για τη σύγκριση απαιτείται κώδικας που ελέγχει κάθε πεδίο ξεχωριστά.

#### Πεδία bit (Bit fields)
Η C επιτρέπει τον ορισμό μελών με συγκεκριμένο μέγεθος σε bit, γνωστά ως πεδία bit. Δηλώνονται ως μέλη τύπου  (signed/unsigned) ή , ακολουθούμενα από άνω-κάτω τελεία και τον αριθμό των bit.

Τα πεδία bit χρησιμοποιούνται συχνά για την εξοικονόμηση μνήμης ή τον έλεγχο υλικού (hardware registers). Δεν είναι δυνατή η λήψη της διεύθυνσής τους (τελεστής ) ούτε η χρήση του .
```c
struct FlagStatus {
    unsigned int flag : 1; // 1 bit (0 ή 1)
    signed int num : 4;    // 4 bit για αποθήκευση αριθμού
    signed int : 3;        // 3 bit κενό πλήρωσης (padding)
} g;
```


#### Χώροι ονομάτων (Namespaces)
Η C δεν διαθέτει εγγενή υποστήριξη για χώρους ονομάτων (namespaces). Αυτό καθιστά τα ονόματα των συμβόλων επιρρεπή σε συγκρούσεις. Ωστόσο, είναι δυνατόν να προσομοιωθούν οι χώροι ονομάτων χρησιμοποιώντας στατικές (anonymous) δομές και δείκτες συναρτήσεων.

Παράδειγμα οργάνωσης βιβλιοθήκης :

```c
// Math.h
const struct {
    double PI;
    double (*sin)(double);
} Math;

// Χρήση στον κώδικα:
double val = Math.sin(Math.PI / 2);
```


### Ένωση (Union)
Σε μεγάλο βαθμό, μια **ένωση** είναι παρόμοια με μια δομή, με τη διαφορά ότι τα πεδία της επικαλύπτονται στην ίδια θέση μνήμης. Αυτό επιτρέπει την αποθήκευση διαφορετικών τύπων δεδομένων, αλλά όχι ταυτόχρονα. Το μέγεθος μιας ένωσης είναι ίσο με το μέγεθος του μεγαλύτερου στοιχείου της συν τυχόν κενά πλήρωσης (padding).

Μια ένωση δηλώνεται με τη λέξη-κλειδί . Το παρακάτω παράδειγμα δηλώνει την ένωση :


```c
union MyUnion {
    int x;
    float y;
    char* z;
} n;
```


### Αρχικοποίηση

#### Βαθμωτοί τύποι (Scalars)
Η αρχικοποίηση μιας μεταβλητής κατά τη δήλωσή της γίνεται με το σύμβολο της ισότητας. Λόγω της γραμματικής της γλώσσας, ένας βαθμωτός τύπος μπορεί να περικλείεται σε οποιονδήποτε αριθμό αγκυλών (αν και αυτό δεν συνηθίζεται).


```c
int x = 12;
int y = { 23 }; // Έγκυρο αλλά σπάνιο
```


#### Λίστα αρχικοποίησης (Initializer list)
Οι δομές, οι ενώσεις και οι πίνακες μπορούν να αρχικοποιηθούν μέσω μιας λίστας αρχικοποίησης. Εάν τα στοιχεία της λίστας είναι λιγότερα από τα μέλη της δομής, τα υπόλοιπα μέλη μηδενίζονται.


```c
int a[10] = {}; // Όλα τα στοιχεία γίνονται 0
struct MyStruct s = { 3, 3.14, "Pi" };
```


Εάν ένας πίνακας δηλωθεί χωρίς ρητό μέγεθος, ο αριθμός των στοιχείων στη λίστα αρχικοποίησης καθορίζει το μέγεθος του πίνακα και συμπληρώνει τον τύπο του.

#### Καθορισμένοι αρχικοποιητές (Designated initializers)
Από το πρότυπο C99, οι καθορισμένοι αρχικοποιητές επιτρέπουν την αρχικοποίηση μελών με βάση το όνομά τους, με οποιαδήποτε σειρά.


```c
struct MyStruct pi = { .z = "Pi", .x = 3, .y = 3.1415 };
```


Αυτή η μέθοδος είναι ιδιαίτερα χρήσιμη σε ενώσεις, όπου μπορούμε να επιλέξουμε ποιο μέλος θα αρχικοποιηθεί (παλαιότερα αρχικοποιούνταν υποχρεωτικά μόνο το πρώτο μέλος):


```c
union MyUnion value = { .y = 3.1415 };
```


Για πίνακες, μπορούμε να καθορίσουμε τη θέση (index) της αρχικοποίησης:


```c
int a[10] = { [0] = 1, [5] = 8, [9] = 2 };
```


#### Σύνθετες σταθερές (Compound literals)
Είναι δυνατή η χρήση της μεθοδολογίας αρχικοποίησης για τη δημιουργία σύνθετων σταθερών τιμών για δομές και πίνακες «εν πτήσει»:


```c
// Δείκτης που δημιουργείται από μια σύνθετη σταθερά πίνακα
int* ptr = (int[]){ 10, 20, 30, 40 };

// Δείκτης σε πίνακα
float (*foo)[3] = &(float[]){ 0.5f, 1.f, -0.5f };

struct MyStruct pi = (struct MyStruct){ 3, 3.1415, "Pi" };
```


Οι σύνθετες σταθερές συχνά συνδυάζονται με καθορισμένους αρχικοποιητές για να κάνουν τη δήλωση πιο ευανάγνωστη:


```c
pi = (struct MyStruct){ .z = "Pi", .x = 3, .y = 3.1415 };
```


### Δείκτες συναρτήσεων

Ένας δείκτης σε συνάρτηση δηλώνεται ως εξής:
*τύπος-επιστροφής* (**όνομα-δείκτη*)(*λίστα-παραμέτρων*);

Ο παρακάτω κώδικας επιδεικνύει τη χρήση δείκτη συνάρτησης για την επιλογή μεταξύ πρόσθεσης και αφαίρεσης:


```c
int add(int x, int y) { 
    return x + y; 
}

int subtract(int x, int y) { 
    return x - y; 
}

int main(int argc, char* argv[]) {
   int (*operation)(int x, int y);
   operation = argc > 1 ? add : subtract;
   int result = operation(10, 5);
   return 0;
}
```


## Τελεστές
## Ροή ελέγχου

### Σύνθετη εντολή (Compound statement)
Μια **σύνθετη εντολή** (ή μπλοκ εντολών) είναι ένα ζεύγος αγκυλών που περιέχει οποιονδήποτε αριθμό εντολών. Απαιτείται για το σώμα των συναρτήσεων και για δομές ελέγχου που περιλαμβάνουν περισσότερες από μία εντολές.
### Εντολή If
Η εντολή υπό συνθήκη  έχει την εξής μορφή:**if** (*έκφραση*) { *εντολή* } **else** { *εντολή* }

Εάν η έκφραση αξιολογηθεί ως μη μηδενική (αληθής), εκτελείται η πρώτη εντολή. Διαφορετικά, εκτελείται η δεύτερη (εφόσον υπάρχει το ). Κάθε  αντιστοιχεί στο πλησιέστερο προηγούμενο  που δεν έχει ήδη αντιστοιχιστεί.
```c
if (i == 1) {
    printf("Είναι 1");
} else if (i == 2) {
    printf("Είναι 2");
} else {
    printf("Είναι κάτι άλλο");
}
```


### Εντολή Switch
Η εντολή  μεταφέρει τον έλεγχο στην ετικέτα  που αντιστοιχεί στην τιμή μιας ακέραιας έκφρασης. Εάν δεν βρεθεί αντιστοιχία, ο έλεγχος μεταφέρεται στην ετικέτα  (αν υπάρχει). Η εκτέλεση συνεχίζεται μέχρι να βρεθεί μια εντολή  ή μέχρι το τέλος του σώματος της .

Η σύνταξη έχει ως εξής:**switch** (*έκφραση*) { **case** *τιμή*: *εντολές* **default**: *εντολές* }

Εάν δεν χρησιμοποιηθεί η εντολή , η εκτέλεση «ρέει» στην επόμενη περίπτωση (fall-through). Αυτό μπορεί να είναι χρήσιμο σε κάποιες περιπτώσεις, αλλά συχνά αποτελεί πηγή προγραμματιστικών λαθών.

Από το πρότυπο C2Y, είναι πλέον δυνατή η χρήση εύρους τιμών (case range) με την αποσιωπητική τελεία .


```c
switch (num) {
    case 1 ... 3:
        printf("Ο αριθμός είναι 1, 2 ή 3\n");
        break;
    default:
        printf("Άλλος αριθμός\n");
}
```


### Εντολές επανάληψης (Loops)
Υπάρχουν τρεις μορφές εντολών επανάληψης στη C:
* **while**: Ο έλεγχος της συνθήκης γίνεται **πριν** από κάθε εκτέλεση του σώματος του βρόχου.
* **do-while**: Ο έλεγχος της συνθήκης γίνεται **μετά** από κάθε εκτέλεση, διασφαλίζοντας ότι ο βρόχος θα εκτελεστεί τουλάχιστον μία φορά.
* **for**: Συνδυάζει την αρχικοποίηση, τον έλεγχο και την ενημέρωση σε μία γραμμή.


```c
// Παράδειγμα while
while (i < 10) { 
    i++; 
}

// Παράδειγμα for (από τη C99 επιτρέπεται η δήλωση μέσα στο for)
for (int i = 0; i < 10; ++i) {
    printf("%d ", i);
}
```


Η λογική της  μπορεί να αναπαρασταθεί με μια  ως εξής:

```c
αρχικοποίηση;
while (συνθήκη) {
    εντολές;
    ενημέρωση;
}
```


Αν και η C δεν διαθέτει εγγενή βρόχο  (όπως η Java ή η C++), αυτό μπορεί να προσομοιωθεί χρησιμοποιώντας μακροεντολές (macros) ή την κλασική δομή  πάνω σε πίνακες.

### Εντολές άλματος (Jump statements)
Υπάρχουν τέσσερις εντολές άλματος (που μεταφέρουν τον έλεγχο άνευ όρων): η , η , η , και η .

Η εντολή  μεταβιβάζει τον έλεγχο του προγράμματος σε μια εντολή που φέρει ετικέτα. Η σύνταξή της είναι:**goto** *όνομα-ετικέτας*;

Η εντολή  μεταφέρει τον έλεγχο στο σημείο συνέχισης του βρόχου της εσωτερικότερης εντολής επανάληψης που την περιέχει. Πρέπει να βρίσκεται υποχρεωτικά εντός βρόχου.


```c
while (true) {
    // ...
    continue; // Μεταπηδά στον έλεγχο της συνθήκης
}
```


Η εντολή  τερματίζει την εκτέλεση μιας εντολής , ,  ή . Ο έλεγχος περνά στην εντολή που ακολουθεί αμέσως μετά το κλείσιμο της δομής ελέγχου.

Η εντολή  επιστρέφει τον έλεγχο στη συνάρτηση που έκανε την κλήση. Εάν ακολουθείται από μια έκφραση, η τιμή αυτής επιστρέφεται ως αποτέλεσμα της συνάρτησης.

### Ετικέτες (Labels)
Μια ετικέτα ορίζει ένα σημείο στον κώδικα στο οποίο μπορεί να μεταφερθεί ο έλεγχος. Αποτελείται από ένα αναγνωριστικό που ακολουθείται από άνω-κάτω τελεία.


```c
if (i == 1) {
    goto END;
}
// υπόλοιπος κώδικας
END:
    printf("Τέλος προγράμματος");
```


Από το πρότυπο C2Y, η C υποστηρίζει πλέον **ονομαστικούς βρόχους** (labelled loops), παρόμοια με τη Java. Αυτό επιτρέπει τη σύνδεση ετικετών με εντολές  και τη χρήση των  και  για έξοδο από πολλαπλά επίπεδα βρόχων (multi-level breaks).


```c
outer:
for (int i = 0; i < n; ++i) {
    for (int j = 0; j < m; ++j) {
        if (condition) {
            break outer; // Έξοδος και από τους δύο βρόχους ταυτόχρονα
        }
    }
}
```


## Συναρτήσεις

### Ορισμός
Για μια συνάρτηση που επιστρέφει τιμή, ο ορισμός αποτελείται από το όνομα του τύπου επιστροφής, το όνομα της συνάρτησης (το οποίο πρέπει να είναι μοναδικό), μια λίστα παραμέτρων σε παρενθέσεις και ένα μπλοκ εντολών που περιλαμβάνει την εντολή .

Η σύνταξη είναι η εξής:
*τύπος-επιστροφής* *όνομα-συνάρτησης***(** *λίστα-παραμέτρων* **)** { *εντολές* **return** *τιμή*; }

Μια συνάρτηση που δεν επιστρέφει τιμή δηλώνεται με τη λέξη-κλειδί  στη θέση του τύπου επιστροφής. Το πρότυπο της C δεν περιλαμβάνει λάμδα (lambda) συναρτήσεις, αν και ορισμένοι μεταγλωττιστές τις προσφέρουν ως επέκταση.
### Παράμετροι
Η λίστα παραμέτρων είναι μια λίστα δηλώσεων μεταβλητών διαχωρισμένων με κόμμα. Ο τύπος επιστροφής δεν μπορεί να είναι πίνακας ή συνάρτηση, αλλά μπορεί να είναι δείκτης σε αυτά.


```c
int f()[3];    // Σφάλμα: συνάρτηση που επιστρέφει πίνακα
int (*g())[3]; // Σωστό: συνάρτηση που επιστρέφει δείκτη σε πίνακα
```


Εάν μια συνάρτηση δεν δέχεται παραμέτρους, η λίστα μπορεί να είναι κενή ή να περιέχει τη λέξη . Η χρήση του  θεωρείται βέλτιστη πρακτική, καθώς υποδηλώνει ρητά ότι η συνάρτηση δεν δέχεται ορίσματα.

Μια συνάρτηση μπορεί να δέχεται μεταβλητό αριθμό ορισμάτων χρησιμοποιώντας αποσιωπητικά  στο τέλος της λίστας (όπως η ). Ο χειρισμός αυτών των ορισμάτων γίνεται μέσω της βιβλιοθήκης .

### Κλήση συναρτήσεων
Για να χρησιμοποιηθεί μια συνάρτηση βιβλιοθήκης, πρέπει πρώτα να δηλωθεί, συνήθως μέσω της οδηγίας  για το αντίστοιχο αρχείο επικεφαλίδας (.h). Η σύνδεση (linking) με τον κώδικα της βιβλιοθήκης γίνεται κατά το στάδιο της σύνδεσης του προγράμματος.

### Μεταβίβαση ορισμάτων
Στη C, τα ορίσματα μεταβιβάζονται πάντα **κατά τιμή** (pass by value), πράγμα που σημαίνει ότι η συνάρτηση λαμβάνει ένα αντίγραφο της τιμής και δεν μπορεί να τροποποιήσει την αρχική μεταβλητή. Για να τροποποιηθεί μια μεταβλητή από μια συνάρτηση, ο προγραμματιστής πρέπει να μεταβιβάσει τη διεύθυνση της μεταβλητής (δείκτη), προσομοιώνοντας τη μεταβίβαση **κατ' αναφορά** (pass by reference).

Παράδειγμα τροποποίησης μεταβλητής μέσω δείκτη:

```c
void incInt(int* y) { 
    (*y)++; // Αυξάνει την τιμή στη διεύθυνση που δείχνει ο y
}

int main(void) {
    int x = 7;
    incInt(&x); // Μεταβιβάζει τη διεύθυνση του x
    return 0;
}
```


#### Μεταβίβαση πινάκων
Όταν ένας πίνακας περνάει ως παράμετρος σε μια συνάρτηση, μετατρέπεται αυτόματα σε δείκτη προς το πρώτο του στοιχείο. Επομένως, οι αλλαγές στα στοιχεία του πίνακα μέσα στη συνάρτηση επηρεάζουν τον αρχικό πίνακα.


```c
void setArray(int array[], int index) {
    array[index] = 123;
}
```

Ο παραπάνω ορισμός είναι ισοδύναμος με τον: .

Από το πρότυπο C99, μπορεί να χρησιμοποιηθεί η λέξη-κλειδί  μέσα στις αγκύλες της παραμέτρου, π.χ. , για να δηλωθεί ότι ο πίνακας πρέπει να έχει τουλάχιστον ένα συγκεκριμένο μέγεθος.

## Attributes (Γνωρίσματα)
Τα **attributes** (γνωρίσματα) προστέθηκαν στο πρότυπο C23 (προερχόμενα από τη C++11) και επιτρέπουν τη χρήση ακολουθιών προσδιορισμού γνωρισμάτων. Τα attributes μπορούν να εφαρμοστούν σε οποιοδήποτε σύμβολο τα υποστηρίζει, όπως συναρτήσεις και μεταβλητές, ώστε ο μεταγλωττιστής να χειριστεί το αντίστοιχο σύμβολο με ειδικό τρόπο. 

Μπορούν να θεωρηθούν παρόμοια με τα annotations της Java, καθώς παρέχουν πρόσθετες πληροφορίες στον μεταγλωττιστή, αλλά διαφέρουν στο ότι δεν είναι μεταδεδομένα προσβάσιμα μέσω reflection. Επίσης, στη C δεν είναι δυνατή η δημιουργία προσαρμοσμένων (custom) attributes από τον χρήστη, αν και υπάρχουν attributes ειδικά για κάθε κατασκευαστή (vendor-specific), τα οποία συνήθως συνοδεύονται από έναν χώρο ονομάτων (π.χ. τα  για τους GCC και Clang).

Η σύνταξη για τη χρήση ενός attribute σε μια συνάρτηση είναι η εξής:


```c
[[nodiscard]]
bool satisfiesProperty(const struct MyStruct* s);
```


Το πρότυπο ορίζει τα ακόλουθα τυπικά attributes:

## Παραπομπές

Κατηγορία:Προγραμματισμός
Κατηγορία:C