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

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

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

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

Δημοσίευσηαπό Star_Light » 10 Σεπ 2011, 01:18

migf1 έγραψε:Διευθυνσιογράφος είναι ατζέντα ονομάτων, διευθύνσεων, τηλεφώνων, κλπ. με δυνατότητα αναζήτησης, φιλτραρίσματος, προσθήκης. διαγραφής, αντικατάστασης, κλπ εγγραφών.

ΥΓ. Άστην την κωλο-άσκηση εκείνη :lol:


χαχαχαχα ε λυσσαξα. Με το ρημαδι! οκ οκ , ακουγεται πολυ ενδιαφερον ο διευθυνσιογραφος... ετσι λεγεται γενικοτερα?
Γνώσεις ⇛ 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 » 10 Σεπ 2011, 01:20

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

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

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

OK και ποια θα ειναι η 1η συνάρτηση που θα βάλουμε μεσα? :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 » 10 Σεπ 2011, 02:08

Star_Light έγραψε:OK και ποια θα ειναι η 1η συνάρτηση που θα βάλουμε μεσα? :D

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

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

Δημοσίευσηαπό Star_Light » 10 Σεπ 2011, 02:29

migf1 έγραψε:
Star_Light έγραψε:OK και ποια θα ειναι η 1η συνάρτηση που θα βάλουμε μεσα? :D

viewtopic.php?p=207045#p207045


LOL Οκ δεν το προσεξα.
Γνώσεις ⇛ 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 » 10 Σεπ 2011, 09:31

Καλημέρες, καλημέρες :)

Λοιπόν δίνω σε spoiler την υλοποίηση της table_print_contents() για να συνεχίσουμε...

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

/* --------------------------------------------------------------------------------
* Τυπώνει τα μη κενά στοιχεία του πίνακα table
* --------------------------------------------------------------------------------
*/
void table_print_contents( int *table, const int maxelems )
{
register int i = 0;

for (i=0; i < maxelems; i++)
if ( table[i] != EMPTYELEM )
printf( "%d ", table[i] );

putchar('\n');

return;
}

Θα προσπαθήσω ο κώδικας που φτιάχνουμε να είναι συμβατός με το στάνταρ ANSI (C89) που το υποστηρίζουν όλοι οι compilers (σε αντίθεση με το c99 που και δεν το υποστηρίζουν όλοι και όσοι το υποστηρίζουν το υποστηρίζουν μερικώς). Για αυτό αν προσέξατε τα σχόλια τα έχω σε /* */ και όχι σε //

Πάει αυτό :)

Το επόμενο είναι πως σας είχα πει να χρησιμοποιείται πάντα την calloc() αντί της malloc() όταν θέλετε να δεσμεύετε δυναμικά μνήμη για κάποιον δείκτη, επειδή η calloc() μηδενίζει εγγυημένα τα περιεχόμενα της μνήμης που δεσμεύει (βάζει την τιμή 0 σε όλα τα bytes που δεσμεύει). Αντίθετα, τα περιεχόμενα της μνήμης που δεσμεύονται με την malloc() είναι undefined (μπορεί δλδ να περιέχουν οτιδήποτε)!

Όμως στον κώδικα που έδωσα για να ξεκινήσουμε, τη μνήμη του table τη δεσμεύω με malloc() και όχι με calloc()... δάσκαλε που δίδασκες δηλαδή :lol: Περίμενα να με ρωτήσετε για αυτό, αλλά είδα πως "δεν" οπότε το σημειώνω μόνος μου :lol:

Λοιπόν ο λόγος που χρησιμοποίησα malloc() αντί για calloc() είναι πως τα αρχικά περιεχόμενα του table δεν τα θέλουμε να είναι 0, αλλά EMPTYELEM (που το έχουμε βάλει να ισούται με -1). Άρα και με calloc() να δέσμευα τη μνήμη θα χρειαζόταν έτσι κι αλλιώς μετά να πάω να βάλω σε όλα τα στοιχεία του πίνακα την τιμή EMPTYELEM ;)

Τώρα, αυτό το γέμισμα όλων των στοιχείων του πίνακα με την ίδια τιμή (που στην προκειμένη περίπτωση είναι η EMPTYELEM) μπορούμε να την κάνουμε φτιάχνοντας μια συνάρτηση, π.χ.

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

void table_fill_same( int *table, const int maxelems, const int value )
{
register int i = 0;

for (i=0; i < maxelems; i++)
table[ i ] = value;
}

return;
}

