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

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

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

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

Δημοσίευσηαπό migf1 » 06 Σεπ 2011, 21:16

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

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

#include <stdio.h>

#define MAX_ELEMENTS 5+1
#define INVALID -1
// ----------------------------------------------------------------
int main( void )
{
int nums[ MAX_ELEMENTS ] = { 0, 12, 45, 76, 100, INVALID }; // πίνακας φυσικών αριθμών (θετικοί ή 0)
int *p = nums;

while ( *p != INVALID )
printf("%u ", *p++);
putchar('\n');

return 0;
}

Σε κώδικα με πάρα πολλές γραμμές είναι πολύ πιο εύκολο να τον καταλάβεις έτσι :)

@Stamatiou: όταν ευκαιρήσεις ρίξε μια ματιά στις προηγούμενες σελίδες, 5-6 ... νομίζω θα σε βοηθήσουν αρκετά. Για την υπερχείλιση τα είπε ήδη ο Κώστας. Βασικά είναι μια "μούρικη" ορολογία για τις περιπτώσεις που προσπαθούμε να δεδομένα ενός πίνακα, αλλά προφανώς κατά λάθος φεύγουμε έξω από τα όρια που έχουμε ορίσεις στον πίνακα... π.χ. απόπειρα να διαχειριστούμε το στοιχείο -1 ενός πίνακα (κάτω υπερχείλιση) ή το 11ο αλλά με ορισμένο άνω όριο το 10 (άνω υπερχείλιση).

@logaro81: ευχαριστούμε για τα links, αλλά σε αυτή τη φάση ασχολούμαστε με τη κατανόηση πιο low-level εννοιών (επίσης η QT είναι σε C++, εδώ έχουμε εστιάσει σε C).

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

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

Δημοσίευσηαπό Star_Light » 06 Σεπ 2011, 21:23

Βασικα εκανα αυτο με την σηματοδοτηση γιατι ηθελα να παιξω με την τιμη ενος δεικτη μεσα στην while.

Οταν εβαζα σκετη τη μεταβλητη δεικτη αντιμετωπιζα προβληματα οπως ατερμονες βρογχους....

ενω εβαζα να μετακινειται μια θεση δεξια πχ

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


while(p)
{

printf("%d",*p);

p++;
}


αυτο πρεπει να ηταν

εν τω μεταξυ ο κωδικας που εκανα με τις συγκρισεις ελπιζω να ειναι σωστος...

ειμαι και απο γουιντοους τωρα σε λιγο θα ξαναμπουταρω απο λινουξ.

στα γουιντοους δεν εχω μεταγλωτιστη.
Γνώσεις ⇛ 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 » 06 Σεπ 2011, 21:27

εννοειται πως εχω αρχικοποιησει τον δεικτη να δειχνει στην αρχη της διαταξης νωριτερα.
Γνώσεις ⇛ 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 » 06 Σεπ 2011, 21:27

Star_Light έγραψε:Βασικα εκανα αυτο με την σηματοδοτηση γιατι ηθελα να παιξω με την τιμη ενος δεικτη μεσα στην while.

Οταν εβαζα σκετη τη μεταβλητη δεικτη αντιμετωπιζα προβληματα οπως ατερμονες βρογχους....

ενω εβαζα να μετακινειται μια θεση δεξια πχ

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


while(p)
{

printf("%d",*p);

p++;
}


αυτο πρεπει να ηταν
...

Δεν είναι σωστό το while, γιατί στη συνθήκη του γράφεις σκέτο p, που ισοδυναμεί με: while( p != NULL )
το οποίο προφανώς είναι πάντα TRUE, αφού το p το έχεις αρχικοποιήσει να δείχνει στον πίνακά σου.

Προφανώς ήθελες να γράψεις: while ( *p ) που ισοδυναμεί με: while ( *p != 0 )
;)
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

Δημοσίευσηαπό Star_Light » 06 Σεπ 2011, 21:35

