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

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

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

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

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

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

Πες μου ποιο σημείο δεν έχεις καταλάβει από αυτά που έχω γράψει να το ξανα-δούμε.

Κατάλαβα ότι κάνω λάθος και το αφήνο να ελέγχει ακόμα και αν φτάσει στο (σατανικό πλέον!) μηδενικό χαρακτήρα.
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

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

Για αυτό είχα πει να ξεκινούσαμε με την strncmp πρώτα (αν κι εκείνη έχει στύψιμο μυαλού για τον έλεγχο των διάφορων περιπτώσεων)...

Θέλετε πριν συνεχίσουμε με αυτές τις δυο, να κάνετε την σκέτη strcmp (χωρίς το n) που είναι πάρα πολύ πιο απλή;

Πρότυπο:
Κώδικας: Επιλογή όλων
int s_compare( const char *s1, const char *s2 );

Επιστρέφει:
  • 0 αν τα s1 και s2 είναι ίδια,
  • θετική τιμή αν το s1 είναι μεγαλύτερο του s2
  • αρνητική τιμή αν το s1 είναι μικρότερο του s2
το μικρότερο και μεγαλύτερο δεν καθορίζεται από το μήκος των strings, αλλά από το αν ο πρώτος μη κοινός χαρακτήρας τους έχει μικρότερο ή μεγαλύτερο ASCII code στο πρώτο string.

Για παράδειγμα:
το s_compare("abc", "abd") δίνει αρνητική τιμή, διότι 'c' < 'd'... άρα το s1 είναι μικρότερο του s2
το s_compare("ab", "c" ) δίνει επίσης αρνητική τιμή, διότι 'a' < 'c' ... άρα το s1 είναι μικρότερο του s2
το s_compare("abc", "abcd" ) δίνει επίσης αρνητική τιμή, διότι '\0' < 'd' ... άρα το s1 είναι μικρότερο του s2
το s_compare("d", "abc" ) δίνει θετική τιμή, διότι 'd' > 'a' ... άρα το s1 είναι μεγαλύτερο του s2
κλπ
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, 15:52

migf1 sorry αλλα δεν εχω βαλει το n ακομη επειδη θελω περισσοτερο να μεινω σε αυτο το σημειο και να καταλαβω επακριβως πως δουλευει ο αλγοριθμος. Φυσικα με δεικτες. Αλλιως για μενα τουλαχιστον δεν εχει νοημα. Ο κωδικας ειναι ο εξης :

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

int main()

{

char s1[5]="Kost";
char s2[5]="Cost";
char *ptr1;
char *ptr2;

ptr1=s1;
ptr2=s2;

printf("%s",f_cp(ptr1,ptr2));


return 0;
}
char *f_cp(char *ptr1 , char *ptr2)
{

char *save=ptr1;

while(*ptr2!='\0')
{
*ptr1=*ptr2;
ptr2++;
ptr1++;
}


return save;
}


Τα λάθη που έκανα ηταν τα εξής :

1. Ουσιαστικα σε προηγουμενο κωδικα αυξανα μονο τον ptr2 και οχι τον ptr1 συνεπως ο ptr2 μαλλον αντεγραφε στον ptr1 μονο το πρωτο στοιχειο.

2. Δεν εσωζα το αποτελεσμα σε εναν *save (μυριζομουν οτι υπαρχει προβλημα με την τιμη επιστροφης αλλα δεν ηξερα τι ακριβως να κανω ωστε να το διορθωσω)

Φυσικα υπάρχουν αρκετα ερωτηματα. Καταρχην με μπερδευει το *save = ptr1; ο *save ειναι ορισμενος σαν δεικτης κατι που σημαινει οτι περιμενει μια δεξια τιμη.... πως παιρνει αριστερη? δηλαδη την τιμη του ptr1 τον οποιο εχω βάλει να δείχνει στον s1 πινακα.

Kαι μετα γιατι επιστρεφουμε σκετο save? Το save δειχνει στην αρχικη διευθυνση της συμβολοσειρας η οποια ειναι σειριακα στην μνημη? Αλλα και παλι δεν θα επιστρεψει διεύθυνση? Πως εκτυπωνεται τελικα.......
Γνώσεις ⇛ 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++

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

