Star_Light Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Εκ παραδρομής. Καταλαβαίνεις πιστεύω ότι το πρόγραμμα είναι τόσο απλό που δεν χρειάζεται ούτε μία global (και βέβαια "δε θα έπρεπε" να έχει ούτε μία αφού δε χρειάζεται). Μια local struct μέσα στη main θα ήταν αρκετή. Oκ ρε συ... αλλα δεν εχει μπει ακομη στις δομες... οποτε το υλοποιει ετσι.
defacer Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Oκ ρε συ... αλλα δεν εχει μπει ακομη στις δομες... οποτε το υλοποιει ετσι. Ότι ο King έχει κάποιο λόγο που το κάνει έτσι μπορώ να το φανταστώ (δεν έχω το βιβλίο). Για σένα το λέω επειδή ξέρω ότι ξέρεις αρκετά για να το καταλάβεις και επειδή το προηγούμενο σχόλιό σου με τις globals μου λέει ότι θα σε ωφελούσαν κάποια pointers (όχι της C, τα άλλα).
Star_Light Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Ότι ο King έχει κάποιο λόγο που το κάνει έτσι μπορώ να το φανταστώ (δεν έχω το βιβλίο). Για σένα το λέω επειδή ξέρω ότι ξέρεις αρκετά για να το καταλάβεις και επειδή το προηγούμενο σχόλιό σου με τις globals μου λέει ότι θα σε ωφελούσαν κάποια pointers (όχι της C, τα άλλα). Δεν ειμαι σιγουρος αν σε πιανω 100% :-/ καταλαβαινω πανω - κατω τα μειονεκτηματα των globals. Εδω πχ αν δεν δηλωνε τους πίνακες num_in_rank & num_in_suit σαν global δεν θα μπορουσε να κρατήσει τις κάρτες πχ ιδιου χρώματος για την συνάρτηση analyze_hand() μετα... δεν θα δουλευε δηλαδη το προγραμμα. Δεδομενου οτι δεν περνάει στην κληση της συναρτησης τιποτα και αρα δεν διατηρουνται οι καποιες αλλαγες στους πινακες εκτος συναρτησης. Τις άλλες που ειναι ακεραιες απλα δεν καιγεται και αρα το αποφευγει επειδη ειπαμε ειναι κακο
defacer Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Δεν ειμαι σιγουρος αν σε πιανω 100% :-/ καταλαβαινω πανω - κατω τα μειονεκτηματα των globals. Εδω πχ αν δεν δηλωνε τους πίνακες num_in_rank & num_in_suit σαν global δεν θα μπορουσε να κρατήσει τις κάρτες πχ ιδιου χρώματος για την συνάρτηση analyze_hand() μετα... δεν θα δουλευε δηλαδη το προγραμμα. Δεδομενου οτι δεν περνάει στην κληση της συναρτησης τιποτα και αρα δεν διατηρουνται οι καποιες αλλαγες στους πινακες εκτος συναρτησης. Τις άλλες που ειναι ακεραιες απλα δεν καιγεται και αρα το αποφευγει επειδη ειπαμε ειναι κακο Θα έπρεπε να γίνεται μέσω παραμέτρων στις κλήσεις των συναρτήσεων. Επειδή οι παράμετροι θα είναι πολλές αν έμπαιναν μία μία θα ήταν σκέτη κούραση και θα αποσπούσε την προσοχή του αναγνώστη από τα σημαντικότερα πράγματα. Επομένως θα έπρεπε να γίνει με struct αλλά όπως λες δεν έχει μιλήσει ακόμα για structs. Εσύ όμως μπορείς να κάνεις αλλαγές στο πρόγραμμα για να δουλεύει χωρίς globals.
Star_Light Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Εσύ όμως μπορείς να κάνεις αλλαγές στο πρόγραμμα για να δουλεύει χωρίς globals. Nαι φυσικά και μπορω. Τωρα θα στο έκανα EDIT αλλα με προλαβες θα περάσω τους 2 πίνακες σαν ορισματα στις 2 συναρτήσεις που τους χρησιμοποιουν και οι αλλαγες που θα συμβουν στην μια συνάρτηση θα ειναι μονιμες στην αλλη . Μέσα στην main() θα έχουμε κατι τετοιο : > int main(void) { int num_in_rank[NUM_RANKS] , num_in_suit[NUM_SUITS]; for (; { read_cards(num_in_rank , num_in_suit); analyze_hand(num_in_rank , num_in_suit); print_result(); } } Θα αλλαξουμε φυσικα και τα πρωτοτυπα στην αρχη για να μην αρχισει να τσιναει ο comp... > void read_cards(int [] , int[]); void analyze_hand(int [] , int []); Kαι στις δηλώσεις... > void read_cards(int num_in_rank[] , int num_in_suit[]) { ..... bla bla } // void analyze_hand(int num_in_rank[] , int num_in_suit[]) { .... bla bla } Αυτο δεν εννοεις και εσυ???? Οποτε ή θα συμφωνήσουμε ή θα σου δώσω και εγω έναν έξτρα τροπο
Re4cTiV3 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 παιδιά αν έχω αυτά τα structs πως μπορώ να έχω πρόσβαση; > typedef struct V { int length; struct V *next; struct E *to; }V; typedef struct E { int height; int width; }E; Αφού κάνω malloc( list = (V*)malloc(sizeof(V)); ) μετά; > list->length = 21; list->to.height = 23; list->to.width = 22; ;;;
migf1 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 παιδιά αν έχω αυτά τα structs πως μπορώ να έχω πρόσβαση; > typedef struct V { int length; struct V *next; struct E *to; }V; typedef struct E { int height; int width; }E; Αφού κάνω malloc( list = (V*)malloc(sizeof(V)); ) μετά; > list->length = 21; list->to.height = 23; list->to.width = 22; ;;; Αυτό θα δώσει seg-fault, γιατί προσπαθείς να περάσεις τιμές σε πεδία του to χωρίς να το έχεις κάνει malloc(). Το αρχικό malloc() που κάνεις στο V φτιάχνει χώρο για 2 δείκτες (τους to και next). Για τον next είσαι οκ γιατί απλά θα τον βάλεις με ανάθεση να δείχνει στον επόμενο κόμβο (που θα είναι ήδη malloced υποθέτω, από τη συνάρτηση εισαγωγής κόμβου στη λίστα σου) αλλά για να μπορέσεις να περάσεις τιμές στο πεδίο to πρέπει πρώτα να το κάνεις malloc ξεχωριστά... > list = malloc( sizeof(V) ); list->to = malloc( sizeof(E) ); τώρα μπορείς να αναθέσεις τιμές στα πεδία height και width του to... > list->to->height = 23; list->to->width = 22; Και πρέπει να μεριμνήσεις εξίσου όταν κάνεις free()
migf1 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 τότε εδώ γιατί δεν κάναμε δυο malloc; Εννοείς τον *token υποθέτω. Κι εκεί χρειάζεται, εκτός αν υπάρχει ήδη έτοιμο κάποιο άλλο string (malloced ή μη) στο οποίο θα βάλεις να δείχνει o token. Αν όμως θες να περάσεις απευθείας ένα string στον token πρέπει να τον κάνεις malloc πρώτα.
Re4cTiV3 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Όχι για το token.Αναφέρομαι για την απάντηση σου εδώ.
defacer Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Αυτο δεν εννοεις και εσυ???? Δεν θα συνιστούσα να περάσεις τους πίνακες σαν ορίσματα, θα σε βάλει σε λάθος τρόπο σκέψης αυτό και θα έχεις μετά μια κακή συνήθεια να ξεμάθεις αν ασχοληθείς με C++. Πέρνα τους σαν pointers στο πρώτο στοιχείο. Επίσης εννοείται πως πάντα πρέπει να περνάς και το μέγεθος του κάθε πίνακα, αν και στο συγκεκριμένο παράδειγμα τα πράγματα είναι πάρα πολύ απλά και μπορείς να χρησιμοποιήσεις τις NUM_RANKS και NUM_SUITS κατευθείαν (μη σου γίνει συνήθεια όμως -- στη συγκεκριμένη οι functions θα χρησιμοποιηθούν με ένα μόνο τρόπο, αλλά γενικά αν το κάνεις αυτό θα καταλήξεις με κώδικα που δεν είναι reusable). Και τέλος, βάλτα όλα σε ένα struct και πέρνα ένα pointer σ' αυτό σαν παράμετρο: >struct poker_hand { int num_in_rank[NUM_RANKS]; int num_in_suit[NUM_SUITS]; }; Aν οι πίνακες δεν ήταν fixed size το struct θα είχε ως εξής: > struct poker_hand { int* num_in_rank; int* num_in_suit; int num_ranks; int num_suits; }; Αυτό βέβαια σημαίνει πως πλέον ένα poker_hand πρέπει να αρχικοποιηθεί, οπότε θα σου χρειαζόταν και δυο έξτρα constructor/destructor συναρτήσεις: >void poker_hand_init(struct poker_hand* ph); // κάνει malloc τους πίνακες και set τους int void poker_hand_destroy(struct poker_hand* ph); // free τους πίνακες, set σε null και τους int σε 0 Και τελικά θα γινόταν έτσι: >int main(void) { struct poker_hand hand; poker_hand_init(&hand); for (; { read_cards(hand); analyze_hand(hand); print_result(); } poker_hand_destroy(&hand); } Αυτά με το hand. Κάνε και το αντίστοιχο με το struct poker_hand_analysis.
migf1 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Όχι για το token.Αναφέρομαι για την απάντηση σου εδώ. Εκεί δεν βλέπω καθόλου τον token. Δεν θυμάμαι τώρα τη ροή των απαντήσεων (πρέπει να κάτσω να τα διαβάσω όλα από την αρχή, και βαριέμαι για να είμαι ειλικρινής) αλλά είδα πως π.χ. εδώ: http://www.insomnia.gr/topic/448292-struct-%ce%ba%ce%b1%ce%b9-stack/page__view__findpost__p__4780834 το extra malloc() για τον token γίνεται μέσω της strdup() στην συνθήκη του if.
Re4cTiV3 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Το char *token το είχαμε βγάλει απέξω! Σε αυτόν τον κώδικά αν κάνουμε malloc > typedef struct Datum { int value; float coefficient; }Datum; typedef struct node { Datum datum; struct node *back; }Node; δεν πρέπει να κάνουμε δυο malloc?ή επειδή μέσα έχει ήδη δυο δείκτες κάνουμε ένα malloc? Αν στο datum είχα ένα πεδίο Datum *next; θα έπρεπε να κάνω δεύτερο malloc?
migf1 Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 @Starlight: Εγώ πάλι αντίθετα με τον defacer δεν θα σε απέτρεπα ούτε από το να περνάς τους πίνακες ως ορίσματα (έτσι κι αλλιώς στη C το πέρασμα ισοδυναμεί αυτόματα με δείκτη στο 1ο στοιχείο τους) ούτε από το να μην περνάς και το μήκος τους ως όρισμα. Από τη στιγμή που μιλάμε για fixed-size πίνακες, μπορείς να μην περνάς το μέγεθός τους και να χρησιμοποιείς απευθείας μέσα στην συνάρτηση το #define που αντιστοιχεί στο μήκος τους. Δηλαδή... > #define MAX_ELEMS 100 ... void foo( int arr[] ) { for (int i=0; i < MAX_ELEMS; i++) ... } ... int main( void ) { int arr[ MAX_ELEMS ] = {0}; foo( arr ); ... } versus... > void foo( int arr[], int maxelems ) { for (int i=0; i < maxelems; i++) ... } int main( void ) { int arr[100] = {0}; foo( arr, 100 ); ... } ή versus... > #define MAX_ELEMS 100 ... void foo( int arr[], int maxelems ) { for (int i=0; i < maxelems; i++) ... } int main( void ) { int arr[ MAX_ELEMS ] = {0}; foo( arr, MAX_ELEMS ); ... } Υπάρχουν + και - και στον 1ο και στον 3ο τρόπο, ενώ ο 2ος καλό είναι να αποφεύγεται, λόγω του magic-numner 100 (δες παρακάτω). Π.χ. με τον 3ο τρόπο μπορείς μέσα στην συνάρτηση να ελέγξεις στο runtime την τιμή του maxelems να μην ξεπερνάει το MAX_ELEMS είτε απευθείας είτε με ένα έξτρα validation macro... > #define MAX_ELEMS 100 #define VALID_LEN(len) ( (len) > -1 && (len) < MAX_ELEMS ) ... int foo( int arr[], int maxelems ) { if ( !VALID_LEN(maxelems) ) // handle error } ή... int foo( int arr[], int maxelems ) { if ( maxelems < 0 || maxelems > MAX_ELEMS-1 ) // handle error } κάτι που με τον 1ο τρόπο μπορείς να πετύχεις απευθείας με το macro, ενώ στον 2ο τρόπο υποχρεωτικά πρέπει να χρησιμοποιήσεις το magic-number 100 (not good) το οποίο κιόλας σε περίπτωση αλλαγής του θα πρέπει να το κάνεις track-down σε όλο σου τον κώδικα για να το αλλάξεις (not good either). Από τη στιγμή που μιλάμε για fixed-size πίνακα, ο πιο λιτός και λειτουργικός τρόπος είναι ο 1ος τρόπος, χωρίς να μειονεκτεί σε τίποτα από τον 3ο. Και ο 3ος είναι θεμιτός τρόπος όμως, απλώς πιο περιφραστικός. Οπότε η δική μου προτροπή είναι να χρησιμοποιείς όποιον σε βολεύει καλύτερα μεταξύ του 1ου και του 3ου. Το char *token το είχαμε βγάλει απέξω! Σε αυτόν τον κώδικά αν κάνουμε malloc > typedef struct Datum { int value; float coefficient; }Datum; typedef struct node { Datum datum; struct node *back; }Node; δεν πρέπει να κάνουμε δυο malloc?ή επειδή μέσα έχει ήδη δυο δείκτες κάνουμε ένα malloc? Αν στο datum είχα ένα πεδίο Datum *next; θα έπρεπε να κάνω δεύτερο malloc? Ναι! Ξεχωριστά malloc() κάνεις σε όλα τα πεδία δείκτες που σκοπεύεις να τα γεμίσεις ας το πούμε χειροκίνητα (όπως π.χ. το *datum) αντί απλά να τα βάλεις να δείχνουν σε ήδη υπάρχον περιεχόμενο (όπως π.χ. το *back). Στο απόσπασμα που παραθέτεις δεν χρειάζεται ξεχωριστό malloc για κανένα πεδίο, γιατί το μόνο πεδίο που είναι δείκτης είναι το *back το οποίο δεν το γεμίζεις χειροκίνητα αλλά το βάζεις να δείχνει σε ήδη υπάρχον περιεχόμενο (ή σε NULL προφανώς).
defacer Δημοσ. 19 Ιουλίου 2012 Δημοσ. 19 Ιουλίου 2012 Εγώ πάλι αντίθετα με τον defacer δεν θα σε απέτρεπα ούτε από το να περνάς τους πίνακες ως ορίσματα (έτσι κι αλλιώς στη C το πέρασμα ισοδυναμεί αυτόματα με δείκτη στο 1ο στοιχείο τους) ούτε από το να μην περνάς και το μήκος τους ως όρισμα. Encapsulation. Από τη στιγμή που μιλάμε για fixed-size πίνακες, μπορείς να μην περνάς το μέγεθός τους και να χρησιμοποιείς απευθείας μέσα στην συνάρτηση το #define που αντιστοιχεί στο μήκος τους. Στη συγκεκριμένη περίπτωση ναι. Σαν learning exercise όμως, όπως και στη γενική περίπτωση, bad idea.
Προτεινόμενες αναρτήσεις