Προγραμμαηιζμός Ι ( ΗΥ120 ) Δηάιεμε 15: Δπλακηθή Μλήκε
Δσναμική μνήμη προγράμμαηος Πνιιέο θνξέο, δελ γλσξίδνπκε εθ ησλ πξνηέξσλ πόζε κλήκε ζα ρξεηαζηεί ην πξόγξακκα καο. Αλ δεζκεύζνπκε πεξηζζόηεξε κλήκε από απηή πνπ ζα ρξεηαζηεί, θαηαλαιώλνπκε άζθνπα πόξνπο ηνπ Η/Υ Δηαθνξεηηθά πεξηνξίδνπκε ηελ ιεηηνπξγηθόηεηα ηνπ πξνγξάκκαηνο καο. Εθηόο από ηελ ζηαηηθή (θαζνιηθή) κλήκε (θαη ηελ ζηνίβα), ππάξρεη θαη ε δσναμική κλήκε. Ο πξνγξακκαηηζηήο κπνξεί λα δεζμεύζει θαη λα αποδεζμεύζει δπλακηθή κλήκε καηά ηην διάρκεια ηης εκηέλεζης, αλάινγα κε ηηο (κεηαβαιιόκελεο) ηξέρνπζεο απαηηήζεηο ηνπ πξνγξάκκαηνο. 2
Κύριες ζσναρηήζεις ( n void *malloc(size_t δέζκεπζε ελόο ζπλερόκελνπ ηκήκαηνο κλήκεο θαη επηζηξνθή δηεύζπλζεο ηεο αξρήο ηνπ ηκήκαηνο (αλ ( NULL δελ ππάξρεη αξθεηή κλήκε, επηζηξέθεηαη 0 / void free(void *adr) απνδέζκεπζε ηεο πεξηνρήο κλήκεο πνπ αξρίδεη ζηε δηεύζπλζε πνπ δίλεηαη ( n void *realloc(void *adr, size_t 3 αλαπξνζαξκνγή κεγέζνπο ηνπ ηκήκαηνο κλήκεο (κε πηζαλή αληηγξαθή ησλ πεξηερνκέλσλ) ε δηεύζπλζε ηνπ νπνίνπ δίλεηαη ζαλ παξάκεηξνο, θαη επηζηξνθή δηεύζπλζεο ηεο αξρήο ηνπ (λένπ) ηκήκαηνο (αλ δελ ( NULL ππάξρεη αξθεηή κλήκε, επηζηξέθεηαη 0 /
Στεηικές ζσναρηήζεις και βιβλιοθήκες #include <stdlib.h> 4 void *malloc(size_t size); void *calloc(size_t n, size_t size); void *realloc(void *p, size_t size); int free(void *p); #include <memory.h> void *memcpy(void *dst, const void *src, size_t n); void memset(void *p, int c, size_t n); int memcmp(const void *p1, const void *p2, size_t n); #include <string.h> char *strdup(const char *s);
Φρήζη δσναμικής μνήμης Οη ξνπηίλεο δηαρείξηζεο δπλακηθήο κλήκεο δελ γλσξίδνπλ ηίποηα ζρεηηθά κε ηνπο ηύπνπο ησλ δεδνκέλσλ πνπ ρξεζηκνπνηεί ην πξόγξακκα. Η διεύθσνζη ποσ επιζηρέθεηαι τρηζιμοποιείηαι με αποκλειζηική εσθύνη ηοσ προγραμμαηιζηή. Κιαζηθή ρξήζε: δέζκεπζε ρώξνπ πνπ αληηζηνηρεί ζην μέγεθος ελόο αληηθεηκέλνπ ηύποσ Τ θαη αλάζεζε ηεο δηεύζπλζεο (κε type casting) ζε κηα κεηαβιεηή ηύπνπ δείκηη-ζε-τ γηα ειεγρόκελε πξόζβαζε ζηελ κλήκε. Ο πξνγξακκαηηζηήο είλαη ππεύζπλνο γηα ηελ αποδέζμεσζη δπλακηθήο κλήκεο πνπ δελ ρξεζηκνπνηεί ην πξόγξακκα Δηαθνξεηηθά ππάξρεη πεξίπησζε ηεξκαηηζκνύ ιόγσ κε επάξθεηαο κλήκεο. 5
Έλεγτος ηιμής ποσ επιζηρέθεηαι Οη malloc θαη realloc επηζηξέθνπλ NULL αλ δελ κπνξεί λα δεζκεπηεί όζε κλήκε δεηήζεθε. Η ηηκή επηζηξνθήο πξέπεη λα ειέγρεηαη (απηό δελ γίλεηαη ζηα παξαδείγκαηα γηα νηθνλνκία ρώξνπ). Δηαθνξεηηθά, αλ ε ηηκή NULL αλαηεζεί ζε δείθηε, ε επόκελε αλαθνξά ζηε κλήκε κέζσ ηνπ δείθηε ζα νδεγήζεη ζε ηεξκαηηζκό ηνπ πξνγξάκκαηνο. Πρόβλημα 1: κπνξεί λα κελ επηζπκνύκε έλα ηέηνην «απόηνκν» ηεξκαηηζκό (π.ρ. ράζηκν δεδνκέλσλ). Πρόβλημα 2: δελ γλσξίδνπκε ζε πνηό ζεκείν ηνπ πξνγξάκκαηνο έγηλε απηή ε αλαθνξά. 6
#include <stdio.h> #include <stdlib.h> int main(int argc, char *argv[]) { int a,b,*sum; δέζκεσζε κλήκες από scanf("%d %d",&a,&b); sizeof(int) bytes 7 sum = (int *) malloc( sizeof(int) ); if (sum == NULL) { printf("no memory\n"); return(1); type cast ζε δείθηε-ζε-αθέραηο *sum = a+b; printf("%d\n",*sum); free(sum); return(0); αποδέζκεσζε κλήκες
Μονιμόηηηα δσναμικής μνήμης Η δπλακηθή κλήκε είλαη μόνιμη, δειαδή πθίζηαηαη θαζ όιε ηε δηάξθεηα ηεο εθηέιεζεο ηνπ πξνγξάκκαηνο. Δπλακηθή κλήκε πνπ δεζκεύεηαη κέζα από κηα ζπλάξηεζε παραμένει ελ ηζρύ κεηά ηελ θιήζε ηεο. Άιινο έλαο ηξόπνο επιζηροθής αποηελεζμάηων ζην πεξηβάιινλ θιήζεο κηαο ζπλάξηεζεο. Η ζπλάξηεζε δεζκεύεη δπλακηθή κλήκε όπνπ απνζεθεύεη ηα δεδνκέλα πνπ επηζπκεί λα επηζηξέςεη. Η ζπλάξηεζε επηζηξέθεη ζαλ απνηέιεζκα ηελ δηεύζπλζε ηνπ κπινθ ηεο κλήκεο. Τν πεξηβάιινλ θιήζεο ρξεζηκνπνηεί ηε δηεύζπλζε όπσο απαηηείηαη αλάζεζε ζε θαηάιιειε κεηαβιεηή δείθηε, απνδέζκεπζε κεηά ηελ ρξήζε, θιπ. 8
#include <stdio.h> #include <stdlib.h> int *add(int a, int b) { int *sum = (int *)malloc(sizeof(int)); *sum = a + b; return(sum); 9 int main(int argc, char *argv[]) { int a, b, *sum; scanf("%d %d", &a, &b); sum = add(a, b); printf("%d\n", *sum); free(sum); return(0);
#include <stdio.h> int *add(int a, int b) { int sum; sum = a + b; return(&sum); /* αυτό είναι λάθος! */ 10 int f(int a, int b) { int sum = 0; int main(int argc, char *argv[]) { int a, b, *sum; scanf("%d %d",&a, &b); sum = add(a, b); f(a, b); printf("%d\n", *sum); return(0);
#include <stdio.h> #include <stdlib.h> char *strappend(const char *s1, const char *s2) { int i,j,len1,len2; char *s3; for (len1=0; s1[len1]!='\0'; len1++); for (len2=0; s2[len2]!='\0'; len2++); s3=(char *)malloc((len1+len2+1)*sizeof(char)); (++ i for (i=0; i<len1; s3[i]=s1[i]; (++ j++,i for (j=0; j<len2; s3[i]=s2[j]; s3[i]='\0'; return(s3); 11 int main(int argc, char *argv[]) { char s1[64],s2[64],*s3; scanf("%63s %63s",s1,s2); s3=strappend(s1,s2); printf("%s plus %s is %s\n",s1,s2,s3); free(s3); return(0);
Δσναμικοί πίνακες Με ρξήζε δπλακηθήο κλήκεο κπνξεί λα πινπνηεζνύλ δσναμικοί πίλαθεο, ην κέγεζνο ησλ νπνίσλ νξίδεηαη (αιιάδεη) καηά ηην διάρκεια ηεο εθηέιεζεο. 1. Δεζκεύεηαη κε malloc ή realloc δπλακηθή κλήκε κεγέζνπο n*sizeof(t), θαη ε δηεύζπλζε πνπ επηζηξέθεηαη απνζεθεύεηαη ζε κεηαβιεηή δείθηε ζε Τ. 2. Αλ ην n απνδεηρζεί κηθξό ή κεγάιν, ρξεζηκνπνηείηαη ε realloc γηα ηελ επέθηαζε / απνθνπή ηνπ πίλαθα. 3. Όηαλ ν πίλαθαο δελ ρξεηάδεηαη, απνδεζκεύεηαη ε κλήκε πνπ ρξεζηκνπνηείηαη κε ηελ free. 12
#include <stdlib.h> char *t; int tlen; void init_array() { t=null; tlen=0; 13 void trim_array(int len) { t=(char*)realloc(t, len*sizeof(char)); tlen=len; void write_array(int pos, char v) { ( tlen if (pos >= trim_array(pos+1); t[pos]=v; char read_array(int pos) { return(t[pos]); void destroy_array() { trim_array(0); t=null;
#include <stdlib.h> void **t; int tlen; void init_array() { t=null; tlen=0; 14 void trim_array(int len) { t=(void**)realloc(t, len*sizeof(void*)); tlen=len; void write_array(int pos, void *v) { ( tlen if (pos >= trim_array(pos+1); t[pos]=v; void *read_array(int pos) { return(t[pos]); void destroy_array() { trim_array(0); t=null;
int main(int argc, char *argv[]) { char s[256],*p; int i; init_array(); i = 0; do { scanf("%255s",s); write_array(i,(void*)strdup(s)); i++; while (strcmp(s,"end")); for (--i; i>=0; i--) { p = (char*)read_array(i); printf("%s\n",p); free(p); destroy_array(); return(0); ειεσζερώλεη ηε (δσλακηθή) κλήκε ποσ δεζκεύηεθε δεκηοσργεί αληίγραθο ηοσ αιθαρηζκεηηθού ( κλήκε (ζε δσλακηθή type cast (από char * ποσ επηζηρέθεηαη) ζε void * ποσ αλακέλεη ε ζσλάρηεζε write type cast (από void * ποσ επηζηρέθεηαη) ζε char * ποσ είλαη ο ηύπος ηες p 15
Δσναμική δέζμεσζη δομών δεδομένων Με ρξήζε δπλακηθήο κλήκεο κπνξεί λα δεζκεπηνύλ ρώξνη κλήκεο γηα ηελ απνζήθεπζε struct/union θαηά ηελ δηάξθεηα ηεο εθηέιεζεο ηνπ πξνγξάκκαηνο. Η δέζκεπζε θαη απνδέζκεπζε δπλακηθήο κλήκεο αθνινπζεί ηνπο ίδηνπο θαλόλεο πνπ ηζρύνπλ θαη γηα ηνπο βαζηθνύο ηύπνπο δεδνκέλσλ. Καηά ηελ δέζκεπζε πξέπεη λα δίλεηαη ην επηζπκεηό κέγεζνο, κέζσ sizeof, θαη ε δεζκεπκέλε κλήκε πξέπεη λα απνδεζκεύεηαη όηαλ δελ είλαη αλαγθαία. Πξόζβαζε ζηελ δπλακηθά δεζκεπκέλε κλήκε γίλεηαη κέζσ κεηαβιεηώλ δεηθηώλ πνπ πξέπεη αξρηθνπνηνύληαη θαηάιιεια. λα 16
Παρένθεζη (βάζη δεδομένων με δσναμικό ( πίνακα
Πρόβλημα Ζεηνύκελν: επηζπκνύκε λα δηαρεηξηζηνύκε ηα πεξηερόκελα ηεο ηειεθσληθήο καο αληδέληαο, κε αληίζηνηρεο ιεηηνπξγίεο πξνζζήθεο, απνκάθξπλζεο θαη αλαδήηεζεο. Πξνζέγγηζε νξίδνπκε δνκή θαηάιιειε γηα ηελ νκαδνπνίεζε ησλ δεδνκέλσλ πνπ αλήθνπλ ζε κηα «εηζαγσγή» θξαηάκε ηα δεδνκέλα ζε ανοιτηό πίλαθα από ηέηνηεο δνκέο Οη ιεηηνπξγίεο πξέπεη λα πινπνηεζνύλ ζύκθσλα κε θαηάιιειεο εζωηερικές ζσμβάζεις γηα ηελ δηαρείξηζε ησλ ζηνηρείσλ ηνπ πίλαθα. 18
ηο κέγεζος ηοσ πίλαθα αιιάδεη δυναμικά ως ζσλέπεηα ηωλ ιεηηοσργηώλ προζζήθες ή/θαη αποκάθρσλζες δεδοκέλωλ 19 αποκάθρσλζε n προζζήθε ζηοητεία σπό τρήζε
int main(int argc, char *argv[]) { int sel,res; char name[64],phone[64]; phonebook_init(); do { printf("1. Add\n"); printf("2. Remove\n"); printf("3. Find\n"); printf("4. Exit\n"); printf("> "); scanf("%d",&sel); switch (sel) { case 1: { printf("name & phone:"); scanf("%63s %63s",name,phone); res=phonebook_add(name,phone); printf("res=%d\n",res); break; case 2: { printf("name:"); scanf("%63s",name); phonebook_rmv(name); break; case 3: { printf("name:"); scanf("%63s",name); res=phonebook_find(name,phone); printf("res=%d\n",res); if (res) { printf("phone: %s\n",phone); break; while (sel!=4); return(0); 20
#include <stdio.h> #include <string.h> #include <stdlib.h> typedef struct { char name[64]; char phone[64]; Entry; Entry *entries; int size; void phonebook_init() { entries=null; size=0; ε κεηαβιεηή entries είλαη δείκηης ζε Entry, θαη τρεζηκεύεη ως ε αρτή ελός δσλακηθού πίλαθα από δοκές Entry 21
int internal_find(const char name[]) { int i; for (i=0; (i<size) && (strcmp(entries[i].name,name)); i++); return(i); 22 int phonebook_find(const char name[], char phone[]) { int pos; pos=internal_find(name); ( size if (pos == return(0); else { strcpy(phone,entries[pos].phone); return(1); void phonebook_rmv(const char name[]) { int pos; pos=internal_find(name); if (pos < size) { memcopy(&entries[pos],&entries[--size],sizeof(entry)); entries=(entry *) realloc(entries,size*sizeof(entry));
int phonebook_add(const char name[], const char phone[]) { int pos; pos=internal_find(name); 23 if (pos < size) { strcpy(entries[pos].phone,phone); return(-1); /* replace */ size++; entries=(entry *) realloc(entries,size*sizeof(entry)); strcpy(entries[size-1].name,name); strcpy(entries[size-1].phone,phone); return(1); /* done */
Στόλιο Κάζε θνξά πνπ απνκαθξύλεηαη έλα ζηνηρείν, γίλεηαη κηα αληηγξαθή δεδνκέλσλ από ηελ ηειεπηαία ζέζε ηνπ πίλαθα ζηελ ζέζε πνπ ειεπζεξώζεθε. Απηό κπνξεί λα είλαη ηδηαίηεξα ρξνλνβόξν (αλ ηα πεξηερόκελα ηεο δνκήο είλαη κεγάια ζε κέγεζνο). Μπνξνύκε λα απνθύγνπκε απηή ηελ αληηγξαθή δεδνκέλσλ, ρξεζηκνπνηώληαο έλα πίλαθα από δείκηες ζε (απηόλνκα) αληηθείκελα δεδνκέλσλ ε κλήκε ησλ νπνίσλ δεζκεύεηαη θαη απνδεζκεύεηαη δπλακηθά θαηά ηελ πξνζζήθε / απνκάθξπλζε ηνπο. Με απηό ην ηξόπν ν πίλαθαο κεηαηξέπεηαη ζε έλα επξεηήξην από δείθηεο ζε αληηθείκελα, επηηξέπνληαο πνιύ γξήγνξεο «αληηκεηαζέζεηο» ζηνηρείσλ. 24
n 25
#include <stdio.h> #include <string.h> #include <stdlib.h> 26 typedef struct { char name[64]; char phone[64]; Entry; ε κεηαβιεηή entries είλαη δείκηης ζε δείκηη ζε Entry, θαη τρεζηκεύεη ως ε αρτή ελός δσλακηθού πίλαθα από δείκηες ζε Entry Entry **entries; int size; void phonebook_init() { entries=null; size=0;
int internal_find(const char name[]) { int i; for (i=0; (i<size) && (strcmp(entries[i]->name,name); i++); return(i); 27 int phonebook_find(const char name[], char phone[]) { int pos; pos=internal_find(name); ( size if (pos == return(0); else { strcpy(phone,entries[pos]->phone); return(1); void phonebook_rmv(const char name[]) { int pos; pos=internal_find(name); if (pos < size) { free(entries[pos]); entries[pos] = entries[--size]; entries=(entry **) realloc(entries,size*sizeof(entry *));
int phonebook_add(const char name[], const char phone[]) { int pos; pos=internal_find(name); 28 if (pos < size) { strcpy(entries[pos]->phone,phone); return(-1); /* replace */ size++; entries=(entry **) realloc(entries,size*sizeof(entry *)); entries[size-1] = (Entry *)malloc(sizeof(entry)); strcpy(entries[size-1]->name,name); strcpy(entries[size-1]->phone,phone); return(1); /* done */
Παρένθεζη (βάζη δεδομένων με δσναμικό ( πίνακα