Τα πάντα για την C

...του ubuntu και έργων ΕΛ/ΛΑΚ (Έργα-Οδηγοί-Προτάσεις)

Συντονιστής: konnn

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 30 Αύγ 2011, 01:26

Kαι εμενα αυτο το "bytes that follow a null byte are not copied" δεν μου γεμισε το μάτι εξαρχής.
Κοιτα αμα καταφερω και φτιαξω αρχικα την strcpy μετα να προσθεσεις ενα n ειναι ευκολο. :D
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 30 Αύγ 2011, 01:29

Star_Light έγραψε:
...
Κοιτα αμα καταφερω και φτιαξω αρχικα την strcpy μετα να προσθεσεις ενα n ειναι ευκολο. :D

Δεν αντιλέγω, καλή ιδέα μου ακούγεται :)
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 30 Αύγ 2011, 02:28

δοκιμασα να διαβασω πινακες απο δεικτες μηπως και με διευκολυνουν.

Κώδικας: Επιλογή όλων
#include<stdio.h>
//char *f_cp(char *ptr[2],char *ptr2[2]);
int main()

{
char *ptr[2]={"ABaaaaa","BAaaaaaaaa"};
char *ptr2[2];
int i;


for(i=0; i<2; i++)
{
ptr2[i]=ptr[i];
printf("%s", ptr2[i]);
}

return 0;
}


απλα δεν καταλαβαινω γιατι θα εκτυπωθει σαν ptr2[i] και οχι σαν *ptr2[i] με τον αστερισκο δεν εχουμε πει πως παιρνουμε τα περιεχομενα?

στο μεταξυ η puts πολυ βολικη μιας και δεν χρειαζεται να της βαλεις τον '\n' οπως στην printf για να εκτυπωσει μια γραμμη πιο κατω.

Υποτιθεται πλεον πως το ptr2[i] ειναι ενας δεικτης σε συμβολοσειρα επομενως κανονικα την διευθυνση της συμβολοσειρας δεν θα μας εδειχνε?
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό Star_Light » 30 Αύγ 2011, 02:43

Επειδη μ αρεσε αυτο το μικρο κεφαλαιακι θα το αναλυσω λιγο παραπανω αλλα η απορια παραμενει νομιζω λοιπον αν εγω δηλωσω

Κώδικας: Επιλογή όλων
int *ptr[2]={1,2,3} ;


τοτε ειναι σαν να εχω

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

=============================================================
ptr[0] ptr[1] ptr[2]
=============================================================

| | |
| | |
| | |
=============================================================
1 2 3
=============================================================



δειχνει καθε ενα στην διευθυνση μνημης οπου ειναι τα 1 , 2 , 3 αντιστοιχα επομενως με τον αστερισκο δεν παιρνω τα περιεχομενα
αυτης της διευθυνσης μνήμης? :crazy:
Γνώσεις ⇛ Linux: Βασικές ┃ Προγραμματισμός: Δέν θέλω μεροκάματο , θέλω C και κακο θάνατο! ┃ Αγγλικά: Lower
Λειτουργικό ⇛ Ubuntu 10.10 σε Dual Boot με Windows 7
Προδιαγραφές ⇛ Επεξεργαστής : Intel(R) Core(TM) i3 CPU 540 @3.07Ghz (64bit)
RAM : Kingston 2GB
HDD : Coreshare 500GB
Κάρτα Γραφικών : Intel Corporation Core Processor Integrated Graphics Controller(rev 18) (prog-if 00 [VGA controller]) [8086:0042]
Star_Light
superbTUX
superbTUX
 
Δημοσιεύσεις: 2787
Εγγραφή: 01 Μάιος 2010, 21:07
Τοποθεσία: Αθήνα
IRC: Star_Light
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 30 Αύγ 2011, 13:07

Πω πω ρε συ, πως τα καταφέρνεις πάντα και μπλέκεις έτσι;;;;;;;;;;;;;;;;;;;; :lol:

Λοιπόν, κοίτα τι θα κάνουμε, θα σου δώσω εγώ τον κώδικα για αντιγραφή χωρίς το n ( που βασικά είναι η στάνταρ συνάρτηση strcpy(char *dst, char *src) ) και μετά εσύ θα φτιάξεις την strncpy(char *dst, char *src, size_t n)... τα πράγματα είναι πολύ πιο απλά από αυτά που κάνεις :lol:

Ξεκινάμε ορίζοντας στη 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

