PDA

Επιστροφή στο Forum : Μεταβλητές σε C



ds electronics
14-09-11, 23:56
Καλησπέρα, έχω μια απορεία στην γλώσσα C.
Σύμφωνα με ένα βιβλίο που διάβασα (αγγλικό) λέει ότι κατα την εκκίνηση προγραμματισμού κρατάς των παρακάτω κανόνα:

void setup() {
μπλα μπλα μπλα
}
void loop() {
μπλα μπλα μπλα
}

Θεωρητικά λοιπόν ότι μεταβλητή ορίσω στο void setup δεν πρέπει να την θυμάται όταν την ζητάω στο void loop ?
Π.Χ ορίζω μια πόρτα σε μια μεταβλητή Χ και στην συνέχεια στο βασικό πρόγραμμα την ζητάω να την επεξεργαστώ. Το αποτέλεσμα που παίρνω είναι σφάλμα ότι η μεταβλητή μου δεν έχει οριστεί......

Αν μπορεί κάποιος ας με ξεμπλοκάρει στο τι δεν κατάλαβα........:crying:

klik
15-09-11, 02:01
http://www.icsd.aegean.gr/lecturers/Stamatatos/courses/logismiko/slides/c-09-scope.pdf

spiroscfu
15-09-11, 03:43
Θεωρητικά λοιπόν ότι μεταβλητή ορίσω στο void setup δεν πρέπει να την θυμάται όταν την ζητάω στο void loop ?
Π.Χ ορίζω μια πόρτα σε μια μεταβλητή Χ και στην συνέχεια στο βασικό πρόγραμμα την ζητάω να την επεξεργαστώ. Το αποτέλεσμα που παίρνω είναι σφάλμα ότι η μεταβλητή μου δεν έχει οριστεί......


Φυσικά πρέπει να προϋπάρχει η main() και η αρχικοποιήσει του προγράμματος και αν θέλεις οι καθολικές μεταβλητές.
Τώρα για το error σωστά στο βγάζει γιατί η μεταβλητή που ορίζεις μέσα στην συνάρτηση έχει τοπική εμβέλεια (μόνο μέσα σε αυτήν) ο μόνος τρόπος για να την προσπελάσεις είναι με pointer (δείκτες),
ή πολύ ποιο απλά την κάνεις καθολική (στην αρχή της main()).

klik
15-09-11, 09:41
...(στην αρχή της main()). πριν την main και "έξω" από αυτή.:001_smile:

spiroscfu
15-09-11, 11:03
Αν οι συναρτήσεις είναι έξω από αυτήν.

picdev
15-09-11, 11:25
λες για τις global μεταβλητές.
Μία μεταβλητή είναι global όταν ορίζεται έξω απο κάθε συνάρτηση (έξω και απο τη main),
ετσι είναι ορατή απο όλες τις συναρτήσεις,
αν τώρα ορίσεις μία μεταβλητή στη main , θα είναι ορατή μέσα στη main και σε όποια συνάρτηση είναι μέσα στη main.
Γενικά ψάξε για "ορατοτητα μεταβλητων"

εδώ το α είναι ορατό στη πρώτη και στη εμφωλευμένη συνάρτηση

{ α { α } }

εδώ το bold α δεν είναι ορατό στα α της πρώτης συνάρτηση

{ α { α} } { α}

εδώ όλα τα α είναι ορατά μεταξύ τους

{ α{ α {α } } }

επλίζω να καταλάβες
*** μια επιφύλαξη αν αυτά ισχύουν στη c, στη java ισχυουν

spiroscfu
15-09-11, 11:31
Αν απάντησες σε εμένα εννοώ πως υπάρχουν οι καθολικές μεταβλητές σε επίπεδο συνάρτησης ή προγράμματος.

panosx13
16-09-11, 15:33
Βασικά ότι μεταβλητές ορίζεις μέσα στο function ειδικά, σε scope γενικά τις βλέπει μόνο αυτό και κανένα άλλο.