Λοιπόν εγώ προσπάθησα το s_compare αλλά έχω κάτι πρωτόγνωρα erros.
Spoiler: show
Κώδικας: Επιλογή όλων
int s_compare(char string1[],char string2[]) {
int i=0,len1,len2;
if((!string1[0]) || (!string2[0])) return 2;
for(len1=0;string1[len1];len1++);
for(len2=0;string2[len2];len2++);
if(len1 == len2) {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') {
return 0;
}else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}

}else {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') return 0;
else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}
}
return 3;
}

Και τα errors:
Spoiler: show
Κώδικας: Επιλογή όλων
s_compare.c: In function ‘s_compare’:
s_compare.c:10: warning: suggest parentheses around assignment used as truth value
s_compare.c:19: warning: suggest parentheses around assignment used as truth value

και όταν εκτελώ μου βγάζει segmentaion fault :problem:
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

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

Star_Light έγραψε:migf1 sorry αλλα δεν εχω βαλει το n ακομη επειδη θελω περισσοτερο να μεινω σε αυτο το σημειο και να καταλαβω επακριβως πως δουλευει ο αλγοριθμος. Φυσικα με δεικτες. Αλλιως για μενα τουλαχιστον δεν εχει νοημα. Ο κωδικας ειναι ο εξης :

Spoiler: show
Κώδικας: Επιλογή όλων
#include<stdio.h>
char *f_cp(char *ptr1 , char *ptr2);

int main()

{

char s1[5]="Kost";
char s2[5]="Cost";
char *ptr1;
char *ptr2;

ptr1=s1;
ptr2=s2;

printf("%s",f_cp(ptr1,ptr2));


return 0;
}
char *f_cp( char *ptr1 , char *ptr2 )
{

char *save=ptr1;

while(*ptr2!='\0')
{
*ptr1=*ptr2;
ptr2++;
ptr1++;
}


return save;
}


Τα λάθη που έκανα ηταν τα εξής :

1. Ουσιαστικα σε προηγουμενο κωδικα αυξανα μονο τον ptr2 και οχι τον ptr1 συνεπως ο ptr2 μαλλον αντεγραφε στον ptr1 μονο το πρωτο στοιχειο.

2. Δεν εσωζα το αποτελεσμα σε εναν *save (μυριζομουν οτι υπαρχει προβλημα με την τιμη επιστροφης αλλα δεν ηξερα τι ακριβως να κανω ωστε να το διορθωσω)

Φυσικα υπάρχουν αρκετα ερωτηματα. Καταρχην με μπερδευει το *save = ptr1; ο *save ειναι ορισμενος σαν δεικτης κατι που σημαινει οτι περιμενει μια δεξια τιμη.... πως παιρνει αριστερη? δηλαδη την τιμη του ptr1 τον οποιο εχω βάλει να δείχνει στον s1 πινακα.

Kαι μετα γιατι επιστρεφουμε σκετο save? Το save δειχνει στην αρχικη διευθυνση της συμβολοσειρας η οποια ειναι σειριακα στην μνημη? Αλλα και παλι δεν θα επιστρεψει διεύθυνση? Πως εκτυπωνεται τελικα.......

Λοιπόν, καταρχήν άλλαξε το όνομα της συνάρτησης σε κάτι που να καταλαβαίνουμε τι κάνει :P Π.χ. s_copy ή mystrcpy ή κάτι τέτοιο ευανάγνωστο :)

Κατόπιν τα ptr1 και ptr2 δεν χρειάζονται καθόλου, θα δουλέψεις απευθείας με τα s1 και s2, οπότε ο κώδικάς σου γίνεται αμέσως-αμέσως λιτός κι ευανάγνωστος...

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

char *s_copy( char *s1 , char *s2);
// ----------------------------------------------------------------------------------------------------
int main( void )
{
char s1[5] = "Kost";
char s2[5] = "Cost";

printf("%s", s_copy( s1, s2) );

return 0;
}
// -----------------------------------------------------------------------------------------------------
char *s_copy(char *s1 , char *s2)
{
char *save = s1;

while ( *s2 != '\0' )
{
*s1 = *s2;
s2++;
s1++;
}

return save;
}