migf1 έγραψε:Δεν είναι σωστό το while, γιατί στη συνθήκη του γράφεις σκέτο p, που ισοδυναμεί με: while( p != NULL )
το οποίο προφανώς είναι πάντα TRUE, αφού το p το έχεις αρχικοποιήσει να δείχνει στον πίνακά σου.

Προφανώς ήθελες να γράψεις: while ( *p ) που ισοδυναμεί με: while ( *p != 0 )
;)


ναι αυτο σκεφτομουν οταν το εγραφα σαν *p!=0 μεσα στο while loop. Να ρωτησω κατι αλλο
το while(p!=NULL) ειναι ισοδυναμο με while(p!=0) ???
ή μονο σε *p ισχυει αυτο.

Εξ ορισμου η while θα πρεπει να δέχεται κατι που δεν ειναι 0 και να εκτελει το σωμα της μέχρι αυτο το κατι δεν ειναι 0 έτσι?
Μηδενικη ποσοτητα εννοω.
Γνώσεις ⇛ 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 » 06 Σεπ 2011, 21:40

Star_Light έγραψε:Να ρωτησω κατι αλλο
το while(p!=NULL) ειναι ισοδυναμο με while(p!=0) ???
ή μονο σε *p ισχυει αυτο.

Σωστός, ισχύει και στα δυο... άλλωστε το NULL δεν είναι τίποτε άλλο από μια σταθερά ορισμένη με #define :)
Κώδικας: Επιλογή όλων
#define NULL 0L
ή
#define NULL (void *)0
που σημαίνει πως ισούται με (long) 0 :)

έγραψε:
Εξ ορισμου η while θα πρεπει να δέχεται κατι που δεν ειναι 0 και να εκτελει το σωμα της μέχρι αυτο το κατι δεν ειναι 0 έτσι?
Μηδενικη ποσοτητα εννοω.

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

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

Δημοσίευσηαπό Star_Light » 06 Σεπ 2011, 21:59

Κατσε να τα συνδυασω τωρα και με τα 3 solutions που χεις δωσει στο buffer overflow στους ελεγχους....

Κώδικας: Επιλογή όλων
if(p1)
{ free(p1);
p1=NULL;
}


Λοιπον η if γενικα ελέγχει την έκφραση μέσα στην παρενθεση της , αν αυτη δωσει μη μηδενικη τιμή μπορει να εκτελεστει , επομενως αν υπάρχει ο p1 (αν υπάρχει εννοουμε να δειχνει σε εγκυρα δεδομενα) τοτε ελευθερωσε τον και θεσε τον μετα σε NULL. Ειμαι σωστος εδω???

επισης λες πως θα πρεπει να αρχικοποιουμε παντοτε τους δεικτες πριν τους χρησιμοποιησουμε... αρκετα λογικο μιας και ενας δεικτης μη αρχικοποιημενος μπορει να δειχνει οπουδηποτε ακομη και σε σημειο στην μνημη που μπορει να υπάρχουν χρησιμες εγγραφες του λειτουργικου συστηματος κτλπ επομενως καταλαβαινει κανεις αμεσως τις συνεπειες για την ασφαλεια και εδω. Επομενως παντα πρεπει να τους αρχικοποιουμε πριν τους χρησιμοποιησουμε ή να τους θέτουμε την τιμή NULL. Εκει δειχνουν παντα στο 0 δηλαδη? Αυτο που ειναι στην αρχη της μνημης?

Επισης λες πως πρεπει να ελεγχεις να μην ειναι NULL ενας δεικτης πριν τον χρησιμοποιησεις... επειδη αμα τον θεσεις μεσα σε μια printf ας πουμε για εκτυπωση θα φας segmentation fault??????

@σταματιου αμα εχεις αποριες στην υπερχειλιση ακομη πες να σου δωσω τον απλο κωδικα που εφτιαξα :P
Γνώσεις ⇛ 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 » 06 Σεπ 2011, 22:08

