Οδηγός Μελέτης - Εισαγωγή στον Προγραμματισμό

Διάλεξη 12 · 10/11/2025 · Διαφάνειες (PDF) · Σημειώσεις 5 · Σημειώσεις 6 · Εργαστήριο 6 · Εργαστήριο 7 · Εργαστήριο 8

Κεφάλαιο 12: Δείκτες και Πίνακες

Στόχοι: μετά από αυτό το κεφάλαιο θα μπορείτε να χρησιμοποιείτε πολυδιάστατους πίνακες και να υπολογίζετε πού βρίσκεται στη μνήμη το a[i][j]· να χειρίζεστε δείκτες σε δείκτες, πίνακες από δείκτες και το argv· να δεσμεύετε δυναμικούς πίνακες με malloc· και να εξηγείτε τι είναι το endianness.

Προαπαιτούμενα: Κεφάλαιο 10, Κεφάλαιο 11

Χρόνος μελέτης: ~2,5 ώρες

Σύνοψη

Η διάλεξη πηγαίνει τους πίνακες και τους δείκτες ένα βήμα πιο πέρα. Οι δισδιάστατοι πίνακες της C είναι πίνακες από πίνακες, αποθηκευμένοι γραμμή-γραμμή σε συνεχόμενη μνήμη, οπότε η θέση του a[i][j] βγαίνει με έναν απλό τύπο. Οι δείκτες σε δείκτες και οι πίνακες από δείκτες (με κορυφαίο παράδειγμα το argv) προσθέτουν ένα επίπεδο έμμεσης αναφοράς. Η malloc δίνει πίνακες με μέγεθος που αποφασίζεται κατά την εκτέλεση, και το endianness εξηγεί τη σειρά των bytes ενός ακεραίου. Όλα αυτά στηρίζουν τις δομές δεδομένων του δεύτερου μισού του μαθήματος.

Θεωρία

§12.1 Ο πίνακας στη μνήμη

Ένας πίνακας (array) κρατά δεδομένα ίδιου τύπου (Κεφάλαιο 10). Στη δήλωση int bears[100]; ο τύπος (type) ορίζει πόση μνήμη παίρνει κάθε στοιχείο, το όνομα (name) κάνει τον μεταγλωττιστή να διαλέξει μια διεύθυνση για τον πίνακα, και το μέγεθος (size) πόσα στοιχεία θα κρατήσει. Το μέγεθος είναι στατικό: δεν αλλάζει κατά την εκτέλεση. Στα στοιχεία αναφερόμαστε με τη θέση (index) τους, bears[0] έως bears[99], και αυτά κάθονται σε συνεχόμενες θέσεις. Με sizeof(int) == 4 και αρχή στη διεύθυνση 4:

Bytes 0–3 4–7 8–11 … 400–403
Περιεχόμενο (άλλο) bears[0] bears[1] … bears[99]

Ο πίνακας πιάνει \(4 \cdot 100 = 400\) bytes (4–403), και το bears[i] βρίσκεται στη διεύθυνση «αρχή + i * sizeof(int)».

§12.2 Δισδιάστατοι πίνακες

Εικόνες, επιστημονικά και οικονομικά δεδομένα ή μια σκακιέρα έχουν φυσικά περισσότερες διαστάσεις (dimensions). Ένας δισδιάστατος πίνακας (two-dimensional array) είναι πίνακας από (υπο)πίνακες: τύπος όνομα[γραμμές][στήλες];. Οι γραμμές (rows) είναι πόσους υποπίνακες έχει (1η διάσταση) και οι στήλες (columns) πόσα στοιχεία έχει ο καθένας (2η διάσταση), άρα συνολικά γραμμές × στήλες στοιχεία. Το a[i][j] είναι το στοιχείο της γραμμής i και της στήλης j, με μέτρηση από το 0, και χρησιμοποιείται όπως μια απλή μεταβλητή. Η αρχικοποίηση δίνει μία λίστα σε αγκύλες ανά γραμμή (εδώ η γραμμή 0 είναι 1, 4, 7, 10 και η γραμμή 1 είναι 3, 6, 9, 12):

int array[2][4] = {
    {1, 4, 7, 10},
    {3, 6, 9, 12},
};

Σε αρχικοποίηση μπορεί να παραλειφθεί μόνο το μέγεθος της πρώτης διάστασης (char arr[][2] = {{'a','b'},{'c','d'}};, από τις σημειώσεις)· ο λόγος φαίνεται στον υπολογισμό διευθύνσεων παρακάτω.