Για να μπορείς να επαιξεργαστείς την τιμή μιας μεταβλητής μπορείς να το κάνεις ευκολα με 2 τρόπους.

1) φτιάχνεις την μεταβλητη αυτή global. δηλαδή την ορίζεις έξω και απ την main. (κάτω απο τα #include)
px

#include <stdio.h>
int a;

void kati ()
{
a=40;
}

main
{
a=10;
kati();

}


2) περνάς την μεταβλήτη by reference στα ορίσματα της συνάρτησης. Με πιο απλά λόγια περνάς την διευθυνση που χει η μεταβλήτη αυτή σαν παράμετρο και ότι αλλάγες της κάνεισ μέσα στην συνάρτηση θα τις βλέπει και η main σου.
px

void kati (int *a)
{
*a=52;

}

sti main

{
int *a;
*a=10;
kati(a);

}

και ένας τρίτος

3) περνάς την μεταβλητή by value στα ορίσματα της συνάρτησης, και κάνεις return την νέα τιμή της μεταβλητής σου.
πχ

int kati (int a)
{
a++;
return a;
}

στη main

α=kati(a);

spiroscfu
16-09-11, 16:06
void kati (int *a)
{
*a=52;

}

sti main

{
int *a,b;
a=&b;
*a=10; // ή το b=10
kati(a); // ή kati(b);

}

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

panosx13
16-09-11, 22:45
Βασικά σε έχασα. ερώτση κανεις ή του δείχνεις κάποιο άλλο παράδειγμα?

spiroscfu
16-09-11, 23:09
Επισήμανα κάποιες ελλείψεις στο παραπάνω (για να μην μπερδευτεί).

Σωστό είναι έτσι.

void aa(int *a,int *b)
{
int c,d;
c=*a;
d=*b;
}

void main()
{
int h=5,i=8;
aa(&h,&i);
}

panosx13
20-09-11, 19:18
Επισήμανα κάποιες ελλείψεις στο παραπάνω (για να μην μπερδευτεί).

Σωστό είναι έτσι.

void aa(int *a,int *b)
{
int c,d;
c=*a;
d=*b;
}

void main()
{
int h=5,i=8;
aa(&h,&i);
}

ναι σωστο ειναι και αυτό αλλα είναι αλλο.

Στο παραδειγμα που έδωσα που βρήκες λάθος γιατί δεν το βλέπω μηπως κατι μου ξεφευγει?

spiroscfu
20-09-11, 19:43
void kati (int *a)
{
*a=52;

}

sti main

{
int *a;
*a=10;
kati(a);

}



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

panosx13
20-09-11, 20:25
Όπως σου είπα ορίζεις δυο φορές τον ίδιο pointer (και δεν ξέρω κατά πόσο είναι σωστό αυτό),
.

Και που είναι το πρόβλημα? σαν ονομα α είναι τα ίδια, σαν pointers είναι διαφορετικοι. Αφού ο ένας δηλώνεται στη main και ο άλλος στην κάτι δεν υπάρχει κάποιο πρόβλημα.

πρόβλημα θα ήταν αν τα δήλωνα μέσα στην ίδια συνάρτηση.



στην main() ορίζεις τον δείκτη αλλά δεν ορίζεις την μεταβλητή που δίχνει
και στη συνάρτηση στέλνεις την διεύθυνση της μεταβλητής που δεν έχεις ορίσει


μάλλον κάτι έχεις μπερδέψει. Λοιπόν γράφω τι γίνεται σε κάθε γραμμη στη main.

int *a; ----> Δηλώνω έναν pointer ο οποίος δείχνει σε μια διευθυνση μνήμης Χ όπου ανήκει ένας Integer.....
*a = 10 -----> Η διευθυνση που δείχνει ο pointer α παίρνει την τιμή 10
kati(a); ----> καλω την κάτι με παράμετρο την διευθυνση της a ( void kati (int *a) ).


Μάλλον σε μπερδευει το *a στη main.