που θα έπιανε τον πίνακα από το στοιχείο 0 και μέχρι να φτάσει στο στοιχείο maxelems-1 θα έβαζε στο κάθε στοιχείο την τιμή value... προφανώς όταν καλούσαμε την συνάρτηση αυτή θα της περνάγαμε ως value το EMPTYELEM.

Αυτός είναι ο κλασικός τρόπος γεμίσματος ενός πίνακα με την ίδια τιμή σε όλα του τα στοιχεία. Είναι όμως αργός τρόπος! Ο ταχύτερος τρόπος να γεμίζουμε ένα κομμάτι μνήμης με την ίδια τιμή στη C είναι με τη στάνταρ συνάρτηση...

Κώδικας: Επιλογή όλων
void * memset (void *block, int c, size_t size)

  • block είναι η αρχή της μνήμης που μας ενδιαφέρει να γεμίσουμε με μια τιμή (η αρχή της μνήμης είναι ένας δείκτης - αδιάφορου τύπου, εξού και το void * - για τον οποίον έχουμε ήδη δεσμεύσει μνήμη... μπορούμε να περάσουμε εδώ και το όνομα ενός απλού πίνακα)
  • c είναι η τιμή που θέλουμε να περάσουμε σε όλα τα στοιχεία του block
  • size είναι το μέγεθος της μνήμης που θέλουμε να γεμίσουμε, αλλά ΠΡΟΣΟΧΗ εκφρασμένο σε bytes και ΟΧΙ σε πλήθος στοιχείων
Στον κώδικα που έδωσα λοιπόν γεμίζω όλα τα στοιχεία του πίνακα table με την τιμή EMPTYELEM, χρησιμοποιώντας την έτοιμη και ταχύτατη memset() ... χρειάζεται #include <string.h> στην αρχή του προγράμματος.

ΣΗΜΕΙΩΣΤΕ πως ως 3ο όρισμα δεν της περνάω το μέγιστο πλήθος στοιχείων του πίνακά μας ( maxelems ) αλλά το μέγεθος που καταλαμβάνουν σε bytes στη μνήμη ( maxelems * sizeof(int) ) το οποίο απλά το έχω υπολογίσει από πριν και το έχω αποθηκεύσει στη μεταβλητή tabsize. Είναι κρίσιμης σημασίας να διαχωρίσετε στο μυαλό σας πως άλλο είναι το πλήθος στοιχείων ενός πίνακα και άλλο το μέγεθος που πιάνουν στη μνήμη σε bytes.

Για παράδειγμα αν ο πίνακάς μας ήταν πίνακας χαρακτήρων, τότε το κάθε στοιχείο του θα έπιανε 1 byte (οι char είναι 1 byte) οπότε σε αυτή την περίπτωση το πλήθος των στοιχείων του πίνακα ταυτίζεται με το συνολικό μέγεθος που καταλαμβάνουν στη μνήμη. Εμείς όμως έχουμε πίνακα από int, και ο κάθε int καταλαμβάνει τουλάχιστον 2 bytes (και αλλάζει ανάλογα την πλατφόρμα) οπότε είναι προφανές πως σε αυτή την περίπτωση το μέγεθος που καταλαμβάνει ο πίνακας σε bytes στη μνήμη ΔΕΝ ταυτίζεται ως νούμερο με το πλήθος των στοιχείων του.

Συνήθως η ορολογία που χρησιμοποιείται για να διαχωρίζει τα 2 αυτά πράγματα είναι: length για το πλήθος στοιχείων και size για την μνήμη που καταλαμβάνουν σε bytes.

Η memset() ( όπως και οι memcpy() και memmove() ) είναι από τις πιο πολυ-χρησιμοποιούμενες συναρτήσεις στη C και θα τις χρησιμοποιήσουμε κι εμείς σε αυτό το πρόγραμμα. Συνιστώ να εξοικειωθείτε πρώτα με την memset() διαβάζοντας την τεκμηρίωσή της και κάνοντας όσες δοκιμές χρειαστούν προκειμένου να κατανοήσετε τη λειτουργία της !

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

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

Δημοσίευσηαπό migf1 » 10 Σεπ 2011, 09:58

Ελπίζοντας πως έχετε καταλάβει τα του προηγούμενου ποστ, πάμε να φτιάξουμε τις μέχρι τώρα συναρτήσεις μας να είναι πιο ασφαλείς !

Στην γραμμή 54 του κώδικά μας, στη main(), έχουμε προνοήσει και ελέγχουμε ώστε αν ο δείκτης table είναι NULL μετά το malloc() (επειδή π.χ. απέτυχε να δεσμευτεί μνήμη για αυτόν) να ειδοποιούμε τον χρήστη και να τερματίζουμε το πρόγραμμα).