Λοιπον παω να δω κατι φιλες και φιλους γιατι θα με επικυρηξουν αμα τους την σκασω παλι .
Θα ξαναμπω πιο μετα να δω την συνεχεια... Μολις λυθουν και οι ακριβως προηγουμενες αποριες μου εγω πχ ειμαι ετοιμος
για να μπουμε σε βιβλιοθηκες... αν πχ ειμαι σωστος και στα τελευταια και ο σταματιου συνεχιζει να εχει αποριες τον αναλαμβανω εγω
μεχρι να ειναι και αυτος ετοιμος :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 » 06 Σεπ 2011, 22:46

Star_Light έγραψε:Κατσε να τα συνδυασω τωρα και με τα 3 solutions που χεις δωσει στο buffer overflow στους ελεγχους....

Κώδικας: Επιλογή όλων
if(p1)
{ free(p1);
p1=NULL;
}


Λοιπον η if γενικα ελέγχει την έκφραση μέσα στην παρενθεση της , αν αυτη δωσει μη μηδενικη τιμή μπορει να εκτελεστει , επομενως αν υπάρχει ο p1 (αν υπάρχει εννοουμε να δειχνει σε εγκυρα δεδομενα) τοτε ελευθερωσε τον και θεσε τον μετα σε NULL. Ειμαι σωστος εδω???

Σωστός! Μια διευκρίνηση όμως, το αν υπάρχει ο δείκτης σημαίνει να μην είναι NULL, το αν δείχνει όμως σε έγκυρη μνήμη ή όχι δεν μπορούμε να το ξέρουμε... πρέπει να έχουμε φροντίσει εμείς να δείχνει σε έγκυρη μνήμη πριν τον χρησιμοποιήσουμε (είτε δλδ να του έχουμε δεσμέυσει μνήμη μόνοι μας με calloc, είτε να τον έχουμε βάλει να δείχνει στη μνήμη μιας άλλης μεταβλητής, π.χ στην αρχή ενός πίνακα, ή σε ένα στοιχείο ενός πίνακα ή στη μνήμη μιας απλής μεταβλητής, κλπ).

έγραψε:επισης λες πως θα πρεπει να αρχικοποιουμε παντοτε τους δεικτες πριν τους χρησιμοποιησουμε... αρκετα λογικο μιας και ενας δεικτης μη αρχικοποιημενος μπορει να δειχνει οπουδηποτε ακομη και σε σημειο στην μνημη που μπορει να υπάρχουν χρησιμες εγγραφες του λειτουργικου συστηματος κτλπ επομενως καταλαβαινει κανεις αμεσως τις συνεπειες για την ασφαλεια και εδω. Επομενως παντα πρεπει να τους αρχικοποιουμε πριν τους χρησιμοποιησουμε ή να τους θέτουμε την τιμή NULL. Εκει δειχνουν παντα στο 0 δηλαδη? Αυτο που ειναι στην αρχη της μνημης?

Όχι δεν σημαίνει αρχή της μνήμης το NULL. Απλά ξέρουμε πως αν είναι NULL ο δείκτης δεν δείχνει σε άκυρη μνήμη... βασικά δεν δείχνει ΠΟΥΘΕΝΑ.

έγραψε:Επισης λες πως πρεπει να ελεγχεις να μην ειναι NULL ενας δεικτης πριν τον χρησιμοποιησεις... επειδη αμα τον θεσεις μεσα σε μια printf ας πουμε για εκτυπωση θα φας segmentation fault??????

Ναι! Βέβαια η printf κοιτάει αν είναι NULL πριν πάει να τον χρησιμοποιήσει οπότε δεν παράγει seg-fault, η puts() όμως δεν κοιτάει. Δοκίμασέ το να το δεις και στη πράξη:

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

int main( void )
char *s = NULL;

printf("%s\n", s); // δεν θα παράξει σφάλμα, γιατί η prinf ελέγχει αν είναι NULL το s πριν το χρησιμοποιήσει
puts( s ); // θα παράξει σφάλμα, γιατί η puts δεν ελέγχει αν είναι NULL το s... το χρησιμοποιεί χωρίς έλεγχο (άρα εδώ θα κρασάρει)
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 07 Σεπ 2011, 00:43

