Σημειώσεις έκτης και έβδομης εβδομάδας Προσέξτε το μέγεθος των δύο δομών. Το Node είναι 8 bytes, ενώ το Node1 1 byte. Η διαφορά έγκειται στο ότι η πρώτη δομή περιέχει ακέραιο, τον δείκτη next, οπότε πρέπει να στοιχίζεται σε θέσεις μνήμης οι οποίες να είναι πολλαπλάσια του μεγέθους του δείκτη. Στον συγκεκριμένο υπολογιστή και compiler τα μεγέθη είναι αυτά που εμφανίζονται στα σχόλια δίπλα από κάθε printf στον κώδικα: int main(void){ typedef struct node { char name; struct node* next; Node; typedef struct node1 { char name; Node1; printf("int: %d\n", sizeof(int)); /* prints 4 */ printf("int*: %d\n", sizeof(int*)); /* prints 4 */ printf("char: %d\n", sizeof(char)); /* prints 1 */ printf("char*: %d\n", sizeof(char*)); /* prints 4 */ printf("node*: %d\n", sizeof(node*)); /* prints 4 */ printf("node: %d\n", sizeof(node)); /* prints 8 */ printf("node1: %d\n", sizeof(node1)); /* prints 1 */ Όταν πρέπει να καλέσουμε την malloc, για δυναμική δέσμευση μνήμης, πρέπει να ελέγχουμε αν η μνήμη πράγματι δεσμεύτηκε ή όχι. Αυτό γίνεται με τον έλεγχο. Αν δεν μπορέσει να δεσμευτεί η μνήμη η malloc επιστρέφει NULL. Εδώ σαν παράδειγμα malloc με έλεγχο για NULL, βλέπουμε την συνάρτηση strdup, η οποία δημιουργεί αντίγραφα από strings. char *strdup(char *s) { char *d=(char*)malloc(strlen(s)+1); if(d==null) return NULL; strcpy(d,s); return d; Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 1 costis@teicrete.gr
Την αρχική μας λίστα της προηγούμενης εβδομάδας την τροποποιούμε έτσι ώστε να γίνει λίστα ονομάτων, αντί για λίστα χαρακτήρων που ήταν. : #include <stdlib.h> #include <string.h> typedef struct node { char* name; struct node* next; Node; void printlist(node* n); int main(void) { Node *fp, *np, *cp; char* name; name=(char*)malloc(80*sizeof(char)); if(name==null) { printf("no memory!\n"); return -1; fp = NULL; printf("enter name: "); scanf("%s",name); while(strcmp(name,"end")) { np = (Node*) malloc(sizeof (Node)); np->name=strdup(name); np->next = NULL; if (fp == NULL) fp = np; else cp->next = np; cp = np; printf("enter name: "); scanf("%s",name); printlist(fp); void printlist(node* current) { if (current == NULL) printf("list is empty\n"); else { printf("%s->", current->name); while (current->next!= NULL) { current = (Node*) current->next; printf("%s->", current->name); printf("null\n"); Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 2 costis@teicrete.gr
H παρακάτω πρόχειρη εκδοχή της deletelist θα μπορούσε να χρησιμοποιηθεί εάν μετά την κλήση της μηδενίσουμε μόνοι μας τον δείκτη στην κεφαλή της λίστας. Αυτό δεν είναι δυνατόν να γίνει μέσα από την συνάρτηση επειδή ο απλός δείκτης στην κεφαλή της λίστας επιτρέπει την αλλαγή στη μεταβλητή στην οποία δείχνει, αλλά όχι την μετατροπή του ίδιου του δείκτη, ο οποίος περνάει σαν αντίγραφο στην συνάρτηση: void deletelist(node* current) { Node* tmp; if (current == NULL) printf("list is empty\n"); else while (current!= NULL) { tmp=current; free(current->name); // επειδή έχουμε πάρει δυναμικά τη μνήμη name current->next=null; free(current); current = (Node*) tmp->next; Απλοί Δείκτες Διπλοί Δείκτες Για να υλοποιήσουμε το παρακάτω παράδειγμα από το βιβλίο των Deitel, χρειαζόμαστε δείκτη σε δείκτη. Με αυτόν τον τρόπο μπορούμε να μηδενίσουμε τον δείκτη στην κεφαλή της λίστας μέσα από μία συνάρτηση. Αν χρησιμοποιήσουμε απλό δείκτη, τότε μπορούμε να τροποποιούμε το σημείο στο οποίο δείχνει ο δείκτης, αλλά όχι τον ίδιο τον δείκτη. Όπως γνωρίζουμε, χρησιμοποιώντας απλούς δείκτες μπορούμε να αλλάξουμε τα περιεχόμενα μέσα από την συνάρτηση swap: void swap(int*,int*); int main(int argc,char** argv) { int x,y; int *m, *n; x=5; y=9; m=&x; n=&y; printf("m %p\n", m); printf("swap\n"); swap(&x,&y); Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 3 costis@teicrete.gr
printf("m %p\n", m); printf("x %d\n", x); printf("y %d\n", y); void swap(int *a,int *b){ int tmp; tmp=*a; *a=*b; *b=tmp; Χρησιμοποιώντας διπλούς δείκτες μπορούμε να αλλάξουμε τους δείκτες μέσα από την συνάρτηση. void swap(int**,int**); int main(int argc,char** argv) { int x,y; int *m, *n; x=5; y=9; m=&x; n=&y; printf("m %p\n", m); printf("swap\n"); swap(&m,&n); printf("m %p\n", m); printf("x %d\n", x); printf("y %d\n", y); Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 4 costis@teicrete.gr
void swap(int **a,int **b){ int *tmp; tmp=*a; *a=*b; *b=tmp; Από το βιβλίο των Deitel, η λίστα αυτή ταξινομεί τους χαρακτήρες που εισάγει ο χρήστης και επιτρέπει την διαγραφή τους χρησιμοποιώντας συναρτήσεις. Διπλοί δείκτες περνάνε μόνο στις συναρτήσεις που αλλάζουν τον δείκτη στην κεφαλή της λίστας, για να μπορούν να αλλάξουν την διεύθυνση στην οποία δείχνουν σε περίπτωση προσθήκης νέου κόμβου ή διαγραφής του πρώτου κόμβου. /* * Deitel Simply Linked List Example */ #include <stdlib.h> struct listnode { char data; struct listnode *nextptr; ; typedef struct listnode ListNode; typedef ListNode* ListNodePtr; void insert(listnodeptr *sptr, char value); char delete(listnodeptr *sptr, char value); int isempty(listnodeptr sptr); void printlist(listnodeptr currentptr); void instructions(void); int main(int argc, char** argv) { ListNodePtr startptr = NULL; int choice; char item; instructions(); printf("? "); scanf("%d", &choice); while (choice!= 3) { switch (choice) { case 1: printf("enter a character: "); scanf("\n%c", &item); insert(&startptr, item); printlist(startptr); break; Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 5 costis@teicrete.gr
case 2: if (!isempty(startptr)) { printf("enter character to be deleted: "); scanf("\n%c", &item); if (delete(&startptr, item)) { printf("%c deleted.\n", item); printlist(startptr); else { printf("%c not found.\n\n", item); else { printf("list is empty.\n\n"); break; default: printf("invalid choice.\n\n"); instructions(); break; printf("? "); scanf("%d", &choice); printf("end of run.\n"); return (EXIT_SUCCESS); void instructions(void) { printf("enter your choice:\n" " 1 to insert an element into list.\n" " 2 to delete an element from the list.\n" " 3 to end.\n"); void insert(listnodeptr *sptr, char value) { ListNodePtr newptr, previousptr, currentptr; newptr = malloc(sizeof (ListNode)); if (newptr!= NULL) { newptr->data = value; newptr->nextptr = NULL; previousptr = NULL; currentptr = *sptr; while (currentptr!= NULL && value > currentptr->data) { previousptr = currentptr; currentptr = currentptr->nextptr; if (previousptr == NULL) { newptr->nextptr = *sptr; *sptr = newptr; else { previousptr->nextptr = newptr; newptr->nextptr = currentptr; Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 6 costis@teicrete.gr
else { printf("%c not inserted. No memory available.\n", value); char delete(listnodeptr *sptr, char value) { ListNodePtr previousptr, currentptr, tempptr; if (value == (*sptr)->data) { tempptr = *sptr; *sptr = (*sptr)->nextptr; free(tempptr); return value; else { previousptr = *sptr; currentptr = (*sptr)->nextptr; while (currentptr!= NULL && currentptr->data!= value) { previousptr = currentptr; currentptr = currentptr->nextptr; if (currentptr!= NULL) { tempptr = currentptr; previousptr->nextptr = currentptr->nextptr; free(tempptr); return value; return '\0'; int isempty(listnodeptr sptr) { return sptr == NULL; void printlist(listnodeptr currentptr) { if (currentptr == NULL) { printf("list is empty.\n\n"); else { printf("the list is:\n"); while (currentptr!= NULL) { printf("%c --> ", currentptr->data); currentptr = currentptr->nextptr; printf("null\n\n"); Σημειώσεις Εργαστηρίου Δομών και Αλγορίθμων Week6-7 7 costis@teicrete.gr