Τι θα γινόταν όμως αν δεν κάναμε τον έλεγχο αυτόν και αφήναμε τη ροή να συνεχίσει; Για να δείτε τι θα γινόταν απενεργοποιήστε προσωρινά τη γραμμή του malloc() (για να είναι NULL ο table, λόγω της αρχικοποίησης στον ορισμό του) καθώς και τις γραμμές του ελέγχου μετά το malloc() και τρέξτε το πρόγραμμα. Για να απενεργοποιείτε στα γρήγορα συνεχόμενες γραμμές κώδικα, μπορείτε να χρησιμοποιείτε το pre-processor directive #if #endif, δηλαδή για το παραπάνω:

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

...
#if 0 // αλλάξτε το σε: #if 1 ή σβήστε το, μαζί με το #endif, για να ενεργοποιηθούν ξανά οι γραμμές

table = malloc( tabsize ); /* δέσμευση μνήμης για τον πίνακα */
if ( !table ) { /* αποτυχία δέσμευσης μνήμης */
puts("*** σφάλμα: ανεπαρκής μνήμη, τερματισμός προγράμματος..." );
exit( EXIT_FAILURE ); /* ... τερματισμός προγράμματος */
}
#endif

memset( table, EMPTYELEM, tabsize ); /* αρχικοποίηση όλων των στοιχείων */
...

Αυτό που θα γίνει είναι πως η memset() θα παράξει segmentation-fault ! Απενεργοποιήστε την κι αυτή προσωρινά, καθώς και το puts() που ακολουθεί για να παέι η ροή απευθείας στη γραμμή που καλεί τη συνάρτηση:

Κώδικας: Επιλογή όλων
table_print_stats( table, maxelems, tabsize ); /* τύπωμα στατιστικών */

Θα διαπιστώσετε πως και αυτή θα παράξει segmentation-fault !

Η επόμενη άσκηση λοιπόν είναι να τροποποιήσετε τον κώδικα των συναρτήσεων: tablen(), table_print_stats() και table_print_contents() ώστε να μην παράγουν segmentation-fault όταν ο πίνακας είναι NULL.

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

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

Δημοσίευσηαπό migf1 » 10 Σεπ 2011, 11:42

Α, και χρησιμοποιήστε την εντολή Search & Replace του editor σας και αντικαταστήστε όλες τις εμφανίσεις της λέξης: MINELEMS σε TABLE_MINLEN
Επίσης, αντικαταστήστε όλες τις εμφανίσεις της λέξης: maxelems σε maxtablen

Αυτό για να είμαστε συνεπείς ως προς την ορολογία length και size που εξήγησα στο προηγούμενο post

Και μιας που θα είστε εκεί, αλλάξτε και όλα τα EMPTYELEM σε TABLE_EMPTYCELL

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

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

Δημοσίευσηαπό stamatiou » 10 Σεπ 2011, 13:58

Καλημέρα! Λοιπόν έχω μια ερώτηση, όχι τόσο για C αλλά ψιλοκολλά. Όλα αυτά τα IDE που έχουν επάνω compiler και τέτοια, όπως στο Pelles C (για Windows) είναι καλά για να μαθαίνεις τη γλώσσα ή αυτά σε "κακομαθαίνουν";
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

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

stamatiou έγραψε:Καλημέρα! Λοιπόν έχω μια ερώτηση, όχι τόσο για C αλλά ψιλοκολλά. Όλα αυτά τα IDE που έχουν επάνω compiler και τέτοια, όπως στο Pelles C (για Windows) είναι καλά για να μαθαίνεις τη γλώσσα ή αυτά σε "κακομαθαίνουν";


Δεν εχει καμια σχεση κατα την προσωπικη μου αποψη αυτο... Απλα ειναι για λογους ευκολιας.
Εχεις ενα ολοκληρωμενο GUI για προγραμματισμο <=> ολοκληρωμενο περιβαλλον αναπτυξης.
Αν επαιζες στο λινουξ με σκετο GCC πχ (υποθετοντας οτι εχει ενσωματωμενο και τον συνδετη και τον συμβολομεταφραστη κτλπ)
απλα θα ησουν σε περιβαλλον "γκριζας" - μαυρης κονσολας. Για να δουμε τι θα πει και ο migf ομως και αν συμφωνει μαζι μου.
Γνώσεις ⇛ 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
Εκτύπωση

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

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