§12.3 Αποθήκευση κατά γραμμές και sizeof

Η μνήμη είναι μονοδιάστατη, γι’ αυτό η C αποθηκεύει τον πίνακα κατά γραμμές (row-major order): όλη η γραμμή 0, αμέσως μετά η γραμμή 1. Για τον παραπάνω array, με αρχή στο 100 (κάθε στοιχείο πιάνει 4 bytes):

Bytes 100 104 108 112 116 120 124 128
Τιμή 1 4 7 10 3 6 9 12
Στοιχείο [0][0] [0][1] [0][2] [0][3] [1][0] [1][1] [1][2] [1][3]

Αφού ο πίνακας είναι πίνακας από πίνακες, το array[0] είναι από μόνο του ένας πίνακας 4 ακεραίων (bytes 100–115) και το array[1] ο επόμενος (116–131). Γι’ αυτό sizeof(array[0]) και sizeof(array[1]) τυπώνουν 16 και sizeof(array) 32 (οι διαφάνειες τυπώνουν με %d· για size_t το σωστό είναι %zu), και sizeof(array) / sizeof(array[0]) δίνει το πλήθος των γραμμών.

§12.4 Υπολογισμός διεύθυνσης στοιχείου

Για int array[X][Y];, για να φτάσουμε στο a[i][j] προσπερνάμε i γραμμές των Y ακεραίων και μετά j ακεραίους:

&a[i][j] = StartAddressOfArray + i * Y * sizeof(int) + j * sizeof(int)
IndexOfElementIJ = i * Y + j

Ο δεύτερος είναι η θέση σε έναν νοητό μονοδιάστατο πίνακα X * Y ακεραίων. Και οι δύο χρειάζονται μόνο τον αριθμό Y των στηλών. Γι’ αυτό η πρώτη διάσταση μπορεί να παραλειφθεί, και μια συνάρτηση που δέχεται δισδιάστατο πίνακα γράφει την παράμετρο π.χ. int matr[][12] (σημειώσεις, «Πολυδιάστατοι πίνακες»). Έλεγχος με τον πίνακα παραπάνω: το a[1][2] είναι στο \(100 + 1 \cdot 4 \cdot 4 + 2 \cdot 4 = 124\), όπου πράγματι βρίσκεται το 9.

§12.5 Πίνακες περισσότερων διαστάσεων

Πίνακες τριών ή περισσότερων διαστάσεων λειτουργούν με τον ίδιο τρόπο, με περισσότερα ζεύγη αγκυλών (π.χ. int rubiksCube[6][3][3];), και είναι πάλι συνεχόμενοι στη μνήμη: για [X][Y][Z] η θέση του [i][j][k] είναι i * Y * Z + j * Z + k. Η διάλεξη ρωτά: είναι απαραίτητοι οι πολυδιάστατοι πίνακες; Όχι· μπορούμε να κρατήσουμε τα ίδια δεδομένα σε μονοδιάστατο πίνακα και να υπολογίζουμε μόνοι μας τη θέση. Είναι όμως βολικοί, γιατί τον λογαριασμό τον κάνει ο μεταγλωττιστής.

§12.6 Δείκτες: υπενθύμιση

Ένας δείκτης (pointer) κρατά μια διεύθυνση μνήμης (Κεφάλαιο 11). Ο μοναδιαίος * κάνει αποαναφορά (dereference): μετά το int *pointer = &x; το *pointer είναι ισοδύναμο με το x, για ανάγνωση και για εγγραφή (αν το x είναι στη διεύθυνση 100, ο pointer περιέχει την τιμή 100).

Στην αριθμητική δεικτών (pointer arithmetic), αν ο p δείχνει σε int, ο p + 2 δείχνει δύο ακεραίους (όχι bytes) πιο μετά, το *(p + 2) ισοδυναμεί με p[2] και το p++ πάει στο επόμενο στοιχείο. Το όνομα ενός πίνακα σε έκφραση μετατρέπεται σε δείκτη στο πρώτο του στοιχείο, άρα το p = x; κάνει τον p να δείχνει στο x[0].

§12.7 Δείκτης σε δείκτη

Ένας δείκτης έχει κι αυτός διεύθυνση, που μπορεί να αποθηκευτεί σε άλλον δείκτη. Ο δείκτης σε δείκτη (pointer to pointer) δηλώνεται με δύο αστερίσκους: μετά από int x = 42; int *ptr = &x; int **ptr2 = &ptr; ο ptr2 είναι δείκτης σε int * (διαβάστε τον τύπο από δεξιά). Με τις διευθύνσεις της διαφάνειας:

