migf1 Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 (επεξεργασμένο) Που έγραψα "έμπειροι προγραμματιστές"; Για το warning, πες μας τι ακριβώς σου λέει ο compiler (βασικά ψιλο-χοντρο βαριέμαι να... αποκρυπτογραφήσω όλους εκείνους του δείκτες που παραθέτεις, επειδή δεν εξυπηρετούν κάποια γενικότερη λογική ροή, οπότε είναι και βαρετό και χρονοβόρο). Για τους πίνακες τώρα, στη C όλοι οι στατικά δηλωμένοι πίνακες μεταφράζονται μονοδιάστατα από τον compiler. Έστω... > int arr2d[NROWS][NCOLS]; το παραπάνω μεταφράζεται σε... > int arr2d[NROWS * NCOLS]; Αν n είναι ο μονοδιάστατος indexer και i,j οι 2διάστατοι indexers, τότε ανά πάσα στιγμή ισχύουν τα ακόλουθα... > n = i * NCOLS + j; και... > i = n / NCOLS; j = n % NCOLS; Οπότε όχι μόνο κανείς δεν μας εμποδίζει να ορίσουμε μονοδιάστατα έναν 2διάστατο πίνακα, και να τον διαχειριστούμε ανάλογα, αλλά πολλές φορές μας εξυπηρετεί και καλύτερα. Π.χ. σε παιχνίδια με τράπουλα, συνήθως εξυπηρετεί καλύτερα η 2διάστατη τράπουλα να οριστεί μονοδιάστα... > #define NSUITS 4 #define NFACES 13 #define NCARDS (NSUITS * NFACES) #define HAND_NCARDS 6 ... typedef struct Card { ... } Card; ... Card deck[NCARDS]; Διευκολύνει ας πούμε στο ανακάτεμα ή στο μοίρασμα... > void deck_shuffle( Card deck[NCARDS] ) { for (int i=0; i < 3000; i++) card_swap( &deck[rand % NCARDS], &deck[rand % NCARDS] ); } bool deck_deal( Card deck[NCARDS], Card *hand[HAND_NCARDS], int *posDeal ) { for (int i=0; i < HAND_NCARDS; i++) hand[i] = &deck[(*posDeal)++]; ... } Παρέλειψα sanity checks κλπ για να μείνει εύκολα αναγνώσιμος ο κώδικας (το posDeal είναι θέση στην τράπουλα από την οποία ξεκινάει το μοίρασμα). Ο αντίστοιχος κώδικας με 2διάστατα δηλωμένη την τράπουλα είναι πιο περίπλοκος. Φυσικά υπάρχουν περιπτώσεις που ο κώδικας είναι πιο απλός όταν η τράπουλα είναι δηλωμένη 2διάστατα. Για παράδειγμα ο εντοπισμός ας πούμε του Ρήγα Καρό μέσα στην τράπουλα, με 2διάστατη τράπουλα είναι ένα απλό... >deck[sUIT_DIAMONDS][FACE_KING] ενώ με μονοδιάστατη τράπουλα περιπλέκεται σε... >deck[sUIT_DIAMONDS * NFACES + FACE_KING] Αν και αυτές οι εκφράσεις απλοποιούνται με macros, π.χ... > #define N_(i,j) (i) * (NFACES) + (j) ... deck[ N_(SUIT_DIAMONS,FACE_KING) ]; Επεξ/σία 26 Οκτωβρίου 2012 από migf1
imitheos Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 Δεν μπορω να καταλάβω ποια τιμή δεν χρησιμοποιεί ο compiler και μου δινει warn εδω -> > *q++; ----> (*q)++; Αγνοησε τα άλλα και δες μονο το *q++ και την printf μετα. Να ρωτησω κατι ακομη.... αν έχουμε a[j] = 0 o μεταγλωτιστης παράγει οδηγιες για να γίνουν : 1. Πολλ/σμος του i με το μέγεθος μιας single γραμμής 2. Δινει αυτο το αποτέλεσμα εκει που αναπαριστα ο a 3. ΠΟλλαπλασιαζει το j με το μέγεθος ενος στοιχειου πινακα και 4. βάζει αυτο τον υπολογισμο στην διευθυνση που παραγεται απο το βημα 2. οταν λεει single row σε εναν δισδιαστατο εννοει πως αν εχω πχ τον Εφόσον δεν έχουμε δείκτη ή VLA αλλά ένα κανονικό πίνακα, τότε θα γίνει δέσμευση της απαραίτητης μνήμης συνεχόμενα και το a είναι απλά ένα συμβολικό όνομα για μια γνωστή στον compiler (ή καλύτερα στον linker) διεύθυνση μνήμης. Από εκεί και πέρα όπου έχουμε a ισοδυναμεί με αυτή την διεύθυνση η οποία να τονίσουμε πως είναι γνωστή εξαρχής. Αν πχ έχουμε int a[5][8], θα δεσμευτούν 5 * 8 * sizeof(int) συνεχόμενα bytes στη διεύθυνση τάδε. Ας υποθέσουμε ότι είναι η διεύθυνση 500. Το a[j] λέει πρόσθεσε στο 500 το μέγεθος του τύπου i * 8 + j φορές και προσπέλασε τη διεύθυνση που προκύπτει. Αν ο int έχει μέγεθος 4 θα έχουμε 500 + 4 * (i * 8 + j). Επίσης ένα πράγμα που έχει σημασία είναι ότι ενώ η μνήμη δεσμεύεται συνεχόμενα, δεν μπορούμε να την προσπελάσουμε όπως θέλουμε. Στο παραπάνω παράδειγμα, η παράσταση a[1][1] είναι σωστή ενώ η a[0][10] έχει αόριστη συμπεριφορά και μπορεί να βγει ένας δράκος και να δαγκώσει το χέρι. 1
migf1 Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 οκ το γράψα: http://www.insomnia.gr/topic/437533-%ce%b5%cf%81%cf%89%cf%84%ce%ae%cf%83%ce%b5%ce%b9%cf%82-%ce%b3%ce%b9%ce%b1-c/page__st__855#entry5037820
Star_Light Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 (επεξεργασμένο) migf1 θα διαβάσω σε λιγο αυτα που δινεις για τους πολυδιαστατους και τις τραπουλες ή αυριο. Το 12 στον King ειναι απαιτητικο επειδη δεν είχα καλο υποβαθρο στους δισδιαστατους. Ένα - ένα γιατι αν χάσουμε τωρα την μπάλα γμστα. Λοιπον το warn message ειναι tests2.c:18: warning: value computed is not used @imitheos οπα μπερδευτηκα.... ο a[5][8] ειναι ουσιαστικα 5 γραμμές με 8 στοιχεία ( οι στήλες του ) αν τον εικονικοποιήσουμε με row order . Για αυτο η κάθε γραμμή του έχει σαν μέγεθος το 8? Αρα για το a[0][1] θα ειναι 500 + 0* 8 = 500 1 ( j ) * 4 bytes = 4 Αρα 500 + 4 = 504 στην 504 θα ειναι το a[0][1] Ειμαι σωστος ? Για αυτο και δεν μπορεις να παραλείψεις τον αριθμο των στηλών οταν έχεις τον πινακα στο πρωτυπο σε μια συνάρτηση. Ακριβως επειδη χρειάζεται στον υπολογισμο πιο πανω. Επεξ/σία 26 Οκτωβρίου 2012 από Star_Light
migf1 Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 migf1 θα διαβάσω σε λιγο αυτα που δινεις για τους πολυδιαστατους και τις τραπουλες ή αυριο. Το 12 στον King ειναι απαιτητικο επειδη δεν είχα καλο υποβαθρο στους δισδιαστατους. Ένα - ένα γιατι αν χάσουμε τωρα την μπάλα γμστα. Οκ. Λοιπον το warn message ειναι tests2.c:18: warning: value computed is not used Το "value computed" είναι το περιεχόμενο της μνήμης sizeof(int) bytes μετά από την αρχική θέση του δείκτη q (ο οποίος έχει πλέον μετακινηθεί εκεί). Αυτό το περιεχόμενο δεν το χρησιμοποιείς πουθενά. Δοκίμασε να τρέξεις αυτό... > #include <stdio.h> #include <stdlib.h> // ---------------------------------------------------------------- void double_pointer_f(int **p) { **p = 4; return ; } // ---------------------------------------------------------------- int main( void ) { int x = 2, *p = NULL, **pp = NULL; int y = 3; int *q = &y; // 3 == *q // x stuff _________________________ puts( "*** X STUFF ***" ); printf( "x = 2; \t\t\t(x = %d)\n", x ); p = &x; // 2 == *p printf( "int *p = &x; \t\t(x = %d | *p = %d)\n", x, *p ); double_pointer_f( &p ); // 4 == *p printf("double_pointer(&p); \t(x = %d | *p = %d)\n", x, *p ); pp = &p; // 4 == **pp printf( "int **pp = &p; \t\t(x = %d | *p = %d | **pp = %d)\n" , x, *p, **pp); // y stuff __________________________ putchar( '\n' ); puts( "*** Y STUFF ***" ); printf( "y = 3; \t\t(y = %d)\n", y ); printf( "int *q = &y; \t(y = %d | *q = %d)\n", y, *q ); (*q)++; printf("(*q)++; \t(y = %d | *q = %d)\n", y, *q ); *q++; printf("*q++; \t\t(y = %d | *q = %d)\n", y, *q ); system( "pause" ); return 0; } ... ο a[5][8] ειναι ουσιαστικα 5 γραμμές με 8 στοιχεία ( οι στήλες του ) αν τον εικονικοποιήσουμε με row order . Για αυτο η κάθε γραμμή του έχει σαν μέγεθος το 8? Αρα για το a[0][1] θα ειναι 500 + 0* 8 = 500 Σου έδωσα ήδη τους τύπους πριν, οπότε... >a[0][1] == a + (0 * 8 + 1) Δηλαδή ο τύπος που σου έγραψα στο προηγούμενο ποστ, όπου i=0, j=1 και NCOLS = 8 (8 επειδή με τόσες στήλες έχεις ορίσει τον πίνακα). Αν το θες σε bytes, τότε είναι... >(0 * 8 + 1) * sizeof(int) bytes πιο πέρα από εκεί που αρχίζει ο a. Δηλαδή: &a + (0 * 8 + 1) * sizeof(int)
imitheos Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 Λοιπον το warn message ειναι tests2.c:18: warning: value computed is not used Έδειξα στο προηγούμενο μήνυμα γιατί το βγάζει. Λόγω διαφορετικής προτεραιότητας τελεστών, πρώτα αυξάνεις τον q και μετά τον κάνεις dereference χωρίς να κάνεις τίποτα αυτή την τιμή που παίρνεις. Εσύ ο ίδιος έγραψες πριν λίγα μηνύματα το παρακάτω. Ε ναι αμα δεν λύνεις και ασκησεις δεν πας πουθενα. Πχ οσο καλους δεικτες και να χεις διαβάσει μπορει να πέσεις σε κάνα τέτοιο -> *p++; θεωρεις σωστα οτι το *p ειναι μια έμμεση αναφορα για την μεταβλητή οποτε μπορεις να δώσειςμια αύξηση οπως θα έδινες και στην κανονικη μεταβλητη... πχ int x ..... x++ . Οποτε πεφτεις σε λουμπιτσα επειδη δεν ειναι το ιδιο γιατι ο ++ εχει υψηλοτερη προτεραιότητα απο τον (*) οποτε αν θες να αυξήσεις απλα την μεταβλητή στην οποία δειχνει ο δεικτης δινεις ένα *(p++) ή ++ *p ; κοιταζα μια άσκηση πριν και το βρήκα. @imitheos οπα μπερδευτηκα.... ο a[5][8] ειναι ουσιαστικα 5 γραμμές με 8 στοιχεία ( οι στήλες του ) αν τον εικονικοποιήσουμε με row order . Για αυτο η κάθε γραμμή του έχει σαν μέγεθος το 8? Ο a είναι πίνακας 5 στοιχείων με το καθένα από αυτά να είναι πίνακας 8 ακεραίων. Οπότε η διάσταση που μας νοιάζει είναι το 8. Αρα για το a[0][1] θα ειναι 500 + 0* 8 = 500 1 ( j ) * 4 bytes = 4 Αρα 500 + 4 = 504 στην 504 θα ειναι το a[0][1] Ειμαι σωστος ? Για αυτο και δεν μπορεις να παραλείψεις τον αριθμο των στηλών οταν έχεις τον πινακα στο πρωτυπο σε μια συνάρτηση. Ακριβως επειδη χρειάζεται στον υπολογισμο πιο πανω. Όχι ο a[0][1] αλλά ο a[0] είναι 500 + 0 * 8 (* 4) = 500. Από εκεί και πέρα για να βρεις τον a[0][1] προσθέτεις 1 * 4 οπότε και βγαίνει το 504.
Star_Light Δημοσ. 26 Οκτωβρίου 2012 Δημοσ. 26 Οκτωβρίου 2012 (επεξεργασμένο) Έδειξα στο προηγούμενο μήνυμα γιατί το βγάζει. Λόγω διαφορετικής προτεραιότητας τελεστών, πρώτα αυξάνεις τον q και μετά τον κάνεις dereference χωρίς να κάνεις τίποτα αυτή την τιμή που παίρνεις. Εσύ ο ίδιος έγραψες πριν λίγα μηνύματα το παρακάτω. Ο a είναι πίνακας 5 στοιχείων με το καθένα από αυτά να είναι πίνακας 8 ακεραίων. Οπότε η διάσταση που μας νοιάζει είναι το 8. Όχι ο a[0][1] αλλά ο a[0] είναι 500 + 0 * 8 (* 4) = 500. Από εκεί και πέρα για να βρεις τον a[0][1] προσθέτεις 1 * 4 οπότε και βγαίνει το 504. Aσε τους πινακες θα τους δω αύριο. Κοιτα σε αυτα που έγραψα έχει γινει λάθος. Δεν αυξάνεις την μεταβλητη στην οποια δειχνει ο δεικτης με το *p++ . Αρχικα παίρνεις εκει που δειχνει ο δεικτης το p++ δινει p... κάνεις dereference το στοιχειο αυτης της θέσης μετα αυξάνεται η θέση του . Και οπως εύστοχα είπες... αν έχω > *p++; printf(" %d " , *p); τοτε αρχικα υπολογιζεται ο p δινει την θέση (διευθυνση) στην οποια ειναι εξαρχης αρχικοποιημένος και μετα την κανει dereference δεν προλαβαινω να την χρησιμοποιήσω ομως διοτι στην printf που ακολουθεί χρησιμοποιώ την τιμή της νέας θέσης... ΑΝ πριν εδειχνε πχ στο a[3] τωρα δειχνει στο a[4]. Το a[3] παπαλα... και αυτο συμβαινει και βαραει ο μεταγλωτιστης κατα την αποψη μου. Αν ηθελα να αυξησω την μεταβλητη απλα στην οποια δειχνει θα ηθελα ένα (*p)++ , ++(*p) ή ++ *p απλα τα 2 τελευταια ειναι ισοδυναμα και ο δεικτης δεν υφισταται καμια αλλαγη. Το προβλημα λύνεται αν έδινα απευθειας printf("%d" , *p++ ); οποτε και θα εκτύπωνε αυτο που χάνω με αυτο που έκανα πριν για λογους που ομως δεν θελω αλλο να συζητησω υ.γ migf1 οποτε ευκαιρήσεις διόρθωσε το link σου εδω http://x-karagiannis...st-increaments/ Oχι increaments ... increments ειναι. Επεξ/σία 27 Οκτωβρίου 2012 από Star_Light
nik324 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Θα ηθελα λιγη βοηθεια... Εχω φιαξει μια συναρτηση που εισαγει ενα κομβο σε μια διπλα ταξινομιμενη λιστα...αφου εχω βρει το καταλληλο σημειο εισαγωγης τους νεου κομβου, εχω ενα δεικτη dummy και ενα head στους κομβους που αναμεσα θελω να κανω την εισαγωγη...Κανω αυτο που παραθετω σαν κωδικα και ολα ειναι οκ εκτος απο την περιπτωση που ο νεος κομβος πρεπει να παει σαν τελευταιος γιατι ειναι και ο μεγαλυτερος... > new->prev=dummy; new->next=dummy->next; new->prev->next=new; new->next->prev=new; dummy=new; Δεν θελω να παραθεσω ολο τον κωδικα...αν θελει ομως καποιος μπορω να του τον στειλω σε πμ...Ευχαριστω πολυ
migf1 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 (επεξεργασμένο) Θα ηθελα λιγη βοηθεια... Εχω φιαξει μια συναρτηση που εισαγει ενα κομβο σε μια διπλα ταξινομιμενη λιστα...αφου εχω βρει το καταλληλο σημειο εισαγωγης τους νεου κομβου, εχω ενα δεικτη dummy και ενα head στους κομβους που αναμεσα θελω να κανω την εισαγωγη...Κανω αυτο που παραθετω σαν κωδικα και ολα ειναι οκ εκτος απο την περιπτωση που ο νεος κομβος πρεπει να παει σαν τελευταιος γιατι ειναι και ο μεγαλυτερος... > new->prev=dummy; new->next=dummy->next; new->prev->next=new; new->next->prev=new; dummy=new; Δεν θελω να παραθεσω ολο τον κωδικα...αν θελει ομως καποιος μπορω να του τον στειλω σε πμ...Ευχαριστω πολυ Καλημέρα, η γνώμη μου είναι πως θα ευεργετηθείς πάρα πολύ (όχι μόνο στο συγκεκριμένο, αλλά και στις υπόλοιπες συναρτήσεις διαχείρισης της λίστας σου) αν μαζί με τον head διατηρείς κι έναν δείκτη tail (στον τελευταίο κόμβο της λίστας σου) στην βασική δομή της λίστας σου. Οπότε την περίπτωση που περιγράφεις θα την αντιμετωπίζεις με if ως special-case, πριν από τον κώδικα της γενικής περίπτωσης. Το μεγάλο πλεονέκτημα είναι η άμεση εισαγωγή του νέου κόμβου, χωρίς να χρειάζεται να κάνεις traverse ολόκληρη τη λίστα. Εφόσον δεν θες να βγει public ο κώδικάς σου (υποθέτω επειδή πρόκειται για εργασία και δεν θέλεις να δώσεις ιδέες στους υπόλοιπους) σου παραθέτω δικό μου κώδικα που εισαγάγει ταξινομημένα κατά αύξουσα σειρά έναν κόμβο σε μια απλά συνδεδεμένη λίστα. Αντιμετωπίζει την περίπτωση που περιγράφεις καθώς και την περίπτωση της κενής λίστας ξεχωριστά, ως special-cases, πριν από τον κώδικα της γενικής περίπτωσης. Νομίζω έχει τη δυναμική να σε βοηθήσει, όχι μόνο εσένα αλλά και άλλα παιδιά που ενδέχεται να διαβάζουν το νήμα. Αντί για έναν προσωρινό δείκτη dummy χρησιμοποιώ δυο (curr και prev) μιας και η λίστα είναι απλά συνδεδεμένη, κι άρα δεν υπάρχει η ευκολία των prev δεικτών ως μέρος των κόμβων της λίστας. Η περίπτωση που περιγράφεις είναι η σχολιασμένη ως "direct append" σε αυτόν τον κώδικα... Κώδικας... > ... typedef struct node { int data; struct node *next; } Node; typedef struct { Node *head, *tail; int len; } List; ... /* ------------------------------------------------------------------ * Ascending order Insertion of data into list */ Bool list_insascend( List *list, int data ) { Node *curr = NULL, *prev = NULL; Node *new = calloc( 1, sizeof(struct node) ); if ( !new ) // calloc failed return FALSE; new->data = data; new->next = NULL; if ( NULL == list->head ) { // list was empty list->head = list->tail = new; (list->len)++; return TRUE; } if ( data >= list->tail->data ) { // direct append list->tail->next = new; list->tail = new; (list->len)++; return TRUE; } curr = prev = list->head; // general case (traversing) // find spot for the insertion while ( curr && curr->data <= data ) { // use <= data, to allow duplicates prev = curr; // save previous node curr = curr->next; } // insert BEFORE 1st node if ( list->head == curr /* && curr->data != data */ ) { list->head = new; new->next = curr; (list->len)++; return TRUE; } // insert AFTER 1st node if ( !curr || curr->data != data ) { prev->next = new; new->next = curr; } (list->len)++; return TRUE; } Η συγκεκριμένη υλοποίηση επιτρέπει και διπλο-εγγραφές μέσα στη λίστα. Off-topic... ... υ.γ migf1 οποτε ευκαιρήσεις διόρθωσε το link σου εδω http://x-karagiannis...st-increaments/ Oχι increaments ... increments ειναι. Αν το αλλάξω θα σταματήσουν να λειτουργούν ενδεχόμενα bookmarks που έχουν κάνει αναγνώστες του site. EDIT: Ξέχασα, σχετικά με το απόσπασμα που παρέθεσες δοκίμασε με ένα if για την "προβληματική" περίπτωση. Δεν ξέρω αν θα σου δουλέψει σίγουρα γενικώς για το πρόγραμμά σου, γιατί δεν ξέρω την υπόλοιπη υλοποίηση (π.χ. το ότι στο τέλος κάνεις advance τον dummy να δείχνει στον νέο κόμβο, δεν γνωρίζω σε τι μπορεί να εξυπηρετεί τον υπόλοιπο κώδικα). Για δοκίμασέ το όμως και πες μας το αποτέλεσμα... > // set new node's prev & next pointers new->prev = dummy; // new's prev now points to dummy new->next = dummy->next; // new's next now points wherever dummy's next is pointing to // update dummy's next pointer, so it points to the new node dummy->next = new; /* was: new->prev->next = new; */ // update prev pointer of whichever node follows new (it may be NULL) /* ( was: new->next->prev = new; ) */ if ( NULL != new->next ) new->next->prev = new; // advance dummy by 1 node dummy = new; Επεξ/σία 27 Οκτωβρίου 2012 από migf1
nik324 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Καλημέρα, η γνώμη μου είναι πως θα ευεργετηθείς πάρα πολύ (όχι μόνο στο συγκεκριμένο, αλλά και στις υπόλοιπες συναρτήσεις διαχείρισης της λίστας σου) αν μαζί με τον head διατηρείς κι έναν δείκτη tail (στον τελευταίο κόμβο της λίστας σου) στην βασική δομή της λίστας σου. Οπότε την περίπτωση που περιγράφεις θα την αντιμετωπίζεις με if ως special-case, πριν από τον κώδικα της γενικής περίπτωσης. Το μεγάλο πλεονέκτημα είναι η άμεση εισαγωγή του νέου κόμβου, χωρίς να χρειάζεται να κάνεις traverse ολόκληρη τη λίστα. Εφόσον δεν θες να βγει public ο κώδικάς σου (υποθέτω επειδή πρόκειται για εργασία και δεν θέλεις να δώσεις ιδέες στους υπόλοιπους) σου παραθέτω δικό μου κώδικα που εισαγάγει ταξινομημένα κατά αύξουσα σειρά έναν κόμβο σε μια απλά συνδεδεμένη λίστα. Αντιμετωπίζει την περίπτωση που περιγράφεις καθώς και την περίπτωση της κενής λίστας ξεχωριστά, ως special-cases, πριν από τον κώδικα της γενικής περίπτωσης. Νομίζω έχει τη δυναμική να σε βοηθήσει, όχι μόνο εσένα αλλά και άλλα παιδιά που ενδέχεται να διαβάζουν το νήμα. Αντί για έναν προσωρινό δείκτη dummy χρησιμοποιώ δυο (curr και prev) μιας και η λίστα είναι απλά συνδεδεμένη, κι άρα δεν υπάρχει η ευκολία των prev δεικτών ως μέρος των κόμβων της λίστας. Η περίπτωση που περιγράφεις είναι η σχολιασμένη ως "direct append" σε αυτόν τον κώδικα... Κώδικας... > ... typedef struct node { int data; struct node *next; } Node; typedef struct { Node *head, *tail; int len; } List; ... /* ------------------------------------------------------------------ * Ascending order Insertion of data into list */ Bool list_insascend( List *list, int data ) { Node *curr = NULL, *prev = NULL; Node *new = calloc( 1, sizeof(struct node) ); if ( !new ) // calloc failed return FALSE; new->data = data; new->next = NULL; if ( NULL == list->head ) { // list was empty list->head = list->tail = new; (list->len)++; return TRUE; } if ( data >= list->tail->data ) { // direct append list->tail->next = new; list->tail = new; (list->len)++; return TRUE; } curr = prev = list->head; // general case (traversing) // find spot for the insertion while ( curr && curr->data <= data ) { // use <= data, to allow duplicates prev = curr; // save previous node curr = curr->next; } // insert BEFORE 1st node if ( list->head == curr /* && curr->data != data */ ) { list->head = new; new->next = curr; (list->len)++; return TRUE; } // insert AFTER 1st node if ( !curr || curr->data != data ) { prev->next = new; new->next = curr; } (list->len)++; return TRUE; } Η συγκεκριμένη υλοποίηση επιτρέπει και διπλο-εγγραφές μέσα στη λίστα. Off-topic... Αν το αλλάξω θα σταματήσουν να λειτουργούν ενδεχόμενα bookmarks που έχουν κάνει αναγνώστες του site. EDIT: Ξέχασα, σχετικά με το απόσπασμα που παρέθεσες δοκίμασε με ένα if για την "προβληματική" περίπτωση. Δεν ξέρω αν θα σου δουλέψει σίγουρα γενικώς για το πρόγραμμά σου, γιατί δεν ξέρω την υπόλοιπη υλοποίηση (π.χ. το ότι στο τέλος κάνεις advance τον dummy να δείχνει στον νέο κόμβο, δεν γνωρίζω σε τι μπορεί να εξυπηρετεί το υπόλοιπο κώδικα). Για δοκίμασέ το όμως και πες μας το αποτέλεσμα... > // set new node's prev & next pointers new->prev = dummy; // new's prev now points to dummy new->next = dummy->next; // new's next now points wherever dummy's next was pointed to // update dummy's next pointer, so it points to the new node dummy->next = new; // was: new->prev->next = new; // update prev pointer of whichever node follows new (it may be NULL) // ( was: new->next->prev = new; ) if ( NULL != new->next ) new->next->prev = new; // advance dummy by 1 node dummy = new; Συνεχιζει να υπαρχει προβλημα...και εγω συνεχιζω να βρω που ειναι Ολα οκ...δεν χρησιμοιποιησα σωστα αυτο που μου εστειλες...Βρηκα το λαθος μου ομως και ολα δειχνουν να λειτουρργουν μια χαρα...Σε ευχαριστω πολυ
migf1 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Συνεχιζει να υπαρχει προβλημα...και εγω συνεχιζω να βρω που ειναι Οι πληροφορίες που μας δίνεις είναι λίγες, οπότε περιορίζεται και η δυνατότητα βοήθειας (π.χ. τι είδους πρόβλημα παρουσιάζεται, και σε ποιες ακριβώς περιπτώσεις). Plz μη μου στείλεις τον κώδικα σε π.μ. Αν νομίζεις πως μπορείς να δώσεις κι άλλες πληροφορίες, δημοσίευσέ τες στο νήμα. Διότι αφενός δεν είναι εγγυημένο το πότε κι εάν θα έχω την όρεξη ή/και τον χρόνο να μελετήσω μεγάλο κώδικα (οπότε σε ωφελεί να είναι δημόσια κατατεθειμένος σε περίπτωση που τον κοιτάξει κάποιο άλλο παιδί) κι αφετέρου το ηθικά σωστό είναι η δημόσια αίτηση για βοήθεια να ακολουθείται κι από δημόσια βοήθεια EDIT: Α γράφαμε μαζί, εσύ το edit σου κι εγώ την απάντηση στο unedited post σου. Οπότε όλα καλά, καλή συνέχεια
Star_Light Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Ναι. Ίσως σε βοηθήσει κι αυτό: http://x-karagiannis...ers/arithmetic/ Δηλαδή; Για παράδειγμα κάτι σαν το παρακάτω σε μπερδεύει; > #include <stdio.h> #include <stdlib.h> #define NROWS 4 #define NCOLS 3 /*********************************************//** * ************************************************* */ void arr_print( int arr[], int nelems ) { if ( nelems > NCOLS ) return; for (int i=0; i < nelems; i++) printf( "%d ", arr[i] ); puts("\b"); return; } /*********************************************//** * ************************************************* */ int main( void ) { int *pRow = NULL; int arr2d[NROWS][NCOLS] = { {0,0,0}, {1,1,1}, {2,2,2}, {3,3,3} }; for (pRow = *arr2d; pRow < arr2d[NROWS]; pRow += NCOLS ) { arr_print( pRow, NCOLS ); } system("pause"); // Windows only exit(0); } Ναι. Κοιτα καταρχην ειμαι στην σελιδα 268 και προσπαθω να καταλαβω τι γινεται εδω περα.... Ο δισδιάστατος σου αποτελειται απο 4 πίνακες με 3 στοιχεια ο καθενας ωραια? Καθε γραμμη ειναι πινακας 3 στοιχειων. Ο pRow ειναι δεικτης σε κάθε γραμμή δηλαδη σε κάθε πινακα 3 στοιχειων .... το *arr2d ομως ρε συ τι ακριβως ειναι? Αν έχουμε πχ > for( p = &a[0] ; p < &a[NUM_ROWS] ; p++) (*p)[i] = 0; To i εδω που αυξάνεται? ο p δείχνει σε διαφορετικο πίνακα - γραμμη καθε φορα 0 γραμμη πχ ταδε στοιχειων (στηλες) κ.ο.κ οκ το καταλαβα αυτο. > Το loop σταματαει οταν ο p φτάσει στον τελευταιο πίνακα που ειναι η τελευταια γραμμή στο δικο σου παράδειγμα για NROWS = 3.
migf1 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Ναι. Κοιτα καταρχην ειμαι στην σελιδα 268 και προσπαθω να καταλαβω τι γινεται εδω περα.... Δεν το έχω εύκαιρο τώρα το βιβλίο. Ο δισδιάστατος σου αποτελειται απο 4 πίνακες με 3 στοιχεια ο καθενας ωραια? Καθε γραμμη ειναι πινακας 3 στοιχειων. Ο pRow ειναι δεικτης σε κάθε γραμμή δηλαδη σε κάθε πινακα 3 στοιχειων .... το *arr2d ομως ρε συ τι ακριβως ειναι? Είναι η 1η γραμμή του arr2d[][] πίνακα. Ίσως σε βοηθάει καλύτερα να το γράψεις ως... >arr2d[0] Σημείωσε πως δεν θέλουμε τον addressof operator εδώ (&), γιατί η γραμμή arr2d[0] είναι ήδη πίνακας (άρα ήδη δείκτης). Οπότε αν γράφαμε &arr2d[0] θα αναφερόμασταν στην διεύθυνση του δείκτη που δείχνει στην 1η γραμμή (δηλαδή στη διεύθυνση πίνακα, δηλαδή θα θέλαμε δείκτη σε δείκτη), ενώ εμείς θέλουμε την διεύθυνση του 1ου ακέραιου στοιχείου στην 1η γραμμή (την οποία και την κάνουμε advance στο loop κατά sizeof(int) * NCOLS φορές). Αν έχουμε πχ > for( p = &a[0] ; p < &a[NUM_ROWS] ; p++) (*p)[i] = 0; To i εδω που αυξάνεται? ο p δείχνει σε διαφορετικο πίνακα - γραμμη καθε φορα 0 γραμμη πχ ταδε στοιχειων (στηλες) κ.ο.κ οκ το καταλαβα αυτο. Δεν έχεις ορίσει κάποιο i. Επίσης, ο p θα έπρεπε να αρχικοποιείται σε a[0]... έτσι όπως το 'χεις θα έπρεπε να είναι διπλός δείκτης ο p (το εξηγώ αμέσως πιο πριν). Οπότε είναι εσφαλμένα κι όλα τα υπόλοιπα από εκεί και μετά. EDIT: Προσέθεσα μερικές επεξηγήσεις ακόμα.
nik324 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Εστω οτι για ενα αφηριμενο τυπο δεδομενων θελω να φτιαξω μια λειτουργια makeEmptyADT() η οποια θα φτιαχνει αυτον τον κενο αφηρημενο τυπο δεδομενων για μελλοντικη χρηση..κανω το εξης..ειναι σωστο; > Type MakeEmptyADT() { Type *ptr=NULL; return ptr; } Eυχαριστώ
migf1 Δημοσ. 27 Οκτωβρίου 2012 Δημοσ. 27 Οκτωβρίου 2012 Εστω οτι για ενα αφηριμενο τυπο δεδομενων θελω να φτιαξω μια λειτουργια makeEmptyADT() η οποια θα φτιαχνει αυτον τον κενο αφηρημενο τυπο δεδομενων για μελλοντικη χρηση..κανω το εξης..ειναι σωστο; > Type MakeEmptyADT() { Type *ptr=NULL; return ptr; } Eυχαριστώ Δεν καταλαβαίνω τι εννοείς όταν λες "θα φτιάχνει αυτόν τον τύπο". Στα ADT συνήθως ο end-programmer περνάει τα data και το μέγεθος τους ως όρισματα στην συνάρτηση που του παρέχει το ADT interface για δημιουργία μιας ας την πούμε ADT μεταβλητής.
Προτεινόμενες αναρτήσεις