nik324 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 >typedef struct note{ void *data; struct note *next; }NODE; NODE *listCreate(void *data){ NODE *node; node=calloc(1,sizeof(NODE)); if (!node){return NULL;} node->data=data; node->next=NULL; return node; } NODE *insertNode(NODE *list, void *data){ NODE *newNode; newNode=listCreate(data); newNode->next=list; return newNode; } Εστω οτι εχω τα παραπανω.Προκυπτουν καποιες αποριες και θα ηθελα τα φωτα σας... 1) Τι σημασια εχει το * στην συναρτηση insertNode και listCreate και γιατι οι συναρτησεις ειναι τυπου NODE 2) Θα μπορουσα να προσθεσω κατι τετοιο και αν ναι τι διαφορα εχει; >typedef struct linked_list { NODE * first; NODE * last; } linked_list_t; 3)Aπο την στιμη που η listCreate περνει σαν ορισμα ενα Pointer τυπου void γιατι οταν καλειται η ιδια συναρτηση μεσα απο την insertNode στελνετε το data by value? Ευχαριστω πολυ...
nilosgr Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 1) ότι επιστρέφουν δείκτη, συγκεκριμένα η listInsert επιστρέφει την κεφαλή της λίστας, ενώ η listCreate επιστρέφει δείκτη στη θέση μνήμης του νέου κόμβου που δημιούργησε 2)ναι θα μπορούσες και θα σήμαινε ότι μάλλον θες να φτιάξεις μια ουρά (ή τουλάχιστον επειδή θες να ξέρεις και τον πρώτο, αλλά και τον τελευταίο κόμβο της λίστα χρησιμοποιείς guard-node) 3) επειδή όταν έχουμε σαν argument δείκτη (ή πίνακα -αν και είναι το ίδιο πρακτικά-) δενδημιουργείτε "αντίγραφο" της τιμής στο stack frame, αλλά περνάει η θέση που δείχνει και έτσι έχουμε πρόσβαση στην ίδια τη μεταβλητή. (γι αυτό δεν είμαι απόλυτα σίγουρος) Να ρωτήσω κι εγώ κάτι; ...μήπως δεν έπρεπε να έχεις για τίτλο "Απορίες σε λίστες", αλλά να είχες "εργασίες σε λίστες" εεε;
imitheos Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Να ρωτήσω κι εγώ κάτι; ...μήπως δεν έπρεπε να έχεις για τίτλο "Απορίες σε λίστες", αλλά να είχες "εργασίες σε λίστες" εεε; +1 Βλέποντας σε να ρωτάς "γιατί είναι τύπου NODE", τείνω να συμφωνήσω και εγώ με τον nilosgr. Οι ερωτήσεις σου δείχνουν ότι δεν διάβασες βασικά πράγματα. Μπορεί βέβαια το φόρουμ να μας έκανε καχύποπτους και μια και βαριέμαι ας απαντήσω και εγώ. >typedef struct note{ void *data; struct note *next; }NODE; NODE *listCreate(void *data){ NODE *node; node=calloc(1,sizeof(NODE)); if (!node){return NULL;} node->data=data; node->next=NULL; return node; } NODE *insertNode(NODE *list, void *data){ NODE *newNode; newNode=listCreate(data); newNode->next=list; return newNode; } 1) Τι σημασια εχει το * στην συναρτηση insertNode και listCreate και γιατι οι συναρτησεις ειναι τυπου NODE Η typedef, όπως λέει και το όνομά της, ορίζει τύπους ή αν θες aliases σε τύπους. Έτσι ορίζεται ένας "τύπος" με όνομα NODE ο οποίος δεν είναι τίποτα άλλο από ένα εύκολο συμβολικό όνομα για την δομή note. Οπουδήποτε το πρόγραμμα έχει NODE θα μπορούσε να έχει "struct note". Ο αστερίσκος σημαίνει ότι επιστρέφει δείκτη σε NODE. 2) Θα μπορουσα να προσθεσω κατι τετοιο και αν ναι τι διαφορα εχει; >typedef struct linked_list { NODE * first; NODE * last; } linked_list_t; Μπορείς να χρησιμοποιήσεις ό,τι θέλεις. Ανάλογα με τη δουλειά που θέλουμε να κάνουμε υπάρχουν καλύτερες επιλογές και χειρότερες. Η διαφορά σε αυτή τη "δομή" είναι ότι ξέρεις τον πρώτο και τον τελευταίο κόμβο της λίστας. Επίσης θα μπορούσες μέσα στη note να παρέχεις και τον προηγούμενο κόμβο αντί για μόνο τον επόμενο και 1002 άλλες παραλλαγές. Όλα εξαρτώνται από το τι θέλεις να κάνεις. 3)Aπο την στιμη που η listCreate περνει σαν ορισμα ενα Pointer τυπου void γιατι οταν καλειται η ιδια συναρτηση μεσα απο την insertNode στελνετε το data by value? Καταρχήν, όπου μπορείς απόφυγε τις λέξεις "by value" και "by reference" γιατί σε μπερδεύουν. Ειδικά η "by reference" δεν θα έπρεπε καν να χρησιμοποιείται όταν μιλάμε για C. Ας έρθουμε τώρα στο void*. Ένας δείκτης σε void ορίζεται από το πρότυπο ότι μπορεί να μετατραπεί από και σε οποιονδήποτε άλλο. Τι μας χρησιμεύει αυτό ? Μπορείς σε ένα μικρό βαθμό να γράψεις γενικές δομές που να δουλεύουν με πολλούς τύπους. Μπορείς για παράδειγμα σε αυτό το πρόγραμμα να έχεις int για "data" και σε ένα άλλο να έχεις float ή οτιδήποτε άλλο χωρίς να χρειάζεται να έχεις 2 δομές. Όταν λες "by value" υποθέτω εννοείς "node->data=data", σωστά ? Ένας δείκτης είναι και αυτός μια απλή μεταβλητή όπως όλες οι άλλες. > int k; k = 5; Στο παραπάνω κώδικα, δεσμεύεται μνήμη για ένα int και μετά γράφουμε σε αυτή τη διεύθυνση την τιμή 5. Το ίδιο ακριβώς γίνεται και σε ένα δείκτη. Δεσμεύεται μνήμη όσο χρειάζεται για ένα δείκτη και μετά γράφεις εκεί μια τιμή η οποία όμως σε αυτή την περίπτωση είναι μια διεύθυνση μνήμης αλλά δεν έχει μεγάλη διαφορά από το παραπάνω 5. Στο δικό σου κώδικα, όταν τρέχεις την calloc δεσμεύεται μνήμη για την δομή οπότε και για το μέλος data. Έπειτα απλά του γράφεις την τιμή που θέλεις και είναι η τιμή στην οποία δείχνει η data που πέρασες στην συνάρτηση. Για αυτό το λόγο το κάνεις έτσι "by value" όπως είπες. > address of data is 0xa947478 data points to 0xa9474a4 address calloced for node.data is 0x1480010 node->data points to 0xa9474a4 Άλλαξα την listCreate ώστε να τυπώνει κάποιες διευθύνσεις. Όπως βλέπεις, ο void δείκτης data που περνάς στη συνάρτηση έχει διεύθυνση την a947478 δηλαδή εκεί του έχει δεσμευθεί μνήμη. Η τιμή του (δηλαδή εκεί που δείχνει) είναι το 4a4. Όταν τρέχεις την calloc, δεσμεύεται η διεύθυνση 1480010 για το πεδίο της δομής και σε αυτή τη διεύθυνση αντιγράφεται η "τιμή" a9474a4 δηλαδή εκεί που έδειχνε αυτό που πέρασες. Όπως ακριβώς δηλαδή όταν περνάς μια απλή μεταβλητή τύπου int σε μια συνάρτηση, δημιουργείται ένα νέο "αντικείμενο" με την ίδια τιμή, το ίδιο ακριβώς γίνεται και με το δείκτη. Αυτό που σε ενδιαφέρει και στις 2 περιπτώσεις είναι η "τιμή" της μεταβλητής.
migf1 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Ο imitheos έδωσε μια κατατοπιστική απάντηση, επειδή όμως δεν ξέρουμε το γνωσικό σου επίπεδο και άρα τι σου είναι κατανοητό και τι όχι, καθώς επίσης κι επειδή είναι αρκετά αυτά που χρειάζεται να γνωρίζει κανείς πριν φτάσει στις λίστες (τόσα ώστε να μην είναι βολικό να γράφονται συνέχεια) στην υπογραφή μου θα βρεις ένα link στο οποίο επιχειρώ να εξηγήσω με όσο πιο απλά λόγια μπορώ τους δείκτες, τα c-strings και τις απλά συνδεδεμένες λίστες, έχοντας και παραδείγματα με κώδικα. Ίσως να σε βοηθήσουν, σε συνδυασμό με το βιβλίο σου. Σίγουρα πάντως καλύπτουν όλα όσα ρωτάς στο αρχικό ποστ. Μια ακόμα επισήμανση στην προτροπή του imitheoy να μη χρησιμοποιείται καν ο όρος "by reference" στη C. Τεχνικά είναι σωστή η παρατήρησή του, διότι στην C όλα τα ορίσματα περνιούνται "by value", ακόμα και οι δείκτες (by reference δεικτών το προσομοιώνουμε με διπλό δείκτη). Θα ήταν λοιπόν πιο σωστό κάτι σαν "simulated call/pass by reference". Όμως δεν είναι καθόλου βολικό να συνεννοείται κανείς με τους υπόλοιπους έτσι σε every-day use "προσομοιωμένη κλήση/πέρασμα αναφοράς". Στις σημειώσεις μου, στο link που σου πρότεινα, το εξηγώ μια φορά ότι στη C ο όρος χρησιμοποιείται ως προσομοίωση του ίδιου όρου (ή συναφών) σε άλλες γλώσσες (όπως π.χ. στο JDBC API της Java και στην Pascal με τα keywords inout και var, αντίστοιχα), κι από εκεί και πέρα τον χρησιμοποιώ σκέτο (αν και τις περισσότερες φορές ισχύει το αντίθετο, δηλαδή στις άλλες γλώσσες το by reference συνήθως υλοποιείται με δείκτες εσωτερικά). Προσωπικά δεν θα σου πρότεινα να τον αποφεύγεις, αρκεί να γνωρίζεις πως στη C ως ορολογία δεν αντιστοιχεί επακριβώς με την αντίστοιχη ορολογία άλλων γλωσσών.
nik324 Δημοσ. 10 Ιουλίου 2012 Μέλος Δημοσ. 10 Ιουλίου 2012 Να ρωτήσω κι εγώ κάτι; ...μήπως δεν έπρεπε να έχεις για τίτλο "Απορίες σε λίστες", αλλά να είχες "εργασίες σε λίστες" εεε; Οχι απορίες ειναι...Ετσι και αλλιως τετοια εποχη τι εργασιες να υπαρχουν;; Ευχαριστω για τις απαντησεις σας θα επανελθω και με αλλες αποριες ή "εργασιες" αν το θελετε ετσι...
Timonkaipumpa Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 [....] nik324 Το θέμα με τις λίστες είναι ότι χρησιμοποιείς κάποιες περιοχές μνήμης στις οποίες θες να έχεις πρόσβαση και να αλλάζεις, εάν χρειαστεί, ό,τι τιμές περιέχουν. Δηλαδή, όταν φτιάξεις μία λίστα, και εάν υποθέσουμε ότι έχεις ένα struct που έχει τους δείκτες listHead (ή listStart ) και listTail (ή listEnd/listLastNode) αλλά και για τον πρώτο κόμβο, θα γίνουν οι εξής διαδικασίες: α) Θα δεσμεύσεις ένα χώρο στην μνήμη για τον πρώτο κόμβο β) Θα καταχωρήσεις τιμές για τον κόμβο αυτό γ) Θα πας στον χώρο που έχεις δεσμεύσει για τον listHandler (ο κόμβος με τα listHead και listTail) και θα βάλεις το listStart/listHead (και το listTail/listEnd, εάν είναι ο πρώτος κόμβος) να δείχνει στον χώρο που δέσμευσες Τώρα, στην συνάρτηση που θα τα κάνει αυτά, θες να μπορείς να πειράξεις τις πραγματικές τιμές στους κόμβους και όχι κάποια αντίγραφα που δημιουργούνται μέσα στις συναρτήσεις. Έτσι, εάν περάσεις σε μία τέτοια συνάρτηση, π.χ., τον listHandler, για να πλοηγηθείς σε κάποιο κόμβο... θα πάρεις ένα αντίγραφο και όχι τον "πραγματικό" listHandler. Εάν όμως, περάσεις μία μεταβλητή που να έχει την διεύθυνση μνήμης που υπάρχει κάτι... τότε αν και θα δημιουργηθεί αντίγραφο μέσα στην συνάρτηση... αυτό θα έχει μία διεύθυνση στην οποία θα μπορείς να πας και να κάνεις ό,τι θες. Αυτός είναι και ο λόγος που περνάς ορίσματα σαν δείκτες. Για να μπορείς να πας εκεί και να τα επεξεργαστείς αυτά και όχι κάποια αντίγραφά τους. Τώρα.. σχετικά με την τελευταία ερώτησή σου.. Εν γένει... υπάρχει μία δομή από κόμβους που χρησιμοποιείται στους Η/Υ. Αναλόγως το πώς συνδέονται οι κόμβοι, δίνονται και άλλα ονόματα στην δομή. Π.χ., εάν κάθε κόμβος δείχνει στον προηγούμενο μόνο... δηλαδή: > typedef struct aGeneralNode { struct aGeneralNode* previous; int theData; }GeneralNode; τότε δεν μπορείς να αρχίσεις από τον πρώτο, γιατί δεν δείχνει πουθενά και άρα δεν ξέρεις που είναι ο δεύτερος, και η δομή αυτή μπορεί να χρησιμοποιηθεί μόνο αρχίζοντας από τον τελευταίο... ο οποίος δείχνει στον προηγούμενο κ.ο.κ. Αυτή η δομή λέγεται στοίβα. Εάν αλλάξουμε το που δείχνει ο δείκτης... και δείχνει στον επόμενο, > typedef struct aGeneralNode { struct aGeneralNode* next; int theData; }GeneralNode; τότε αυτή η δομή δεν μπορεί να χρησιμοποιηθεί από τον τελευταίο κόμβο, γιατί δεν δείχνει πουθενά, και λέγεται ουρά. Τώρα.. Για ευκολία, μπορείς να χρησιμοποιήσεις ένα ακόμα κόμβο, ο οποίος να δείχνει στο πρώτο, προς χρήση, στοιχείο της δομής που έχεις. Π.χ. > typedef struct nodeHandler{ GeneralNode* theStart; }NodeHandler; Η διαφορά μίας απλής λίστας από μία ουρά και μία στοίβα... είναι οι παρεχόμενες συναρτήσεις. Έτσι, σε μία στοίβα, μπορείς να βάλεις μόνο από πάνω κόμβους ενώ σε μία λίστα να βάλεις και ενδιάμεσα. Επειδή όμως, οι στοίβες και οι ουρές, συνήθως, δεν χρησιμοποιούνται για καταστάσεις που θες να παρεμβάλεις ενδιάμεσα κόμβους... όταν έχεις λίστα, που άρα θες να παρεμβάλεις ενδιάμεσα κόμβους, βολεύει να έχεις την δυνατότητα να πλοηγείσαι από την αρχή προς το τέλος αλλά και από το τέλος προς την αρχή. Αυτό μπορεί να γίνει εύκολα προσθέτοντας έναν ακόμα δείκτη: > typedef struct aGeneralNode { struct aGeneralNode* next; struct aGeneralNode* previous; int theData; }GeneralNode; Και για ευκολία διαχείρισης: > typedef struct nodeHandler{ GeneralNode* theStart; GeneralNode* theEnd; }NodeHandler; Οπότε, μπορείς να πας στο τέλος και ψάξεις από την αρχή... ή στην αρχή και να ψάξεις προς το τέλος. Στην ουσία... τα πάντα είναι structs που δείχνουν σε κάποια άλλα. Εάν υπάρχουν κανόνες στο που δείχνουν, θα μπορούσαμε να μιλάμε για δένδρα. Εάν δείχνουν μόνο προς μία κατεύθυνση... θα μπορούσαμε να μιλάμε για ουρές, στοίβες ή απλές λίστες... Όλα όμως αφορούν διευθύνσεις μνήμης οι οποίες έχουν ένα struct το οποίο κρατάει μία αναφορά/δείκτη για κάποια άλλα συν τα δεδομένα του. Το με ποια άλλα structs συνδέεται και τι συναρτήσεις για να διατρέξεις την δομή, να προσθέσεις κόμβους ή να οργανώσεις την δομή σου είναι που αλλάζει το όνομα της δομής. Όμως, τα πάντα είναι περιοχές μνήμης οι οποίες κρατάνε δεδομένα συν ένα δείκτη για μία άλλη περιοχή μνήμης.
defacer Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Αυτή η δομή λέγεται στοίβα. Παρακαλούνται οι κ.κ. stack και heap να διαλέξουν διαφορετικά ονόματα για να μη μπερδευόμαστε... Αλήθεια πως το λένε το heap στα ελληνικά; Ποτέ μου δεν κατάλαβα για ποιό λόγο φοράμε ελληνικές λέξεις πάνω σε ξενόφερτους τεχνικούς όρους. Μόλις συνειδητοποίησα ας πούμε ότι το tuple το λένε "πλειάδα". :eek:
Timonkaipumpa Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Σόρος..ε... Μπερδεύτηκα με το ΔΝΤ.. Σωρός (θαρρώ).
defacer Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Δηλαδή όταν κάποιος λέει "έχω ένα σωρό αριθμούς και θέλω να τους ταξινομήσω" τι του απαντάς;
Timonkaipumpa Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Δηλαδή όταν κάποιος λέει "έχω ένα σωρό αριθμούς και θέλω να τους ταξινομήσω" τι του απαντάς; Του λες, "βρες τα με τον Σόρος"
imitheos Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Δηλαδή όταν κάποιος λέει "έχω ένα σωρό αριθμούς και θέλω να τους ταξινομήσω" τι του απαντάς; Για αυτές τις δουλειές βγήκε το κάρο (καθώς και μεγαλύτερα όπως φορτηγό, τριαξονικό, επικαθήμενο, κτλ) Του λες να χρησιμοποιεί "έχω ένα κάρο αριθμούς" και δεν υπάρχει σύγχυση.
defacer Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 Για αυτές τις δουλειές βγήκε το κάρο (καθώς και μεγαλύτερα όπως φορτηγό, τριαξονικό, επικαθήμενο, κτλ) Του λες να χρησιμοποιεί "έχω ένα κάρο αριθμούς" και δεν υπάρχει σύγχυση. Δε μου αρέσει το κάρο γιατί δεν είναι ακριβής έκφραση. Προτιμώ "ένα σκασμό" γιατί έτσι φαίνεται ξεκάθαρα ότι έχεις παραπάνω απ' όσους θα ήθελες.
migf1 Δημοσ. 10 Ιουλίου 2012 Δημοσ. 10 Ιουλίου 2012 (επεξεργασμένο) >typedef struct note{ void *data; struct note *next; }NODE; NODE *listCreate(void *data){ NODE *node; node=calloc(1,sizeof(NODE)); if (!node){return NULL;} node->data=data; node->next=NULL; return node; } NODE *insertNode(NODE *list, void *data){ NODE *newNode; newNode=listCreate(data); newNode->next=list; return newNode; } Εστω οτι εχω τα παραπανω.Προκυπτουν καποιες αποριες και θα ηθελα τα φωτα σας... 1) Τι σημασια εχει το * στην συναρτηση insertNode και listCreate και γιατι οι συναρτησεις ειναι τυπου NODE 2) Θα μπορουσα να προσθεσω κατι τετοιο και αν ναι τι διαφορα εχει; >typedef struct linked_list { NODE * first; NODE * last; } linked_list_t; 3)Aπο την στιμη που η listCreate περνει σαν ορισμα ενα Pointer τυπου void γιατι οταν καλειται η ιδια συναρτηση μεσα απο την insertNode στελνετε το data by value? Ευχαριστω πολυ... Ξαναδιαβάζοντας το αρχικό σου πόστ (το έχω σε παράθεση) διαπιστώνω πως το λινκ που σου υπέδειξα δεν καλύπτει όλες σου τις ερωτήσεις, όπως υποστήριξα αρχικά. Συγκεκριμένα δεν καλύπτει την 1η ερώτηση, η οποία έχει προεκτάσεις στο λεγόμενο generic programming ή abstract data types (ADT) και στο οποίο ήδη αναφέρθηκαν επί τροχάδην κάποια παιδιά. Το βασικό ζητούμενο είναι σε πιο υψηλό επίπεδο να απελευθερώσεις τα data types σου από την εξάρτηση με συγκεκριμένους τύπους δεδομένων, τους οποίους τους διαχειρίζεσαι privately σε πιο χαμηλό επίπεδο. Για παράδειγμα, στον κώδικα που παραθέτεις λείπει αυτή η explicit υλοποίηση του τύπου των data σου, με αποτέλεσμα έτσι όπως είναι τώρα να μην μπορείς να τυπώσεις την τιμή κανενός από τα data σου (αν το επιχειρήσεις ο compiler θα σου παραπονεθεί πως προσπαθείς να κάνεις dereference έναν void pointer... πράγμα που δεν γίνεται). Για να σου δουλέψει πρέπει να κάνεις χειροκίνητα alloc το data που περνάς στην Insert(), δίνοντας δηλαδή explicitly το data type του, και κατόπιν να κάνεις και πάλι explicitly cast σε αυτόν τον τύπο στη συνάρτηση που τυπώνει τα nodes της λίστας σου. Για παράδειγμα... > ... int main( void ) { NODE *list = NULL; int *intdata = calloc(1, sizeof(int) ); if ( NULL == (list=insertNode(list, intdata)) ) { // handle error here } else printf( "%d\n", *(int *)(list->data) ); ... } ΥΓ. Δεν είμαι σε θέση να γνωρίζω τι ακριβώς ψάχνεις, αλλά βεβαιώσου πως είσαι εξοικειωμένος με δείκτες πριν αρχίσεις να καταπιάνεσαι με λίστες, και πολύ περισσότερο με (void *) EDIT: Αλλαγή του list->node.data σε list->data για να είναι συνεπές με τον ορισμό του NODE. Επεξ/σία 10 Ιουλίου 2012 από migf1
nik324 Δημοσ. 10 Ιουλίου 2012 Μέλος Δημοσ. 10 Ιουλίου 2012 Ξαναδιαβάζοντας το αρχικό σου πόστ (το έχω σε παράθεση) διαπιστώνω πως το λινκ που σου υπέδειξα δεν καλύπτει όλες σου τις ερωτήσεις, όπως υποστήριξα αρχικά. Συγκεκριμένα δεν καλύπτει την 1η ερώτηση, η οποία έχει προεκτάσεις στο λεγόμενο generic programming ή abstract data types (ADT) και στο οποίο ήδη αναφέρθηκαν επί τροχάδην κάποια παιδιά. Το βασικό ζητούμενο είναι σε πιο υψηλό επίπεδο να απελευθερώσεις τα data types σου από την εξάρτηση με συγκεκριμένους τύπους δεδομένων, τους οποίους τους διαχειρίζεσαι privately σε πιο χαμηλό επίπεδο. Για παράδειγμα, στον κώδικα που παραθέτεις λείπει αυτή η explicit υλοποίηση του τύπου των data σου, με αποτέλεσμα έτσι όπως είναι τώρα να μην μπορείς να τυπώσεις την τιμή κανενός από τα data σου (αν το επιχειρήσεις ο compiler θα σου παραπονεθεί πως προσπαθείς να κάνεις dereference έναν void pointer... πράγμα που δεν γίνεται). Για να σου δουλέψει πρέπει να κάνεις χειροκίνητα alloc το data που περνάς στην Insert(), δίνοντας δηλαδή explicitly το data type του, και κατόπιν να κάνεις και πάλι explicitly cast σε αυτόν τον τύπο στη συνάρτηση που τυπώνει τα nodes της λίστας σου. Για παράδειγμα... > ... int main( void ) { NODE *list = NULL; int *intdata = calloc(1, sizeof(int) ); if ( NULL == (list=insertNode(list, intdata)) ) { // handle error here } else printf( "%d\n", *(int *)(list->data) ); ... } ΥΓ. Δεν είμαι σε θέση να γνωρίζω τι ακριβώς ψάχνεις, αλλά βεβαιώσου πως είσαι εξοικειωμένος με δείκτες πριν αρχίσεις να καταπιάνεσαι με λίστες, και πολύ περισσότερο με (void *) EDIT: Αλλαγή του list->node.data σε list->data για να είναι συνεπές με τον ορισμό του NODE. φιλε migf1 σε ευχαριστω πολυ για την αναλυτικη απαντηση σου
migf1 Δημοσ. 11 Ιουλίου 2012 Δημοσ. 11 Ιουλίου 2012 φιλε migf1 σε ευχαριστω πολυ για την αναλυτικη απαντηση σου Να 'σαι καλά φίλε nik324 Να συμπληρώσω κάτι και για την 3η σου ερώτηση, παρόλο που ήδη την απάντησαν κι άλλα παιδιά (o nilosgr νομίζω). Όταν ορίζουμε έναν δείκτη, τότε αν τον περάσουμε ως όρισμα σε μια συνάρτηση είναι σαν να περνάμε by reference το περιεχόμενο του δείκτη. Δηλαδή... > ... void foo( int *pi ) { (*pi)++; } ... int main(void) { int *pInt = calloc( 1, sizeof(int) ); // δημιουργία δείκτη σε ακέραιο περιεχόμενο με αρχική τιμή 0 if (NULL == pInt) { // handle error } else { foo( pInt ); } ... } Το παραπάνω είναι σαν να έχεις μια int μεταβλητή με αρχική τιμή 0, την οποία την περνάς by-ref στην foo() που της αυξάνει την τιμή κατά 1. Θα μπορούσες δηλαδή να το γράψεις και κάπως έτσι... > ... void foo( int *pi ) { (*pi)++; } int main(void) { int integer = 0 foo( &integer ); ... } ή ακόμα κι έτσι... > void foo( int *pi ) { (*pi)++; } int main(void) { int integer = 0; int *pInt = &integer; foo( pInt ); ... } Τώρα, αν περάσεις σε μια συνάρτηση τη διεύθυνση ενός δείκτης (δλδ το &pInt στα παραπάνω παραδείγματα) τότε είναι σαν να περνάς by-ref τον ίδιο τον δείκτη (και όχι δλδ το περιεχόμενό του). Σε αυτή την περίπτωση θα πρέπει να τροποποιήσεις και τον κώδικα της foo() ώστε να περιμένει και να διαχειρίζεται δείκτη σε δείκτη, δηλαδή... > void foo( int **ppi ) { (*(*ppi))++; } και να αλλάξει και η κλήση της foo() στην main().. > int main( void ) { int integer = 0; int *pInt = &integer; foo( &pInt ); ... } Όταν βρεις χρόνο, ρίξε μια ματιά στις σημειώσεις μου. Το εξηγώ με πιο χρήσιμα παραδείγματα στις απλά συνδεδεμένες λίστες.
Προτεινόμενες αναρτήσεις
Δημιουργήστε ένα λογαριασμό ή συνδεθείτε για να σχολιάσετε
Πρέπει να είστε μέλος για να αφήσετε σχόλιο
Δημιουργία λογαριασμού
Εγγραφείτε με νέο λογαριασμό στην κοινότητα μας. Είναι πανεύκολο!
Δημιουργία νέου λογαριασμούΣύνδεση
Έχετε ήδη λογαριασμό; Συνδεθείτε εδώ.
Συνδεθείτε τώρα