πχ το παράδειγμα που δίνεις μπορεί να γίνει όπως παρακατω.

void main()
{
int h=5,i=8;
aa(&h,&i);
}

void main()
{
int *h=5,*i=8;
aa(h,i);
}

Σαν αποτέλεσμα δεν έχει διαφορά, το ίδιο θα βγάλει. απλώς εσύ χρησιμοποιείς pointers μόνο στην συνάρτηση ενώ εγώ και στη main και στη συνάρτηση.

klik
20-09-11, 21:29
πχ το παράδειγμα που δίνεις μπορεί να γίνει όπως παρακατω.

void main()
{
int h=5,i=8;
aa(&h,&i);
}

void main()
{
int *h=5,*i=8; ΛΑΘΟΣ, δείκτες σε τυχαίο χώρο (θέση μνήμης 5 και 8 )
aa(h,i);
}

Σαν αποτέλεσμα δεν έχει διαφορά, το ίδιο θα βγάλει. απλώς εσύ χρησιμοποιείς pointers μόνο στην συνάρτηση ενώ εγώ και στη main και στη συνάρτηση.
..........................

spiroscfu
20-09-11, 22:10
int *a; ----> Δηλώνω έναν pointer ο οποίος δείχνει σε μια διευθυνση μνήμης Χ όπου ανήκει ένας Integer.....
Για την ακρίβεια δηλώνεις έναν δείκτη ο οποίος δείχνει το πρώτο byte (α/α) ενός υποθετικού integer σε μια τυχαία θέση μνήμης.
*a = 10 -----> Η διευθυνση που δείχνει ο pointer α παίρνει την τιμή 10
Μπορεί το 10 να γραφτεί όπου θέλει
kati(a); ----> καλω την κάτι με παράμετρο την διευθυνση της a ( void kati (int *a) ).



Μάλλον σε μπερδευει το *a στη main.

πχ το παράδειγμα που δίνεις μπορεί να γίνει όπως παρακατω.

void main()
{
int h=5,i=8;
aa(&h,&i);
}

void main()
{
int *h=5,*i=8;
aa(h,i);
}

Σαν αποτέλεσμα δεν έχει διαφορά, το ίδιο θα βγάλει. απλώς εσύ χρησιμοποιείς pointers μόνο στην συνάρτηση ενώ εγώ και στη main και στη συνάρτηση.

Klik με το παρακάτω σχόλιο σου
int *h=5,*i=8; ΛΑΘΟΣ, δείκτες σε τυχαίο χώρο (θέση μνήμης 5 και 8 )
νομίζω πως γράφει το 5 και το 8 σε δυο τυχαίες θέσης μνήμης που μπορεί (δεν είμαι σίγουρος) ο πρώτος να αυξάνει ανά 5 και ο δεύτερος ανά 8.
αυτό που γράφεις θα γίνονταν μάλλον έτσι
&h=5,&i=8.

klik
20-09-11, 23:14
Klik με το παρακάτω σχόλιο σου
int *h=5,*i=8; ΛΑΘΟΣ, δείκτες σε τυχαίο χώρο (θέση μνήμης 5 και 8 )
νομίζω πως γράφει το 5 και το 8 σε δυο τυχαίες θέσης μνήμης που μπορεί (δεν είμαι σίγουρος) ο πρώτος να αυξάνει ανά 5 και ο δεύτερος ανά 8.
αυτό που γράφεις θα γίνονταν μάλλον έτσι
&h=5,&i=8.
Το 5 και το 8 το γράφει στις μεταβλητές h και i (οι οποίες δεν είναι τυχαίες, αλλά υπάρχουσες μεταβλητές). Μέχρι εκεί είναι απλά επικίνδυνο (όπλο οπλισμένο και απασφαλισμένο) αλλά ακόμα δεν έχει πυροδοτήσει το πόδι.
Μια εντολή που τραβά τη σκανδάλη, είναι π.χ. *h = 32 (τώρα το 32 θα γραφτεί στο 5ο byte της RAM) δηλαδή οποιαδήποτε εντολή αποδώσει τιμή στις θέσεις *h ή *i.

