Δημοσιεύτηκε: 12 Σεπ 2011, 15:49
από Star_Light
migf1 έγραψε:Καλημέρα,

Star_Light έγραψε:εφτασα και στο τελευταιο step πλεον πριν αρχισω να κοιταω τον κωδικα σου....

Δομες και δείκτες (μεσα σε συναρτηση)

Spoiler: show
Κώδικας: Επιλογή όλων

#include <stdio.h>
#define N 254 + 1
typedef struct person
{
int age;
char name[N];
char surname[N];
} kostas ;

void struct_function(kostas *p);


int main(void)
{

kostas someone , *p;

p=&someone;

struct_function(p) ;

return 0;
}

void struct_function(kostas *p)
{


printf("Dwse to onoma sou: ");
fgets(p->name,254,stdin);

printf("Dwse to epwnumo sou: ");
fgets(p->surname,254,stdin);

printf("Dwse tin ilikia sou: ");
scanf("%d",&(*p).age);


printf("========================================");

printf("\nTo onoma pou edwses einai: %s",p->name);
printf("H ilikia pou edwses einai: %d",p->age);
printf("\nTo epwnimo pou edwses einai: %s",p->surname);

}

Έτσι όπως έχεις γράψει τον κώδικα μπερδεύονται τα πράγματα, ενώ είναι πολύ πιο απλά! Ο κώδικάς σου για να αντιστοιχεί και στην ανθρώπινη σκέψη και άρα να είναι μακράν πιο κατανοητός πρέπει να γραφτεί κάπως έτσι...

Κώδικας: Επιλογή όλων

#include <stdio.h>
#include <stdlib.h> // για atoi()

// Macros

#define MAXSLEN (254 + 1) // MAXimum String LENgth

// Πρόσθετοι Τύποι Δεδομένων

typedef struct person // ορισμός δομής person ως πρόσθετο τύπο
{ // με το όνομα Person (λόγω του typedef)
char name[ MAXSLEN ]; // ... 1ο πεδίο της δομής
char surname[ MAXSLEN ]; // ... 2ο πεδίο της δομής
int age; // ... 3ο πεδίο της δομής
} Person; // το όνομα του πρόσθετου τύπου

// Πρότυπα Συναρτήσεων

char *s_getflushed(char *s, size_t len); // αντί fgets, για να μην κρατάει το '\n'
void read_person( Person *someone ); // για διάβασμα των πεδίων της someone
void print_person( Person someone ); // για τύπωμα των πεδίων της someone

// -------------------------------------------------------------------------------
int main( void )
{
Person someone; // η someone είναι μεταβλητή τύπου Person

read_person( &someone ); // πέρασμα της someone by reference
print_person( someone ); // πέρασμα της someone by value

return 0;
}
// -------------------------------------------------------------------------------
char *s_getflushed(char *s, size_t len)
{
char *cp;
for (cp=s; (*cp=getc(stdin)) != '\n' && (cp-s) < len-1; cp++ )
;

if ( *cp != '\n') { // len reached withoutn '\n'
*cp = '\0'; // null terminate s and
while (getchar() != '\n') // flush remaining chars
;
}
else // '\n' found
*cp = '\0'; // null-terminate

return s;
}
// -------------------------------------------------------------------------------
void read_person( Person *someone ) // by reference πέρασμα της someone
{ // άρα χρήση του -> για τα πεδία της
char inbuf[ 254+1 ] = {'\0'};

printf("Dwse to onoma sou: ");
s_getflushed( someone->name, MAXSLEN );

printf("Dwse to epwnumo sou: ");
s_getflushed( someone->surname, MAXSLEN );

printf("Dwse tin ilikia sou: ");
s_getflushed( inbuf, MAXSLEN );
someone->age = atoi( inbuf );

return;
}
// -------------------------------------------------------------------------------
void print_person( Person someone ) // by value πέρασμα της someone
{ // άρα χρήση τελείας για τα πεδία της
puts("========================================");

printf("To onoma pou edwses einai: %s\n", someone.name);
printf("To epwnimo pou edwses einai: %s\n", someone.surname);
printf("H ilikia pou edwses einai: %d\n", someone.age);

putchar('\n');

return;
}

Τον γέμισα με Ελληνικά σχόλια ελπίζοντας πως ξεκαθαρίζει τα πράγματα και μπορεί να χρησιμοποιηθεί και ως γρήγορος οδηγός για φρεσκάρισμα μνήμης. Εδώ και με syntax-highlighting: http://ideone.com/tw7BS

