PDA

Επιστροφή στο Forum : Διαχείριση βάσης με link list ( C )



leequid
12-05-09, 21:20
Καλησπέρα παιδία,

έχω το εξής θέμα στην C:
(Δεν έχω ιδιαίτερη εμπειρία και δυσκολεύομαι αρκετά να καταλάβω τι γίνεται..)

Θέλω να δημιουργήσω στα πλαίσια εργασίας, μία database "όνομα - τηλεφωνο", όπου για κάθε όνομα αντιστοιχούν διάφορα τηλέφωνα: κινητό σταθερό κλπ. Ο προτεινόμενος τρόπος εργασίας είναι κυκλική linked list.
Έχω ήδη δημιουργήσει την λίστα ονομάτων η οποία δουλεύει, αλλά δεν ξέρω πως θα εισάγω τα τηλέφωνα στην αντιστοιχη δομή.
Παραθέτω ενδεικτικό κώδικα:




struct phone_list {
char mobile;
struct phone_list * next;
struct phone_list * prev;
};

struct name_list {
int name;
struct phone_list * phone;
struct name_list * next;
struct name_list * prev;
};




typedef struct name_list node;
typedef struct phone_list phone;





switch(option)
{
case 'a':

printf("\nDwste onoma?: ");
scanf("%d",&name_temp);
printf("\nDwste Kinito?: ");
scanf("%d",&phone_temp);
temp = (node *)malloc(sizeof(node));
temp->name = name_temp;

(Εδω πρεπει να εισαγω κατι για να
αντιστοιχιζει το Mobile στο Name ..)

append (temp) ;
break;



Η συναρτηση append λειτουργει σωστα.



void append(node *temp) {
if(head == NULL) {
head = temp;
temp->prev = NULL;
} else {
tail->next = temp;
temp->prev = tail;
}

tail = temp;
temp->next = NULL;
}


Βοηθήστε τον νεο:oops: και ατζαμή προγραμματιστή :p

nikospara
12-05-09, 22:18
Εν γένει το έχεις πιάσει...

Χονδρικά: Φτιάξε άλλη μια σαν την append(), την:



appendPhone(
node *node,
struct phone_list *phone
)


Δές ότι παίρνει δείκτη πρός το node στο οποίο θες να εισάγεις το τηλέφωνο. Η λογική της είναι ίδια με την append, μόνο που αντί head θα βάλεις node->next και αντί tail, node->prev.

Στο σημείο που ρωτάς, απλά κάνε άλλο ένα malloc(sizeof struct phone_list) για να δημιουργήσεις την εγγραφή στη λίστα τηλεφώνων. Βάλε μέσα και το τηλέφωνο και μετά δώσε την στην appendPhone().


ΠΡΟΣΟΧΗ! Το παρακάτω:



char name_temp[100];
...
scanf("%d",&name_temp);
...
temp->name = name_temp;


Θα σου δημιουργήσει πρόβλημα, αν είναι όντως έτσι η δήλωση της name_temp. (Στο λέω, για καλό και για κακό.) Το σωστό:



char *name_temp = (char *) malloc(100 * sizeof(char));

WagItchyef
12-05-09, 22:50
char *name_temp = (char *) malloc(100 * sizeof(char));


Στην ISO C δεν χρειάζονται casting οι κλήσεις στην malloc(), στην calloc(), και στην realloc().

Άλλο ένα misconception που μου θύμισες, και θα το προσθέσω στην σελίδα "Common misconceptions about C":

http://www.cpp-software.net/documents/c_misconceptions.


Οι ακόλουθοι C κώδικες είναι απολύτως σωστοί και ισοδύναμοι με τον επάνω:



char *name_temp = malloc(100);



Edited: Διόρθωσα ένα λάθος.


char *name_temp = malloc(100* sizeof(*name_temp));



Ευτυχώς που μου θύμισες αυτό το misconception πάντως, γιατί είναι ευρέως διαδεδομένο.

nikospara
13-05-09, 11:45
Στην ISO C δεν χρειάζονται casting οι κλήσεις στην malloc(), στην calloc(), και στην realloc().

Α, ωραία, μάθαμε κάτι. Έχω καιρό να χρησιμοποιήσω C και μου έχουν μείνει οι συνήθειες από τους παλιούς compilers.

........Auto merged post: nikospara πρόσθεσε 2 λεπτά και 33 δευτερόλεπτα αργότερα ........

...Αλλά αυτό μάλλον δεν ισχύει (θα δεσμεύσεις μνήμη για έναν χαρακτήρα):


char *name_temp = malloc(sizeof(*name_temp));

Μάλλον εννοείς 100*sizeof(...)

WagItchyef
13-05-09, 13:08
Α, ωραία, μάθαμε κάτι. Έχω καιρό να χρησιμοποιήσω C και μου έχουν μείνει οι συνήθειες από τους παλιούς compilers.

........Auto merged post: nikospara πρόσθεσε 2 λεπτά και 33 δευτερόλεπτα αργότερα ........

...Αλλά αυτό μάλλον δεν ισχύει (θα δεσμεύσεις μνήμη για έναν χαρακτήρα):


char *name_temp = malloc(sizeof(*name_temp));

Μάλλον εννοείς 100*sizeof(...)

Ναι έχεις δίκιο, τυπογραφικό λάθος. Έκανα edit το μήνυμα και το διόρθωσα. Ευχαριστώ για την επισήμανση.

leequid
14-05-09, 19:23
Παιδια ευχαριστώ πολυ!

leequid
20-05-09, 19:00
Εν γένει το έχεις πιάσει...

Χονδρικά: Φτιάξε άλλη μια σαν την append(), την:



appendPhone(
node *node,
struct phone_list *phone
)
Δές ότι παίρνει δείκτη πρός το node στο οποίο θες να εισάγεις το τηλέφωνο. Η λογική της είναι ίδια με την append, μόνο που αντί head θα βάλεις node->next και αντί tail, node->prev.

Στο σημείο που ρωτάς, απλά κάνε άλλο ένα malloc(sizeof struct phone_list) για να δημιουργήσεις την εγγραφή στη λίστα τηλεφώνων. Βάλε μέσα και το τηλέφωνο και μετά δώσε την στην appendPhone().





node *temp=NULL;
phone *tempp=NULL;




void appendphone(node *temp,phonenumber *tempp)
{

Idia me parapanw..

temp->phone_list = tempp;
}


Πως ομως θα προσθετω-εμφανιζω νεα τηλεφωνα;

Για 1-1 εγγραφη:


for(temp = head; temp != NULL; temp = temp->next)
{
printf("%d - %c\n", temp->name,(temp->phone_number)->mobile);
}

nikospara
20-05-09, 19:45
Πρόσεξε, το temp->name είναι string, οπότε μέσα στο format string θές %s αντί %d. (Τώρα είδα ότι και στην scanf το διαβάζεις με %d... Δε θα έπρεπε.)

Αν το phone_number είναι δείκτης σε struct phone_list, το bold σου θα είναι: temp->phone_number->mobile

leequid
20-05-09, 19:59
Εχεις δικιο για την scanf.Εκ παραδρομης λαθος..

Αυτο που προσπαθω να σχεδιασω ειναι πως θα βαζω πολλαπλα τηλεφωνα σε εναν χρηστη και τελικα πολλαπλα τηλεφωνα σε ολους τους χρηστες..

nikospara
20-05-09, 21:01
Αν ένας χρήστης μπορεί να έχει άγνωστο αριθμό τηλεφώνων, τότε θα πρέπει και αυτό να υλοποιηθεί με μια δομή μεταβλητού μεγέθους, όπως η λίστα.

Επειδή το πράγμα έχει αρχίσει και μπλέκεται οι συμβουλές μου είναι οι εξής:

Βρές ή φτιάξε συναρτήσεις που θα χειρίζονται λίστες, ασχέτως δεδομένων. Πχ, αντί για struct phone_list, struct name_list κλπ φτιάξε μία λίστα σαν:



typedef struct _ListNode {
void *data;
struct _ListNode *next;
struct _ListNode *prev;
} ListNode;

typedef struct _List {
ListNode *head;
ListNode *tail;
// άλλα στοιχεία, πχ αριθμός κόμβων
// ... οι συναρτήσεις σου όμως πρέπει να διαχειρίζονται και
// αυτά τα στοιχεία
} List;


Το void * μπορεί να δεχθεί δείκτη σε ότι τύπο θές, αρκεί να κάνεις cast όταν το χρησιμοποιείς. (Βέβαια χάνεις την type safety που σου δίνει ο compiler. Εδώ είναι χρήσιμα τα templates/generics κλπ, αλλά αυτό άλλη ιστορία.) Παράδειγμα χρήσης:



// ορισμοί
List *list_create() { ...υλοποίηση...}
void list_add_node(List *list, void *data) { ...υλοποίηση...}

// δημιουργία και προσθήκη κόμβου
List *mylist = list_create();
struct {
..ότι θές...
} *otinanai = ...
list_add_node(otinanai);

// διάσχιση:
ListNode *cur = mylist->head;
if( cur != NULL ) do {
...κάνε κάτι με το cur...
cur = cur->next;
} while( cur != mylist->head );


Βάσει αυτών, όρισε το μοντέλο σου, πχ (πρόχειρες σκέψεις):



typedef struct _PhoneBook {
List *people; // data: Person
} PhoneBook;

typedef struct _Person {
char *name;
...άλλες πληροφορίες...
List *phones; // data: Phone
} Person;

typedef struct _Phone {
char *type;
char *phone;
} Phone;


Για κάθε παραπάνω δομή, καλό θα ήταν να έχεις συναρτήσεις που τις διαχειρίζονται, πχ:



PhoneBook *phonebook_create() {
PhoneBook *ret = malloc(sizeof(PhoneBook));
ret->people = list_create();
return ret;
}

void phonebook_destroy(PhoneBook *pb) {
list_destroy(pb->people);
free(pb);
}


Ούφ! Τα παραπάνω παραδείγματα είναι απλοϊκά, αλλά θα σε βοηθήσουν να δομήσεις το πρόγραμμά σου. Η δόμηση ενός προγράμματος είναι πιο σημαντική στις περισσότερες περιπτώσεις από το ίδιο το γράψιμο.

Καλή συνέχεια!


Παράδειγμα απλοϊκότητας των παραπάνω είναι ότι δεν έχουμε συζητήσει καθόλου πώς χειρίζεσαι την αποδέσμευση μνήμης των κόμβων μιας λίστας, όταν αυτή σβήνεται. Αν κάνεις free() σε κάθε κόμβο, κινδυνεύεις να έχεις κάποιον pointer σε αυτόν κάπου αλλού που θα μείνει ξεκρέμαστος. Αν δεν κάνεις, κινδυνεύεις να έχεις memory leaks.

Σε αυτά βοθάει η C++ και, πολύ περισσότερο, τα συστήματα με αυτόματη διαχείριση μνήμης. Αυτά όμως σε άλλο επεισόδιο.

leequid
21-05-09, 01:04
Σε ευχαριστω παρα πολυ για τον χρονο σου!Αυριο θα τα μελετησω :)

WagItchyef
21-05-09, 11:39
Είναι απαραίτητο να χρησιμοποιήσεις linked list; Κάνεις ταξινόμηση κατά όνομα κατά την διάρκεια εκτέλεσης του προγράμματος;

leequid
21-05-09, 19:29
Εχω ηδη φτιαξει μια linked list που κανει ταξινομηση,μονο που ειναι single.Θα πρεπει να την προσαρμοσω για double

@ ADSLgr.com All rights reserved.