panosx13
21-09-11, 00:06
Το 5 και το 8 το γράφει στις μεταβλητές h και i (οι οποίες δεν είναι τυχαίες, αλλά υπάρχουσες μεταβλητές). Μέχρι εκεί είναι απλά επικίνδυνο (όπλο οπλισμένο και απασφαλισμένο) αλλά ακόμα δεν έχει πυροδοτήσει το πόδι.
Μια εντολή που τραβά τη σκανδάλη, είναι π.χ. *h = 32 (τώρα το 32 θα γραφτεί στο 5ο byte της RAM) δηλαδή οποιαδήποτε εντολή αποδώσει τιμή στις θέσεις *h ή *i.

Εχεις απόλυτο δίκιο, απλως το παραπάνω είναι ψευδοκώδικας δεν είναι αυστηρά C. Απλώς βαριέμαι να κάθομαι να γράφω int *h ; h=malloc(sizeof(int)); (*h)=5 και απλά δίνω *h=5. Λογικό να δημιουργησα μπέρδεμα αφού δεν γίνεται να είστε μέσα στο μυαλό μου και να ξέρετε τι εννοω. Σορρυ. Ελπίζω να το ξεδιαλυνα το θέμα.

spiroscfu
21-09-11, 03:43
Πολύ πολύπλοκα και περίεργα το κάνεις, απλά ορίζεις μια άλλη μεταβλητή και δίνεις την διεύθυνση της στην τιμή του δείκτη.
π.χ. int *a,b; a=&b;

spiroscfu
21-09-11, 04:13
Το 5 και το 8 το γράφει στις μεταβλητές h και i (οι οποίες δεν είναι τυχαίες, αλλά υπάρχουσες μεταβλητές). Μέχρι εκεί είναι απλά επικίνδυνο (όπλο οπλισμένο και απασφαλισμένο) αλλά ακόμα δεν έχει πυροδοτήσει το πόδι.
Μια εντολή που τραβά τη σκανδάλη, είναι π.χ. *h = 32 (τώρα το 32 θα γραφτεί στο 5ο byte της RAM) δηλαδή οποιαδήποτε εντολή αποδώσει τιμή στις θέσεις *h ή *i.

Σωστά κάνουμε αρχικοποίηση στους δείκτες και αν η int είναι και 4 byte τότε θα μπλέκονται και αναμεταξύ τους εκτός τον δεδομένον που θα επηρεάζουν.


Το h=32 θα δουλεύει σαν το *h=32?

Mihos
21-09-11, 06:27
Το h=32 θα δουλεύει σαν το *h=32?
Όχι. Άλλο το ένα άλλο το άλλο. Μόνο στις αποδώσεις αρχικών τιμών στις δηλώσεις μεταβλητών μπορείς να γράψεις:
void *p=1;
Και αυτό να είναι ισοδύναμο με p=1 (αρχικοποιείται ο δείκτης και όχι ο χώρος στον οποίο δείχνει).

Πάντως κανείς μπορεί να σπάσει πολύ πλάκα με τη C...

Να βάλω ένα πρόβλημα για δυνατούς λύτες?


int* a(int *n){
int a;
a = *n;
return &a;
}

int* b(int *n){
int b[] = {0,0,42,0,2};
return &b[*n];
}

int zero(){
int zero = 0;
int* p = &zero;
p = a(p);
return *b(p);
}

Τι θα επιστρέψει η zero? Υποθέστε ότι ο compiler δεν κάνει καμία μα καμία βελτιστοποίηση...