Μεταβλητή Τύπος Διεύθυνση Τιμή
x int 100 42
ptr int * 200 100
ptr2 int ** 400 200
flowchart LR
    P2["ptr2: int ** (400)"] --> P["ptr: int * (200)"]
    P --> X["x: int (100) = 42"]

Σχήμα: κάθε * ακολουθεί ένα βέλος· *ptr2 είναι ο ptr (100), **ptr2 ο x (42).

Η διάλεξη ρωτά τι τυπώνει το printf("%p %d", *ptr2, **ptr2);: μια διεύθυνση (σε δεκαεξαδικό, διαφορετική σε κάθε εκτέλεση) και το 42. Το ίδιο γενικεύεται σε int ***. Γιατί έχει σημασία; Δέντρα και γράφοι είναι κόμβοι που δείχνουν σε άλλους κόμβους (Κεφάλαιο 21), και το argv και οι δυναμικοί δισδιάστατοι πίνακες έχουν τύπους char ** και int **.

§12.8 Πίνακες από δείκτες

Οι δείκτες μπαίνουν και σε πίνακες: ο πίνακας από δείκτες (array of pointers) int *ptr[3]; έχει τρία στοιχεία τύπου int *. Το *ptr[2] σημαίνει *(ptr[2]), γιατί οι αγκύλες έχουν μεγαλύτερη προτεραιότητα από τον μοναδιαίο *.

Η συνηθέστερη χρήση είναι ένας πίνακας συμβολοσειρών, char *sentence[]: κάθε στοιχείο δείχνει στον πρώτο χαρακτήρα μιας συμβολοσειράς, και σε αντίθεση με έναν δισδιάστατο πίνακα char οι συμβολοσειρές μπορούν να έχουν διαφορετικά μήκη. Συχνά το τελευταίο στοιχείο είναι ο κενός δείκτης (null pointer) NULL, που λειτουργεί ως «φρουρός»: ένας βρόχος με συνθήκη sentence[i] σταματά εκεί χωρίς να ξέρει το πλήθος.

flowchart LR
    S0["sentence[0]"] --> W0["I'm"]
    S1["sentence[1]"] --> W1["singing"]
    S2["sentence[2]"] --> W2["in"]
    S3["sentence[3]"] --> W3["the"]
    S4["sentence[4]"] --> W4["rain"]
    S5["sentence[5]"] --> W5["!"]
    S6["sentence[6]"] --> N["NULL"]

Σχήμα: πίνακας από δείκτες σε συμβολοσειρές διαφορετικού μήκους, με NULL στο τέλος.

§12.9 Το argv

Το πιο γνωστό παράδειγμα πίνακα από δείκτες είναι η παράμετρος της main για τα ορίσματα γραμμής εντολών (command-line arguments): int main(int argc, char * argv[]). Το argc είναι το πλήθος των ορισμάτων μαζί με το όνομα του προγράμματος, και το argv[i] δείχνει στη συμβολοσειρά του i-οστού ορίσματος. Για ./echo hello fine world έχουμε argc = 4:

flowchart LR
    A0["argv[0]"] --> T0["'.' '/' 'e' 'c' 'h' 'o' '#92;0'"]
    A1["argv[1]"] --> T1["'h' 'e' 'l' 'l' 'o' '#92;0'"]
    A2["argv[2]"] --> T2["'f' 'i' 'n' 'e' '#92;0'"]
    A3["argv[3]"] --> T3["'w' 'o' 'r' 'l' 'd' '#92;0'"]

Σχήμα: το argv για ./echo hello fine world (argc = 4).

Τα πραγματικά ορίσματα ξεκινούν από το argv[1], και το argv[argc] είναι NULL (σημειώσεις, «Ορίσματα γραμμής εντολών»). Επειδή ένας πίνακας περνά σε συνάρτηση ως δείκτης στο πρώτο του στοιχείο, η παράμετρος γράφεται ισοδύναμα char **argv.

§12.10 Δυναμικοί πίνακες με malloc

Όταν το μέγεθος γίνεται γνωστό μόνο κατά την εκτέλεση (π.χ. διαβάζεται από την είσοδο), χρησιμοποιούμε δυναμικούς πίνακες (dynamic arrays):

τύπος * όνομα = malloc(μέγεθος * sizeof(τύπος));