Για τον δείκτη save τώρα, όταν δουλεύεις τα strings απευθείας ως δείκτες (που ξεκινάνε δείχνοντας στην αρχή τους) τότε όταν γράψεις π.χ. s1++ για να προχωρήσεις στον 2ο χαρακτήρα του s1 έχασες την επαφή σου με την αρχή του s1. Στο τέλος του while-loop τόσο ο s1 όσο και ο s2 έχουν προχωρήσει (λόγω των s1++ και s2++) άρα έχεις χάσει την επαφή σου με τις αρχές των strings σου. Για το s2 σε αυτή την συνάρτηση δεν μας ενδιαφέρει, αλλά το s1 θέλουμε να το επιστρέψει η συνάρτηση. Όμως ο δείκτης s1 μετά το loop έχει πάει στο τέλος του string, και συγκεκριμένα δείχνει στον μηδενικό χαρακτήρα του s1, οπότε το: return s1 θα σου επέστρεφε έναν δείκτη στο τέλος του s1.

Για αυτόν ακριβώς τον λόγο λοιπόν, πριν ξεκινήσουμε το while-loop ορίζουμε έναν τοπικό δείκτη (τον save εδώ) τον οποίον το βάζουμε να δείχνει στην αρχή του s1 (save = s1). Άρα λοιπόν έχουμε σωσμένη την αρχή του s1, οπότε όταν τελειώσει το while-loop κι ο δείκτης s1 έχει φτάσει στο τέλος του string, εμείς επιστρέφουμε τον save, που δείχνει στην αρχή του string ;)

Σημείωσε πως όταν δουλεύεις με μετρητές αντί για δείκτες, δεν το έχεις αυτό το πρόβλημα, γιατί το s1[i] δεν μετακινεί τον δείκτη s1 στη θέση i, απλά αναφέρεται στην θέση i... ισοδυναμεί δηλαδή με: s1+i και όχι με s1 = s1 + i;

Μι' πιάν'ς :lol:
Τελευταία επεξεργασία από migf1 και 30 Αύγ 2011, 16:23, έχει επεξεργασθεί 1 φορά/ες συνολικά
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

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

Άμα μου κάνεις ευανάγνωστο τον κώδικα θα το κοιτάξω :lol:

stamatiou έγραψε:Λοιπόν εγώ προσπάθησα το s_compare αλλά έχω κάτι πρωτόγνωρα erros.
Spoiler: show
Κώδικας: Επιλογή όλων
int s_compare(char string1[],char string2[]) {
int i=0,len1,len2;
if((!string1[0]) || (!string2[0])) return 2;
for(len1=0;string1[len1];len1++);
for(len2=0;string2[len2];len2++);
if(len1 == len2) {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') {
return 0;
}else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}

}else {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') return 0;
else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}
}
return 3;
}

Και τα errors:
Spoiler: show
Κώδικας: Επιλογή όλων
s_compare.c: In function ‘s_compare’:
s_compare.c:10: warning: suggest parentheses around assignment used as truth value
s_compare.c:19: warning: suggest parentheses around assignment used as truth value

και όταν εκτελώ μου βγάζει segmentaion fault :problem:
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, 16:20

f_cp <=> function copy :lol: :lol: αλλα εχεις δικιο παρα ειναι συμπτυγμενο. Ακριβως σκεφτηκα και αυτο με το λιτο κωδικα που ειπες αφοτου την ειχα ποσταρει και λεω θα μου την πει τωρα :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++

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

migf1 έγραψε:
Για τον δείκτη save τώρα, όταν δουλεύεις τα strings απευθείας ως δείκτες (που ξεκινάνε δείχνοντας στην αρχή τους) τότε όταν γράψεις π.χ. s1++ για να προχωρήσεις στον 2ο χαρακτήρα του s1 έχασες την επαφή σου με την αρχή του s1. Στο τέλος του while-loop τόσο ο s1 όσο και ο s2 έχουν προχωρήσει (λόγω των s1++ και s2++) άρα έχεις χάσει την επαφή σου με τις αρχές των strings σου. Για το s2 σε αυτή την συνάρτηση δεν μας ενδιαφέρει, αλλά το s1 θέλουμε να το επιστρέψει η συνάρτηση. Όμως ο δείκτης s1 μετά το loop έχει πάει στο τέλος του string, και συγκεκριμένα δείχνει στον μηδενικό χαρακτήρα του s1, οπότε το: return s1 θα σου επέστρεφε έναν δείκτη στο τέλος του s1.