klik
21-09-11, 14:50
...Τι θα επιστρέψει η zero? Υποθέστε ότι ο compiler δεν κάνει καμία μα καμία βελτιστοποίηση...
η zero στην εντολή p=a(p) έχει αποθηκεύσει άκυρη θέση στο p (θέση της auto μεταβλητής a που δεν υπάρχει πια)...
από εκεί και πέρα θα πρέπει να ξέρουμε αρχιτεκτονική του επεξεργαστή στον οποίο αναφέρεσαι και αν έχουμε cdecl ή pascal call argument passing, ώστε να δούμε τι θα έχει (αν έχει) γραφτεί στο stack στην θέση που ήταν το a.
(το οποίο δεν ξέρω αν αξίζει τον χρόνο να το ψάξουμε)

spiroscfu
21-09-11, 14:52
int* a(int *n){
int a;
a = *n; // ή a=0
return &a; // επιστρέφει την θέση μνήμης της a που έχει τιμή 0
}

int* b(int *n){
int b[] = {0,0,42,0,2};
return &b[*n]; // επιστρέφει απο το πίνακα b το b[0] που είναι 0
}

int zero(){
int zero = 0;
int* p = &zero; // ή *p=0
p = a(p); // ή p=a(&zero) και p=0
return *b(p); // 0
}

Τι θα επιστρέψει η zero? Υποθέστε ότι ο compiler δεν κάνει καμία μα καμία βελτιστοποίηση...

Το πέτυχα?

spiroscfu
21-09-11, 15:08
Όχι. Άλλο το ένα άλλο το άλλο.


Στο ποιο πίσω παράδειγμα όμως ο δείκτης *h δεν θα δείχνει στην μεταβλητή h.

Mihos
21-09-11, 16:58
η zero στην εντολή p=a(p) έχει αποθηκεύσει άκυρη θέση στο p (θέση της auto μεταβλητής a που δεν υπάρχει πια)...
από εκεί και πέρα θα πρέπει να ξέρουμε αρχιτεκτονική του επεξεργαστή στον οποίο αναφέρεσαι και αν έχουμε cdecl ή pascal call argument passing, ώστε να δούμε τι θα έχει (αν έχει) γραφτεί στο stack στην θέση που ήταν το a.
(το οποίο δεν ξέρω αν αξίζει τον χρόνο να το ψάξουμε)

Ναι οκ η ερώτηση μου είναι πολύ αόριστη αλλά η αοριστία είναι που έχει πλάκα. Η αλήθεια είναι ότι δεν έχω ιδέα πως δουλέυει το pascal passing και ούτε ήξερα ότι υπάρχουν c compilers που εφαρμόζουν αυτή τη σύμβαση. Τέλος πάντων, υπέθεσε ότι έχουμε ένα πολύ συμβατικό σύστημα (cdecl) σε έναν πολύ συνηθισμένο επεξεργαστή (x86) και όπως είπα χωρίς βελτιστοποιήσεις και κανένα περίεργο κολπάκι. Αν και βέβαια κάτι μου λέει ότι έχεις ήδη την απάντηση στο μυαλό σου (βασικά έχεις μία για κάθε διαφορετικό compiler και αρχιτεκτονική εσύ:001_rolleyes:...), επομένως για άσε να δούμε τι άλλες απαντήσεις θα έχουμε.

Αν αξίζει το κόπο; Θα κερνούσα μπύρα, αλλά το φόρουμ δεν έχει το εικονιδιάκι απ' ότι βλέπω...

Mihos
21-09-11, 17:00
Το πέτυχα?

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

Mihos
21-09-11, 17:04
Στο ποιο πίσω παράδειγμα όμως ο δείκτης *h δεν θα δείχνει στην μεταβλητή h.

Για ποιό παράδειγμα λες? Δεν βλέπω να λέει πουθενά h=&h;

klik
21-09-11, 17:06
Το πέτυχα?


όχι, ο Mihos έχει φτιάξει ίδιο call style (ίδιοι παράμετροι εισόδου, return value) οπότε, στην θέση της προσωρινής μεταβλητής a (πρώτη θέση στο stack), θα υπάρχει η "πρώτη" μεταβλητή της επόμενης συνάρτησης.