Η malloc (από το stdlib.h) δεσμεύει μνήμη και επιστρέφει τη διεύθυνσή της, που την κρατά ένας δείκτης στον τύπο των στοιχείων. Το όρισμα είναι σε bytes, γι’ αυτό πολλαπλασιάζουμε το πλήθος με sizeof(τύπος). Το int * array = malloc(N * sizeof(int)); δημιουργεί πίνακα N ακεραίων, που χάρη στην αριθμητική δεικτών χρησιμοποιείται κανονικά, από array[0] έως array[N - 1]. Η μνήμη αυτή βρίσκεται στον σωρό (heap), το θέμα του Κεφαλαίου 13.

Από τις σημειώσεις: η malloc δεν αρχικοποιεί τη μνήμη (οι τιμές 1, 3, 3, 7 της διαφάνειας είναι ενδεικτικές)· αν αποτύχει επιστρέφει NULL, οπότε ελέγχουμε πάντα το αποτέλεσμα· και ό,τι δεσμεύσαμε το αποδεσμεύουμε με free. Το sizeof ενός δείκτη είναι το μέγεθος μιας διεύθυνσης (8 bytes σε σύστημα 64 bit), όχι του μπλοκ, οπότε το πλήθος των στοιχείων το κρατάμε σε μεταβλητή. Ένας δυναμικός δισδιάστατος πίνακας N × M φτιάχνεται με έναν int ** που δείχνει σε N δείκτες γραμμών, με κάθε γραμμή από δική της malloc, ή με έναν μονοδιάστατο πίνακα N * M και τη θέση i * M + j.

§12.11 Endianness

Ένας int αποτελείται από πολλά bytes. Endianness λέμε τη σειρά με την οποία αποθηκεύονται: little endian από το μικρότερο (λιγότερο σημαντικό) byte προς το μεγαλύτερο, big endian αντίστροφα. Για τα διαδοχικά bytes 68 65 6c 6c (ASCII 'h' 'e' 'l' 'l'):

Μηχάνημα byte +0 byte +1 byte +2 byte +3 Ακέραιος
little endian 68 65 6c 6c 0x6c6c6568
big endian 68 65 6c 6c 0x68656c6c

Οι x86 και οι περισσότεροι ARM είναι little endian (τα σχήματα μνήμης των διαφανειών για τους δείκτες είναι σχεδιασμένα big endian, που διαβάζεται ευκολότερα). Το endianness μετράει σε δυαδικά δεδομένα, π.χ. κεφαλίδες αρχείων εικόνας και ήχου.

Παραδείγματα

§12.12 Η σκακιέρα

Εφαρμόζει τους «Δισδιάστατους πίνακες»: κάθε κελί είναι ένας char (κεφαλαία για τον έναν παίκτη, πεζά για τον άλλο, κενό για άδειο τετράγωνο).

#include <stdio.h>

int main() {
    char chessBoard[8][8] = {
        {'R', 'N', 'B', 'Q', 'K', 'B', 'N', 'R'},
        {'P', 'P', 'P', 'P', 'P', 'P', 'P', 'P'},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
        {' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '},
        {'p', 'p', 'p', 'p', 'p', 'p', 'p', 'p'},
        {'r', 'n', 'b', 'q', 'k', 'b', 'n', 'r'}
    };
    chessBoard[1][4] = ' ';
    chessBoard[3][4] = 'p';
    return 0;
}

Οι δύο αναθέσεις κάνουν την κίνηση e2–e4 (γραμμή 1 → γραμμή 3, στήλη 4). Με τη σύμβαση του πίνακα το πιόνι θα έπρεπε να είναι 'P'· η διαφάνεια γράφει 'p'. Για εκτύπωση, ο εξωτερικός βρόχος διατρέχει τις γραμμές και ο εσωτερικός τις στήλες.

§12.13 Ο κύβος του Rubik

Εφαρμόζει τους «Πίνακες περισσότερων διαστάσεων»: 6 έδρες × 3 × 3 = 54 ακέραιοι.

int rubiksCube[6][3][3] = {
    {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}}, // Face 1 (e.g., Red)
    {{1, 1, 1}, {1, 1, 1}, {1, 1, 1}}, // Face 2 (e.g., Green)
    {{2, 2, 2}, {2, 2, 2}, {2, 2, 2}}, // Face 3 (e.g., Blue)
    {{3, 3, 3}, {3, 3, 3}, {3, 3, 3}}, // Face 4 (e.g., Yellow)
    {{4, 4, 4}, {4, 4, 4}, {4, 4, 4}}, // Face 5 (e.g., Orange)
    {{5, 5, 5}, {5, 5, 5}, {5, 5, 5}}  // Face 6 (e.g., White)
};

