Δημοσιεύτηκε: 30 Αύγ 2011, 13:07
Πω πω ρε συ, πως τα καταφέρνεις πάντα και μπλέκεις έτσι;;;;;;;;;;;;;;;;;;;; 
Λοιπόν, κοίτα τι θα κάνουμε, θα σου δώσω εγώ τον κώδικα για αντιγραφή χωρίς το n ( που βασικά είναι η στάνταρ συνάρτηση strcpy(char *dst, char *src) ) και μετά εσύ θα φτιάξεις την strncpy(char *dst, char *src, size_t n)... τα πράγματα είναι πολύ πιο απλά από αυτά που κάνεις
Ξεκινάμε ορίζοντας στη main 2 strings src και dst τα οποία τα ορίζουμε να έχουν ΙΔΙΟ μέγιστο μήκος (το κακό με την strcpy() είναι πως δεν ελέγχει αν το src χωράει στο dst, οπότε θα τα βάλουμε να έχουν ίδιο μέγιστο μήκος.... όχι πως η strncpy ελέγχει, αλλά εκείνη τουλάχιστον μας δίνει την ευκαιρία να το κοντρολάρουμε μέσω του ορίσματος n):
Ας ονομάσουμε τη συνάρτησή μας s_copy. Μια υλοποίησή της χωρίς δείκτες μπορεί να γίνει κάπως έτσι...
Μπορούμε τώρα να αντιγράψουμε το src στο dst κάπως έτσι:
το οποίο θα μας τυπώσει:
Κοιτώντας τώρα την τεκμηρίωση της κανονικής strcpy παρατηρούμε πως δεν είναι void, αλλά επιστρέφει ότι περιέχει το dst μετά την αντιγραφή. Οπότε ας το κάνουμε κι εμείς έτσι...
Αυτό λειτουργικά δεν επηρεάζει το πως τη χρησιμοποιήσαμε προηγουμένως που ήταν void, αλλά μας δίνει μια έξτρα λειτουργικότητα στο ότι τώρα μπορούμε να τη χρησιμοποιήσουμε απευθείας μέσα στην printf (ή σε όποια άλλη συνάρτηση δέχεται ως όρισμα string) σαν να ήταν το αλλαγμένο dst.
Π.χ....
που θα τυπώσει...
ή αν δεν σου αρέσουν τα πολλά λόγια
...
που θα τυπώσει...
Αν τώρα θέλεις να συμπτύξεις τον κώδικα της συνάρτησης (ξέρω γω για να πουλήσεις μούρη στην παρέα...
) μπορείς να την αλλάξεις σε κάτι τέτοιο...
ή ακόμα κι έτσι...
Όλες αυτές οι υλοποιήσεις μπορούν να γίνουν και με δείκτες, π.χ...
η οποία συμπτυγμένη μπορεί να γραφτεί κι έτσι...
Σου έγραψα διάφορες παραλλαγές της ίδιας συνάρτησης για να δείξω αφενός πως είναι πολύ πιο εύκολη από ότι ενδεχομένως πίστευες κι αφετέρου πως μπορείς να τη κάνεις όσο απλή ή όσο πολύπλοκη θέλεις. Στον προγραμματισμό ο χρυσός κανόνας είναι να γράφουμε όσο πιο λιτό κώδικα μπορούμε και κυρίως όσο πιο ευανάγνωστο γίνεται. Πρώτα για να τον καταλαβαίνουμε οι ίδιοι όταν χρειαστεί να τον ξαναδιαβάσουμε μετά από καιρό και ύστερα για να τον καταλαβαίνουν και οι άλλοι που ενδεχομένως θα χρειαστεί να τον διαβάσουν.
Και ΠΑΝΤΑ να τον συνοδεύουμε με σχόλια, ειδικά στα σημεία που ξεφεύγουν από τα τετριμμένα.
Προφανώς και δεν είναι υποχρεωμένος κανείς να χρησιμοποιήσει δείκτες για την διαχείριση των strings αν τον δυσκολεύουν. Μπορεί κάλλιστα να τα διαχειριστεί κάνοντάς indexing τους χαρακτήρες τους με απλούς μετρητές (i, j, κλπ)
Ελπίζω να μπορέσεις τώρα να φτιάξεις τη s_ncopy( char *dst, char *src, const size_t n) χωρίς να μπλέκεις με όλα αυτά που μπλέκεις
Λοιπόν, κοίτα τι θα κάνουμε, θα σου δώσω εγώ τον κώδικα για αντιγραφή χωρίς το n ( που βασικά είναι η στάνταρ συνάρτηση strcpy(char *dst, char *src) ) και μετά εσύ θα φτιάξεις την strncpy(char *dst, char *src, size_t n)... τα πράγματα είναι πολύ πιο απλά από αυτά που κάνεις
Ξεκινάμε ορίζοντας στη main 2 strings src και dst τα οποία τα ορίζουμε να έχουν ΙΔΙΟ μέγιστο μήκος (το κακό με την strcpy() είναι πως δεν ελέγχει αν το src χωράει στο dst, οπότε θα τα βάλουμε να έχουν ίδιο μέγιστο μήκος.... όχι πως η strncpy ελέγχει, αλλά εκείνη τουλάχιστον μας δίνει την ευκαιρία να το κοντρολάρουμε μέσω του ορίσματος n):
- Κώδικας: Επιλογή όλων
int main( void )
{
char src[15+1] = "12345"; // μέγιστο μήκος 15+1, τρέχον μήκος 5+1
char dst[15+1] = ""; // μέγιστο μήκος 15+1, τρέχον μήκος 0+1
...
return 0;
}
Ας ονομάσουμε τη συνάρτησή μας s_copy. Μια υλοποίησή της χωρίς δείκτες μπορεί να γίνει κάπως έτσι...
- Κώδικας: Επιλογή όλων
void s_copy( char *dst, char *src )
{
register int i = 0;
while ( src[i] != '\0' )
{
dst[i] = src[i];
i++;
}
return;
}
Μπορούμε τώρα να αντιγράψουμε το src στο dst κάπως έτσι:
- Κώδικας: Επιλογή όλων
...
printf( "Before: dst = %s, src = %s\n", dst, src );
s_copy( dst, src );
printf( "After : dst = %s, src = %s\n", dst, src );
...
το οποίο θα μας τυπώσει:
- Κώδικας: Επιλογή όλων
Before: dst = , src = 12345
After : dst = 12345, src = 12345
Κοιτώντας τώρα την τεκμηρίωση της κανονικής strcpy παρατηρούμε πως δεν είναι void, αλλά επιστρέφει ότι περιέχει το dst μετά την αντιγραφή. Οπότε ας το κάνουμε κι εμείς έτσι...
- Κώδικας: Επιλογή όλων
char *s_copy( char *dst, char *src )
{
register int i = 0;
while ( src[i] != '\0' )
{
dst[i] = src[i];
i++;
}
return dst;
}
Αυτό λειτουργικά δεν επηρεάζει το πως τη χρησιμοποιήσαμε προηγουμένως που ήταν void, αλλά μας δίνει μια έξτρα λειτουργικότητα στο ότι τώρα μπορούμε να τη χρησιμοποιήσουμε απευθείας μέσα στην printf (ή σε όποια άλλη συνάρτηση δέχεται ως όρισμα string) σαν να ήταν το αλλαγμένο dst.
Π.χ....
- Κώδικας: Επιλογή όλων
...
printf( "Before: dst = %s\n", dst );
printf( "After : dst = %s\n, s_copy( dst, src) );
...
που θα τυπώσει...
- Κώδικας: Επιλογή όλων
Before: dst =
After : dst = 12345
ή αν δεν σου αρέσουν τα πολλά λόγια
- Κώδικας: Επιλογή όλων
...
// Before
puts( dst );
// After
puts( s_copy( dst, src) );
...
που θα τυπώσει...
- Κώδικας: Επιλογή όλων
12345
Αν τώρα θέλεις να συμπτύξεις τον κώδικα της συνάρτησης (ξέρω γω για να πουλήσεις μούρη στην παρέα...
- Κώδικας: Επιλογή όλων
char *s_copy( char *dst, char *src )
{
register int i = 0;
while ( (dst[i] = src[i]) != '\0' ) // το = είναι ανάθεση και όχι έλεγχος ισότητας
{
i++;
}
return dst;
}
ή ακόμα κι έτσι...
- Κώδικας: Επιλογή όλων
char *s_copy( char *dst, char *src )
{
register int i = 0;
while ( (dst[i] = src[i++]) ) // το = είναι ανάθεση και όχι έλεγχος ισότητας
;
return dst;
}
Όλες αυτές οι υλοποιήσεις μπορούν να γίνουν και με δείκτες, π.χ...
- Κώδικας: Επιλογή όλων
char *s_copy( char *dst, char *src )
{
char *save = dst;
while ( *src != '\0' )
{
*dst = *src;
src++;
dst++;
}
return save;
}
η οποία συμπτυγμένη μπορεί να γραφτεί κι έτσι...
- Κώδικας: Επιλογή όλων
char *s_copy( char *dst, char *src )
{
char *save = dst;
while ( (*dst++ = *src++) ) // το = είναι ανάθεση και όχι έλεγχος ισότητας
;
return save;
}
Σου έγραψα διάφορες παραλλαγές της ίδιας συνάρτησης για να δείξω αφενός πως είναι πολύ πιο εύκολη από ότι ενδεχομένως πίστευες κι αφετέρου πως μπορείς να τη κάνεις όσο απλή ή όσο πολύπλοκη θέλεις. Στον προγραμματισμό ο χρυσός κανόνας είναι να γράφουμε όσο πιο λιτό κώδικα μπορούμε και κυρίως όσο πιο ευανάγνωστο γίνεται. Πρώτα για να τον καταλαβαίνουμε οι ίδιοι όταν χρειαστεί να τον ξαναδιαβάσουμε μετά από καιρό και ύστερα για να τον καταλαβαίνουν και οι άλλοι που ενδεχομένως θα χρειαστεί να τον διαβάσουν.
Και ΠΑΝΤΑ να τον συνοδεύουμε με σχόλια, ειδικά στα σημεία που ξεφεύγουν από τα τετριμμένα.
Προφανώς και δεν είναι υποχρεωμένος κανείς να χρησιμοποιήσει δείκτες για την διαχείριση των strings αν τον δυσκολεύουν. Μπορεί κάλλιστα να τα διαχειριστεί κάνοντάς indexing τους χαρακτήρες τους με απλούς μετρητές (i, j, κλπ)
Ελπίζω να μπορέσεις τώρα να φτιάξεις τη s_ncopy( char *dst, char *src, const size_t n) χωρίς να μπλέκεις με όλα αυτά που μπλέκεις