Προς το περιεχόμενο

Προτεινόμενες αναρτήσεις

Δημοσ. (επεξεργασμένο)

Που έγραψα "έμπειροι προγραμματιστές";

 

Για το 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) ];

Επεξ/σία από migf1
  • Απαντ. 1,6k
  • Δημ.
  • Τελ. απάντηση

Συχνή συμμετοχή στο θέμα

Δημοσ.

Δεν μπορω να καταλάβω ποια τιμή δεν χρησιμοποιεί ο 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] έχει αόριστη συμπεριφορά και μπορεί να βγει ένας δράκος και να δαγκώσει το χέρι.

  • Like 1
Δημοσ. (επεξεργασμένο)

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]

 

Ειμαι σωστος ?

 

Για αυτο και δεν μπορεις να παραλείψεις τον αριθμο των στηλών οταν έχεις τον πινακα στο πρωτυπο σε μια συνάρτηση. Ακριβως επειδη χρειάζεται στον υπολογισμο πιο πανω.

Επεξ/σία από Star_Light
Δημοσ.

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)

Δημοσ.

Λοιπον το 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.

Δημοσ. (επεξεργασμένο)

Έδειξα στο προηγούμενο μήνυμα γιατί το βγάζει. Λόγω διαφορετικής προτεραιότητας τελεστών, πρώτα αυξάνεις τον 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++ ); οποτε και θα εκτύπωνε αυτο που χάνω με αυτο που έκανα πριν για λογους που ομως δεν θελω αλλο να συζητησω :P

 

υ.γ migf1 οποτε ευκαιρήσεις διόρθωσε το link σου εδω

 

http://x-karagiannis...st-increaments/

 

Oχι increaments ... increments ειναι.

Επεξ/σία από Star_Light
Δημοσ.

Θα ηθελα λιγη βοηθεια...

 

Εχω φιαξει μια συναρτηση που εισαγει ενα κομβο σε μια διπλα ταξινομιμενη λιστα...αφου εχω βρει το καταλληλο σημειο εισαγωγης τους νεου κομβου, εχω ενα δεικτη dummy και ενα head στους κομβους που αναμεσα θελω να κανω την εισαγωγη...Κανω αυτο που παραθετω σαν κωδικα και ολα ειναι οκ εκτος απο την περιπτωση που ο νεος κομβος πρεπει να παει σαν τελευταιος γιατι ειναι και ο μεγαλυτερος...

>
    new->prev=dummy;
    new->next=dummy->next;
    new->prev->next=new;
    new->next->prev=new;
    dummy=new;

 

Δεν θελω να παραθεσω ολο τον κωδικα...αν θελει ομως καποιος μπορω να του τον στειλω σε πμ...Ευχαριστω πολυ

Δημοσ. (επεξεργασμένο)

Θα ηθελα λιγη βοηθεια...

 

Εχω φιαξει μια συναρτηση που εισαγει ενα κομβο σε μια διπλα ταξινομιμενη λιστα...αφου εχω βρει το καταλληλο σημειο εισαγωγης τους νεου κομβου, εχω ενα δεικτη 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;

Επεξ/σία από migf1
Δημοσ.

Καλημέρα,

 

η γνώμη μου είναι πως θα ευεργετηθείς πάρα πολύ (όχι μόνο στο συγκεκριμένο, αλλά και στις υπόλοιπες συναρτήσεις διαχείρισης της λίστας σου) αν μαζί με τον 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;

 

Συνεχιζει να υπαρχει προβλημα...και εγω συνεχιζω να βρω που ειναι :(

 

Ολα οκ...δεν χρησιμοιποιησα σωστα αυτο που μου εστειλες...Βρηκα το λαθος μου ομως και ολα δειχνουν να λειτουρργουν μια χαρα...Σε ευχαριστω πολυ

Δημοσ.

Συνεχιζει να υπαρχει προβλημα...και εγω συνεχιζω να βρω που ειναι :(

 

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

 

 

 

Plz μη μου στείλεις τον κώδικα σε π.μ. Αν νομίζεις πως μπορείς να δώσεις κι άλλες πληροφορίες, δημοσίευσέ τες στο νήμα.

 

Διότι αφενός δεν είναι εγγυημένο το πότε κι εάν θα έχω την όρεξη ή/και τον χρόνο να μελετήσω μεγάλο κώδικα (οπότε σε ωφελεί να είναι δημόσια κατατεθειμένος σε περίπτωση που τον κοιτάξει κάποιο άλλο παιδί) κι αφετέρου το ηθικά σωστό είναι η δημόσια αίτηση για βοήθεια να ακολουθείται κι από δημόσια βοήθεια ;)

 

 

 

EDIT:

 

Α γράφαμε μαζί, εσύ το edit σου κι εγώ την απάντηση στο unedited post σου. Οπότε όλα καλά, καλή συνέχεια :)

Δημοσ.

Ναι. Ίσως σε βοηθήσει κι αυτό: 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.

Δημοσ.

 

 

Ναι. Κοιτα καταρχην ειμαι στην σελιδα 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:

 

Προσέθεσα μερικές επεξηγήσεις ακόμα.

Δημοσ.

Εστω οτι για ενα αφηριμενο τυπο δεδομενων θελω να φτιαξω μια λειτουργια makeEmptyADT()

η οποια θα φτιαχνει αυτον τον κενο αφηρημενο τυπο δεδομενων για μελλοντικη χρηση..κανω το εξης..ειναι σωστο;

 

 

>
Type MakeEmptyADT()
{
Type *ptr=NULL;
return ptr;
}

Eυχαριστώ

Δημοσ.

Εστω οτι για ενα αφηριμενο τυπο δεδομενων θελω να φτιαξω μια λειτουργια makeEmptyADT()

η οποια θα φτιαχνει αυτον τον κενο αφηρημενο τυπο δεδομενων για μελλοντικη χρηση..κανω το εξης..ειναι σωστο;

 

 

>
Type MakeEmptyADT()
{
Type *ptr=NULL;
return ptr;
}

Eυχαριστώ

 

Δεν καταλαβαίνω τι εννοείς όταν λες "θα φτιάχνει αυτόν τον τύπο".

 

Στα ADT συνήθως ο end-programmer περνάει τα data και το μέγεθος τους ως όρισματα στην συνάρτηση που του παρέχει το ADT interface για δημιουργία μιας ας την πούμε ADT μεταβλητής.

 

 

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

  • Δημιουργία νέου...