§12.14 Βρόχος με αριθμητική δεικτών

Εφαρμόζει τη «Δείκτες: υπενθύμιση». Ποια είναι τα περιεχόμενα του x μετά την εκτέλεση;

int * p;
int x[] = {5, 7, 2, 3, 6, 0, 1, 4};
p = x;
while (*p = *(p+2))
  p++;

Η συνθήκη είναι ανάθεση: αντιγράφει στο *p την τιμή δύο θέσεις πιο μετά, και αφού η τιμή μιας ανάθεσης είναι η τιμή που ανατέθηκε, ο βρόχος σταματά μόλις αντιγραφεί ένα 0. Ο πίνακας αλλάζει όσο τρέχει ο βρόχος, οπότε ιχνηλατήστε βήμα-βήμα. Για όσους δυσκολεύονται με τους δείκτες, η διάλεξη προτείνει το βίντεο των βοηθών (δείτε το Διάβασμα).

§12.15 Πίνακας από δείκτες σε ακεραίους

Εφαρμόζει τους «Πίνακες από δείκτες»:

#include <stdio.h>
int main() {
  int *ptr[3], a = 100, b = 200, c = 300;
  ptr[0] = &a;
  ptr[1] = &b;
  ptr[2] = &c;
  printf("%d %d %d\n", *ptr[2], *ptr[1], *ptr[0]);
  return 0;
}
$ ./example
300 200 100

§12.16 Μια πρόταση ως πίνακας από συμβολοσειρές

Εφαρμόζει τους «Πίνακες από δείκτες» με φρουρό NULL:

#include <stdio.h>
int main() {
  char *sentence[] = {
      "I'm", "singing", "in", "the", "rain", "!", NULL
  };
  int i;
  for(i = 0 ; sentence[i]; i++) {
      printf("%s\n", sentence[i]);
  }
  return 0;
}
$ ./sentence
I'm
singing
in
the
rain
!

§12.17 Ένα απλό echo

Εφαρμόζει «Το argv»: τυπώνει όλα τα ορίσματα, μαζί με το όνομα του προγράμματος. Για ορίσματα-αριθμούς (π.χ. argcalc.c του εργαστηρίου 8) χρειάζεται η atoi.

#include <stdio.h>
int main(int argc, char * argv[]) {
  int i;
  for(i = 0 ; i < argc ; i++) {
    printf("%s\n", argv[i]);
  }
  return 0;
}
$ ./echo hello fine world
./echo
hello
fine
world

§12.18 Πόση μνήμη δεσμεύει η malloc

Εφαρμόζει τους «Δυναμικούς πίνακες». Πόση μνήμη δεσμεύει κάθε κλήση και τι τυπώνει το printf;

int * nums = malloc(100 * sizeof(int));
double * coeffs = malloc(100 * sizeof(double));
char * str = malloc(100 * sizeof(char));
printf("%zu %zu %zu\n", sizeof(nums), sizeof(coeffs), sizeof(str));
$ ./dynamic
8 8 8

Κάθε κλήση δεσμεύει 100 * sizeof(τύπος) bytes, αλλά το printf τυπώνει το μέγεθος των ίδιων των δεικτών: 8 bytes ο καθένας σε σύστημα 64 bit. Για την άσκηση array.c του εργαστηρίου 7: διαβάστε το N, δεσμεύστε, ελέγξτε για NULL, και στο τέλος free.

§12.19 Βλέποντας τα bytes ενός ακεραίου

Εφαρμόζει το «Endianness». Μετατρέπουμε (cast) τη διεύθυνση του x σε char *, που προχωρά ένα byte τη φορά. Τι θα τυπώσει;

#include <stdio.h>
int main() {
  int x = 42;
  char * bytes = (char*)&x;
  int i;
  for(i = 0; i < sizeof(int) / sizeof(char); i++)
     printf("%02x\n", bytes[i]);
  return 0;
}
$ ./int
2a
00
00
00

Το 42 είναι 0x0000002a· πρώτο τυπώνεται το λιγότερο σημαντικό byte, άρα το μηχάνημα είναι little endian. Επειδή το char είναι συνήθως προσημασμένο, ένα byte 0x80 θα έβγαινε ffffff80 με %02x· με unsigned char * αυτό δεν συμβαίνει.