Τώρα εδώ έχουμε το εξής μπέρδεμα, έχουμε πίνακα αντί για μία μεταβλητή. Σε ένα πίνακα, το πρώτο στοιχείο είναι στην RAM με τη μικρότερη θέση και από εκεί και πέρα οι διευθύνσεις αυξάνονται.
Επειδή όμως ο πίνακας είναι αποθηκευμένο στο stack (το οποίο μεγαλώνει από μεγάλη διεύθυνση προς μικρή), η πρώτη τιμή στο stack είναι το τελευταίο στοιχείο του πίνακα (δηλαδή το 2).

Αρα το *n που δείχνει στην ίδια θέση με το *a, έχει την τιμή 2.
Οπότε η προσπέλαση του πίνακα γίνεται στο στοιχείο b[2] το οποίο είναι 42...

Αυτό δεν παίζει σε όλες τις αρχιτεκτονικές (π.χ. αν δεν έχουμε εκτέλεση κάθε task σε ξεχωριστό memory space, κάποιο interrupt θα είχε επικαλύψει τα δεδομένα μας) ούτε σε όλα τα calling convertions, καθότι δεν είναι δεσμευτικό από την ansi C.

ΥΓ. αν κατάλαβε κάποιος τι είπα παραπάνω, ας μου το πεί!:w00t:
ΥΓ2. περιμένω τη μπύρα μου!

Mihos
21-09-11, 17:19
Αν και στο φόρουμ δεν έχει το εικονοδιάκι εγώ κερνάω...
23684

Νομίζω είναι προφανές το πόσο πλάκα έχει!:drool:

klik
21-09-11, 17:44
γειά μας... 23685

spiroscfu
21-09-11, 22:17
Για ποιό παράδειγμα λες? Δεν βλέπω να λέει πουθενά h=&h;

Όχι δεν έχει κάτι τέτοιο το έχει έτσι int *h=5,*i=8;
Κάνει αρχικοποίηση στους δείκτες και ο *h θα δείχνει στην θέση μνήμης 5,
δηλ. αν κάνουμε *h=10 θα γραφτεί το 10 στο πέμπτο byte, αν όμως κάνουμε h=10 τότε τι θα γίνει (θα αλλάξουμε την θέση μνήμης)?

spiroscfu
21-09-11, 22:25
Μιχάλη χαλάς το klik, τον ποτίζεις και δεν βγάζουμε άκρη τη λέει και επειδής εγώ έμαθα την C από ένα βιβλίο (μόνο για τους pic) δηλ. είμαι χαμηλού επιπέδου όπως και η C,
δεν το εξηγείς ποιο απλά.

Mihos
21-09-11, 23:35
Όχι δεν έχει κάτι τέτοιο το έχει έτσι int *h=5,*i=8;
Κάνει αρχικοποίηση στους δείκτες και ο *h θα δείχνει στην θέση μνήμης 5,
δηλ. αν κάνουμε *h=10 θα γραφτεί το 10 στο πέμπτο byte, αν όμως κάνουμε h=10 τότε τι θα γίνει (θα αλλάξουμε την θέση μνήμης)?

Ναι, αλλάζουμε τη θέση που δείχνει ο h. Αν δλδ μετά γράψουμε *h = 1234 το 1234 θα πάει στη διέυθυνση 10 (λέμε τώρα...). Στη πραγματικότητα και στις δύο περιπτώσεις τα πρόγραμμα μάλλον θα "σκάσει" καθώς επιχειρούμε πρόσβαση σε θέση μνήμης που δεν έχουμε πρόσβαση...

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

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

Τώρα το πως υλοποιείται αυτή η "δημιουργεία" και η "καταστροφή" μεταβλητών είναι κάτι που εξαρτάται από τον εκάστοτε compiler και αρχιτεκτονική όπως φωνάζει και klik. Αλλά στις περισσότερες περιπτώσεις αυτό γίνεται με τη χρήση της στοίβας.