Ορίζουμε μια δομή struct person, την μετατρέπουμε σε πρόσθετο τύπο Person με το typedef και ορίζουμε μια μεταβλητή someone να είναι τύπου Person. Κατόπιν περνάμε την someone by reference στη συνάρτηση read_person() επειδή θέλουμε να διατηρηθούν οι αλλαγές που θα γίνουν στα πεδία της (διαβάζουμε νέες τιμές για τα πεδία). By reference σημαίνει πως μέσα στη συνάρτηση έχει οριστεί ως δείκτης, άρα εκεί μέσα όταν θέλουμε να αναφερθούμε σε κάποιο πεδίο της το κάνουμε με το σύμβολο ->
Τέλος περνάμε την someone by value στη συνάρτηση print_person() επειδή δεν θα αλλάξουμε τιμές στα πεδία της μέσα στη συνάρτηση. By value σημαίνει πως μέσα στη συνάρτηση ΔΕΝ έχει οριστεί ως δείκτης, άρα εκεί μέσα όταν θέλουμε να αναφερθούμε σε κάποιο πεδίο της το κάνουμε με το σύμβολο της τελείας .

Με άλλα λόγια, σε επίπεδο main() η someone συμπεριφέρεται όπως οποιαδήποτε άλλη μεταβλητή και η μόνη διαφορά με τις κανονικές μεταβλητές είναι πως δεν έχει μια ενιαία τιμή, έχει επιμέρους τιμές στο καθένα από τα πεδία της.

Και μερικές συμβουλές για ευανάγνωστο κώδικα:

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

Π.χ...

Κώδικας: Επιλογή όλων

struct person {
char name[ MAXSLEN ];
char surname[ MAXSLEN ];
int age;
};
typedef struct person Person;

ή σε ένα μόνο βήμα...

Κώδικας: Επιλογή όλων

typedef struct person {
char name[ MAXSLEN ];
char surname[ MAXSLEN ];
int age;
} Person;


ΥΓ. Το (*p).age το γράφουμε: p->age και η διεύθυνσή του είναι: &p->age


ΚΑΤΑΛΑβα δηλαδη ετσι μπερδευεται καποιος που διαβαζει τον κωδικα μου επειδη ενω δεν κανω call by reference μεσα στην συναρτηση με τον τελεστη (->) ειναι σαν να δειχνω οτι κανω....

Οσο για το
migf1 έγραψε: Είναι δηλαδή σαν να με ρωτάς για ποιο λόγο προτιμάς γενικώς στους δείκτες τη γραφή: p αντί της: &(*p)


Και ομως το πιστευεις οτι εγω συμφωνω πιο πολυ με το &(*p) παρα με το p? Το p γιατι να το δεχθω σαν διευθυνση? Επειδη ετσι μου το οριζουν ή μου το λενε? Δεν εχω καποια αλλη ενδειξη... οταν παλιοτερα καποιος πηγε να μου εξηγησει τους δεικτες (πολυ παλιοτερα) μου ειχε πει οκ
οριζουμε int *p το p πλεον ειναι μεταβλητη δεικτη που φερει την διευθυνση ενω το * ειναι περιεχομενα....

ενω αντιθετως... στο
Κώδικας: Επιλογή όλων
&(*p)


το & ειναι τελεστης διευθυνσης και δινει την διευθυνση... ειναι αξιωμα. Δεν σου λεει ο αλλος ειναι δικο μου αξιωμα οποτε δεξου το και εσυ... καταλαβαινεις γενικα πως ειναι αξιωμα. Οκ? Απο την αλλη και το (*p) ειναι και αυτο γενικο αξιωμα οτι δινει το περιεχομενο αρα ολο μαζι
δηλαδη το &(*p) δινει την διευθυνση του περιεχομενου στο οποιο δειχνει ο δεικτης... ακριβως με αυτη τη διευθυνση που έχεις αρχικοποιησει και τον δεικτη στο να δειχνει... καταλαβαινεις τι λεω ή ειμαι για δεσιμο? :lol:

Και σχετικα με την ερωτηση

Κώδικας: Επιλογή όλων
struct_function(p)


Θα γινω πιο συγκεκριμενος... γιατι το καλεις ετσι??? Επειδη μεσα εχει την διευθυνση της δομης (στην οποια εχουμε βαλει να δειχνει ο δεικτης) αυτο ηθελα να ξεκαθαρισω.