Κύρια σημεία

  1. Ένας δισδιάστατος πίνακας είναι πίνακας από πίνακες, τύπος όνομα[γραμμές][στήλες], αρχικοποιείται με μία λίστα ανά γραμμή, και το a[i][j] είναι μια απλή μεταβλητή.
  2. Αποθηκεύεται κατά γραμμές σε συνεχόμενη μνήμη· sizeof(array[0]) είναι μία γραμμή, sizeof(array) όλος ο πίνακας.
  3. Για int array[X][Y] η θέση του a[i][j] είναι i * Y + j: χρειάζεται μόνο το Y, γι’ αυτό μόνο η πρώτη διάσταση μπορεί να παραλειφθεί.
  4. Πίνακες περισσότερων διαστάσεων λειτουργούν ίδια· δεν είναι απαραίτητοι, αλλά απλοποιούν τον κώδικα.
  5. Το *pointer ισοδυναμεί με τη μεταβλητή όπου δείχνει ο δείκτης· ένας int ** κρατά τη διεύθυνση ενός δείκτη, και κάθε * ακολουθεί ένα επίπεδο.
  6. Οι δείκτες μπαίνουν σε πίνακες· ένας πίνακας char * με NULL στο τέλος κρατά συμβολοσειρές διαφορετικού μήκους.
  7. Το argv είναι πίνακας από char * (ισοδύναμα char **) με argc στοιχεία, και το argv[0] είναι το όνομα του προγράμματος.
  8. Το malloc(μέγεθος * sizeof(τύπος)) φτιάχνει στον σωρό πίνακα με μέγεθος που αποφασίζεται κατά την εκτέλεση· το sizeof του δείκτη είναι 8, όχι το μέγεθος του μπλοκ.
  9. Endianness είναι η σειρά των bytes ενός ακεραίου: στο little endian πρώτο είναι το λιγότερο σημαντικό· με έναν char * το διαπιστώνουμε.

Ορολογία

Ελληνικά English Σύντομος ορισμός
πίνακας / θέση array / index Στοιχεία ίδιου τύπου σε συνεχόμενη μνήμη / ο i στο a[i].
δισδιάστατος πίνακας two-dimensional array Πίνακας από πίνακες, a[γραμμές][στήλες].
αποθήκευση κατά γραμμές row-major order Οι γραμμές αποθηκεύονται η μία μετά την άλλη.
αποαναφορά dereference Πρόσβαση με * εκεί όπου δείχνει ένας δείκτης.
δείκτης σε δείκτη pointer to pointer Δείκτης που κρατά διεύθυνση δείκτη, π.χ. int **.
πίνακας από δείκτες array of pointers Πίνακας με στοιχεία τύπου δείκτη, π.χ. char *s[5].
κενός δείκτης null pointer (NULL) Δείκτης που δεν δείχνει πουθενά· συχνά σημαδεύει το τέλος.
ορίσματα γραμμής εντολών command-line arguments Οι λέξεις της κλήσης, στα argc/argv.
δυναμικός πίνακας dynamic array Πίνακας με μέγεθος που αποφασίζεται κατά την εκτέλεση.
σωρός heap Η περιοχή μνήμης από την οποία δεσμεύει η malloc.
σειρά bytes endianness Η σειρά αποθήκευσης των bytes ενός ακεραίου.

Διάβασμα

Συχνά λάθη

Τι δυσκόλεψε την τάξη

Από τα Kahoot των διαλέξεων: οι ερωτήσεις όπου μια λάθος απάντηση μάζεψε πολλές ψήφους, με το ποσοστό σωστών απαντήσεων.

Ερωτήσεις κατανόησης

Kahoot από το αμφιθέατρο (Κ12.1–Κ12.9)

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

Ασκήσεις

Ζέσταμα: από τις διαφάνειες (Α12.1–Α12.7)

Εργαστήριο (Α12.8–Α12.11)

Εργασίες (Α12.12)

Θέματα εξετάσεων (Α12.13–Α12.22)

Σχετικές ασκήσεις από άλλα κεφάλαια

  1. 120 bytes· \(1000 + 2 \cdot 20 \cdot 4 + 3 \cdot 4 = 1172\). ↩

  2. Για να φτάσουμε στη γραμμή i προσπερνάμε i γραμμές μήκους Y. ↩

  3. argc είναι 3 και το argv[0] δείχνει στο "./prog". ↩

  4. 800 bytes στον σωρό· ο δείκτης είναι 8 bytes σε σύστημα 64 bit. ↩

  5. 78, 56, 34, 12. ↩

Κατεβάστε το κεφάλαιο: PDF · Markdown · GitHub