Η στοίβα είναι ένα κομμάτι μνήμης (στο τέλος τoυ χώρου διευθύνσεων που χρησιμοποιεί ένα πρόγραμμα) η οποία μεγαλώνει και μικραίνει σαν ακορντεον ανάλογα με τις κλίσεις συναρτήσεων. Δίνω ένα απλοικό παράδειγμα για το πως θα μπορούσε να λειτουργεί η στοίβα (δεν είναι απαραίτητο να λειτουργεί ακριβώς έτσι όπως είπαμε). Υπέθεσε ότι όλοι οι τύποι έχουν μέγεθος ίσο με 1 byte για απλοποίηση.

Έστω ότι είναι υπό εκτέλεση η συνέρτηση zero οι οποία χρησιμοποιεί τις αυτόματες μεταβλητές int zero και int* p. Η στοίβα θα μοίαζει κάπως έτσι:



|---p <-- Κορυφή της στοίβας stack_top
|-->zero <-- θέση μνήμης με τη μεγαλύτερη διεύθυνση


Αν η zero καλεί την a με παράμετρο την p και η a χρησιμοποιεί την αυτόματη μεταβλητή a τότε η στοίβα θα γίνει κάπως έτσι:



a <-- Κορυφή της στοίβας stack_top
|--------αντίγραφο της p <-- Η παράμετρος
| διάφορα άλλα χρήσιμα δεδομένα
| |---p
|--> |-->zero


Έτσι η a ξέρει ότι θα βρεί τη παράμετρο της στη διέυθυνση stack_top + 1 και την a στην stack_top. Μόλις τώρα επιστρέψει η a η στοίβα θα γίνει πάλι όπως πριν. Εντομεταξύ η p μεταβλητή θα δείνχει εκεί που υπήρχε πριν η a αφού η συνάρτηση a επιστρέφει &a.



|--->Θέση της κατεστραμένης a.
| ...
| ...
|----p <-- Κορυφή της στοίβας stack_top
zero <-- θέση μνήμης με τη μεγαλύτερη διεύθυνση


Μόλις τώρα η zero καλέσει την b η οποία χρησιμοποιεί τον αυτόματο πίνακα b={0,0,42,0,2}, η στοίβα θα γίνει έτσι:



0 <--Κορυφή της στοίβας stack_top
0
42
0
|--> |--> 2 <--Θέση της πρώην a.
| |--- αντίγραφό της p <--παράμετρος
| διάφορα άλλα χρήσιμα δεδομένα
|---------p
zero <-- θέση μνήμης με τη μεγαλύτερη διεύθυνση


Όπως φαίνεται εκεί που πριν υπήρχε η μεταβλητή a τώρα υπάρχει το 2. Έτσι η εντολή return &b[*n] θα επιστρέψει τη διεύθυνση του στοιχείου [2] του πίνακα. Έτσι η zero θα επιστρέψει 42:blink:...

Τα κατάφερα να σε μπερδέψω χειρότερα, ε???

Υγ. Με βελάκια φαίνεται που δείχνουν οι μεταβλητές pointers.

spiroscfu
22-09-11, 01:00
Σπύρο κι εγώ χαμηλού επιπέδου είμαι, πιο χαμηλού από εσένα... Αλλά θα προσπαθήσω να εξηγήσω λίγο πιο λιανά τον "γρίφο" μιας και είμαι νιφάλιος:biggrin:.
Τα κατάφερα να σε μπερδέψω χειρότερα, ε???


Μιχάλη σε ευχαριστώ πολύ για το χρόνο και τη διάθεση σου να με βοηθήσεις με αυτήν την μακροσκελή και κατανοητότατη απάντηση.


Υ.γ.
με αυτά που σου έχω σε bold σε κρατάω, τα τσούγκρισες πάλι ε!!!:biggrin:.

spiroscfu
22-09-11, 02:51
Τώρα που το ξαναείδα φυσικά και με την δικιά σου βοήθεια κατάλαβα και τον ειρμό του klik (τον παρεξήγησα πριν:biggrin:).