Για να ολοκληρώσουμε λοιπόν και το θέμα των ελέγχων που έχουμε αφήσει ανοιχτό στη συνάρτηση s_compare που έχουμε φτιάξει, παραθέτω τον ολοκληρωμένο της κώδικα, κι εξηγώ από κάτω...

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

// ------------------------------------------------------------------------------------
int s_compare( const char *s1, const char *s2 )
{
if ( !s1 && !s2 )
return 0;
if ( !s1 && s2 )
return -1;
if (s1 && !s2 )
return 1;

while ( *s1 == *s2++ )
if ( *s1++ == '\0' )
return 0;

return (int) ( *s1 - *--s2 );
}

Οι έλεγχοι αυτοί είναι όλοι early-exit conditions και αποτελούνται από τα 3 if που έχω προσθέσει στην αρχή της συνάρτησης.

Στο πρώτο ελέγχω αν και ο δείκτης s1 και ο δείκτης s2 είναι NULL (που ουσιαστικά είναι τα 2 strings που μας έχουν περαστεί στη συνάρτηση και καλούμαστε να τα συγκρίνουμε). Όταν λοιπόν είναι και τα 2 NULL, δηλαδή ανύπαρκτα επί της ουσίας, τότε επιστρέφω την τιμή 0... σαν να υπήρχαν δηλαδή και να ήταν ίδια.

Στο 2ο if ελέγχω την περίπτωση όπου το s1 είναι NULL αλλά το s2 υπάρχει (και προφανώς περιέχει κάτι). Σε αυτή την περίπτωση θεωρώ πως το s1 είναι μικρότερο του s2 (με τη λογική πως το ανύπαρκτο είναι πάντα μικρότερο του υπαρκτού) οπότε επιστρέφω την τιμή -1.

Και στο 3ο if εξετάζω την περίπtωση όπου το s1 είναι υπαρκτό και το s2 ανύπαρκτο, οπότε θεωρώ το s1 μεγαλύτερο του s2 κι επιστρέφω την τιμή 1.

Αν η ροή καταφέρει και περάσει από αυτούς τους ελέγχους, τότε έχουμε εγγυημένα 2 υπαρκτά stings (μη NULL) και άρα μπορούμε να γράψουμε τον βασικό αλγόριθμο της συνάρτησής μας, χωρίς να μας απασχολεί πλέον αν κάποιο ή και τα 2 strings που μας περάστηκαν σαν ορίσματα είναι NULL.

Έχουμε καταφέρει επίσης να αποφύγουμε τυχόν παραγωγή segmentation-faults, διότι δεν υπάρχει καμία πιθανότητα ο κώδικάς μας να επιχειρήσει να χρησιμοποιήσει κάποιο από τα s1 και s2 όταν οποιοδήποτε από αυτά είναι NULL.

Άρα έχουμε φτιάξει μια λειτουργική και ΑΣΦΑΛΗ συνάρτηση! :)

Υπάρχει κάποια πιθανότητα να παραχθεί seg-fault, αν για παράδειγμα κάποιο ή και τα δυο από τα s1 και s2 ναι μεν δεν είναι NULL, αλλά δεν δείχνει σε έγκυρη μνήμη. Π.χ. να έχει οριστεί στη main() ως δείκτης χωρίς όμως να έχει αρχικοποιηθεί ούτε σε NULL αλλά ούτε με calloc() / malloc()... και να έχει περαστεί έτσι στη συνάρτησή μας.

Αυτό όμως δεν μπορεί να το γνωρίζει η συνάρτηση, ούτε μπορεί να το ελέγξει. Οπότε ότι είχαμε να κάνουμε σε επίπεδο συνάρτησης το έχουμε κάνε!, Μένει να εξασφαλίσουμε πως τα s1 και s2 θα είναι είτε NULL είτε θα δείχνουν σε έγκυρη μνήμη όταν καλούμε τη συνάρτηση και της τα περνάμε σαν ορίσματα!

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

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

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