Για αυτόν ακριβώς τον λόγο λοιπόν, πριν ξεκινήσουμε το while-loop ορίζουμε έναν τοπικό δείκτη (τον save εδώ) τον οποίον το βάζουμε να δείχνει στην αρχή του s1 (save = s1). Άρα λοιπόν έχουμε σωσμένη την αρχή του s1, οπότε όταν τελειώσει το while-loop κι ο δείκτης s1 έχει φτάσει στο τέλος του string, εμείς επιστρέφουμε τον save, που δείχνει στην αρχή του string ;)

Σημείωσε πως όταν δουλεύεις με μετρητές αντί για δείκτες, δεν το έχεις αυτό το πρόβλημα, γιατί το s1[i] δεν μετακινεί τον δείκτη s1 στη θέση i, απλά αναφέρεται στην θέση i... ισοδυναμεί δηλαδή με: s1+i και όχι με s1 = s1 + i;

Μι' πιάν'ς :lol:


Nαι το ειχαμε πει και στις λιστες αυτο. Δηλαδη η συναρτηση αυτη οριοθετει μια περιοχη η οποια δειχνει το μηκος της συμβολοσειρας.
Χειριζομαστε απευθειας σαν συμβολοσειρες .... οκ δηλαδη ειναι ενας δεικτης σε μια συμβολοσειρα ο *dst πχ?
Γνώσεις ⇛ 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++

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

migf1 έγραψε:Άμα μου κάνεις ευανάγνωστο τον κώδικα θα το κοιτάξω :lol:

stamatiou έγραψε:Λοιπόν εγώ προσπάθησα το s_compare αλλά έχω κάτι πρωτόγνωρα erros.
Spoiler: show
Κώδικας: Επιλογή όλων
int s_compare(char string1[],char string2[]) {
int i=0,len1,len2;
if((!string1[0]) || (!string2[0])) return 2;
for(len1=0;string1[len1];len1++);
for(len2=0;string2[len2];len2++);
if(len1 == len2) {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') {
return 0;
}else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}

}else {
for(i=0;(string1[i] != string2[i]) && (string1[i]);i++);
if(string1[i+1] = '\0') return 0;
else {
if(string1[i] < string2[i]) return -1;
else if(string1[i] > string2[i]) return 1;
}
}
return 3;
}

Και τα errors:
Spoiler: show
Κώδικας: Επιλογή όλων
s_compare.c: In function ‘s_compare’:
s_compare.c:10: warning: suggest parentheses around assignment used as truth value
s_compare.c:19: warning: suggest parentheses around assignment used as truth value

και όταν εκτελώ μου βγάζει segmentaion fault :problem:

Οκ τον αραίωσα στις παρενθέσεις και στα =.
Spoiler: show
Κώδικας: Επιλογή όλων
int s_compare ( char string1[], char string2[] ) {
int i = 0, len1, len2;
if ( ( !string1[0] ) || ( !string2[0] ) ) return 2;
for ( len1 = 0 ; string1[len1]; len1++ );
for ( len2=0; string2[len2]; len2++ );
if ( len1 == len2 ) {
for( i=0; ( string1[i] != string2[i] ) && ( string1[i] );i++ );
if ( string1[i+1] = '\0' ) {
return 0;
}else {
if ( string1[i] < string2[i] ) return -1;
else if ( string1[i] > string2[i] ) return 1;
}

}else {
for ( i=0; ( string1[i] != string2[i] ) && ( string1[i] ); i++);
if ( string1[i+1] = '\0' ) return 0;
else {
if ( string1[i] < string2[i] ) return -1;
else if ( string1[i] > string2[i] ) return 1;
}
}
return 3;
}
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

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

Μόλις τον αραίωσα κι εγώ :lol:

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

int s_compare( char s1[], char s2[] )
{
int i=0, len1, len2;

if ( !s1[0] || !s2[0] )
return 2;

for (len1=0; s1[ len1 ]; len1++)
;
for (len2=0; s2[ len2 ]; len2++)
;
if (len1 == len2)
{
for (i=0; s1[i] != s2[i] && s1[i]; i++)
;
if (s1[i+1] = '\0') {
return 0;
}
else {
if ( s1[i] < s2[i] )
return -1;
else if ( s1[i] > s2[i] )
return 1;
}
}
else
{
for (i=0; s1[i] != s2[i] && s1[i]; i++)
;
if ( s1[i+1] = '\0')
return 0;
else {
if ( s1[i] < s2[i] )
return -1;
else if( s1[i] > s2[i] )
return 1;
}
}
return 3;
}


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

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

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