ή αν δεν σου αρέσουν τα πολλά λόγια :lol: ...
Κώδικας: Επιλογή όλων

...
// Before
puts( dst );
// After
puts( s_copy( dst, src) );
...

που θα τυπώσει...
Κώδικας: Επιλογή όλων


12345


Αν τώρα θέλεις να συμπτύξεις τον κώδικα της συνάρτησης (ξέρω γω για να πουλήσεις μούρη στην παρέα... :lol:) μπορείς να την αλλάξεις σε κάτι τέτοιο...
Κώδικας: Επιλογή όλων

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) χωρίς να μπλέκεις με όλα αυτά που μπλέκεις :lol:
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό stamatiou » 30 Αύγ 2011, 13:33

Τώρα αυτό δε λύνεται έτσι:
Spoiler: show
Κώδικας: Επιλογή όλων
char *mystrncpy(char *destination,int n,char *source) {
int i;
n--;
for(i=0;i<n;i++) {
if(source[i]) {
destination[i] = source[i];
}else {
for(;i < n;i++) {
destination[i] = 0;
}
destination[i+1] = '\0';
return destination;
}
}
destination[i] = '\0';
return destination;
}
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 30 Αύγ 2011, 14:01

Τι εννοείς "δε λύνεται έτσι" ... (είσαι πολύ λακωνικός ρε συ και πολλές φορές δεν καταλαβαίνω τι εννοείς).

Αυτός δεν είναι ο ίδιος κώδικας με αυτόν που έδωσες χτες; 'Υποφέρει" από το ότι σε περίπτωση που το n ισούται με το μέγιστο μήκος του destination τότε το έξτρα '\0' που βάζεις μηδενίζει τον επόμενο από τον τελευταίο χαρακτήρα του destination (άρα βγαίνει εκτός ορίων του destination).
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 30 Αύγ 2011, 14:08

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

}else {
for(;i < n;i++) {
destination[i] = 0;
}
destination[i+1] = '\0';
return destination;
}

Αν το n ισούται με το μέγιστο μήκος του destination (π.χ. char destination[4] = ""; int n = 4; ) τότε μέσα στο loop μηδενίζεις μέχρι το destination[3] που είναι ο 4ος και τελευταίος χαρακτήρας του destination κι αμέσως μετά το loop που το i ισούται με 4 (για αυτό σταμάτησε το loop) πας και μηδενίζεις με εκείνο το [i+1] και τον destination[4+1] χαρακτήρα... δηλαδή τον destination[5]... αλλά ο τελευταίος χαρακτήρας που μπορεί να περιέχει το μέγιστο μήκος του destination σύμφωνα με τον ορισμό του είναι ο destination[3]... άρα πας και μηδενίζεις το 2ο byte μετά το τέλος του destination στη μνήμη.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό stamatiou » 30 Αύγ 2011, 14:58

migf1 έγραψε:Δες κι αυτό εδώ:
Κώδικας: Επιλογή όλων

}else {
for(;i < n;i++) {
destination[i] = 0;
}
destination[i+1] = '\0';
return destination;
}

Αν το n ισούται με το μέγιστο μήκος του destination (π.χ. char destination[4] = ""; int n = 4; ) τότε μέσα στο loop μηδενίζεις μέχρι το destination[3] που είναι ο 4ος και τελευταίος χαρακτήρας του destination κι αμέσως μετά το loop που το i ισούται με 4 (για αυτό σταμάτησε το loop) πας και μηδενίζεις με εκείνο το [i+1] και τον destination[4+1] χαρακτήρα... δηλαδή τον destination[5]... αλλά ο τελευταίος χαρακτήρας που μπορεί να περιέχει το μέγιστο μήκος του destination σύμφωνα με τον ορισμό του είναι ο destination[3]... άρα πας και μηδενίζεις το 2ο byte μετά το τέλος του destination στη μνήμη.

Δλδ εγώ τώρα μηδενίζω ποιο byte;
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

Re: Τα πάντα για την C/C++

Δημοσίευσηαπό migf1 » 30 Αύγ 2011, 15:02

:lol: καλά τι έγραφα τόση ώρα βρε συ σήμερα και χτες; :lol:

Πες μου ποιο σημείο δεν έχεις καταλάβει από αυτά που έχω γράψει να το ξανα-δούμε.
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

ΠροηγούμενηΕπόμενο

Επιστροφή στο Ανάπτυξη Λογισμικού / Αλγόριθμοι