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

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

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

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

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

Είναι καλή φάση αυτό που ξεκινήσαμε πάντως, εμένα μου αρέσει πολύ γιατί έχουμε την ευκαιρία να αναλύσουμε σε βάθος πολλά πράγματα, με τη σειρά και με σύστημα :)
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, 19:46

hahahah θυμασαι οταν ειχες πρωτομπει πρωτη μερα και αρχιζες να πετας λιστες αχαχχαχα καπου αρχες ΙΟυνιου

παντως και απο δεικτες που ξεκινησαμε ηταν καλο... γιατι τωρα εγω νιωθω πιο εξοικειωμενος.... κοιτα και απο δυσκολα να ξεκινας ειναι μια τακτικη ακομη και αν δεν τα καταλαβαινεις ολα... γιατι ξεψαρωνεις... μετα
Γνώσεις ⇛ 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 » 10 Σεπ 2011, 20:13

Σόρρυ παδιά, είχα πάει για μπάσκετ :lol: Είπα να αποχαιρετώ σιγά σιγά το καλοκαιράκι :lol:
Θα κοιτάξω το θέμα σε λίγο :D
stamatiou
daemonTUX
daemonTUX
 
Δημοσιεύσεις: 947
Εγγραφή: 25 Ιουν 2010, 20:23
Εκτύπωση

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

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

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

Στην γραμμή 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(). Αυτή η πρακτική πρέπει να μας γίνει συνήθεια σε ΟΛΕΣ τις συναρτήσεις που δέχονται δείκτες ως ορίσματα!


Δηλαδη αρχικα αρχικοποιεις τον δείκτη του πίνακα στο NULL μετα του δεσμευεις μνημη με malloc και μετα γεμιζεις μνημη με την memset σε αυτον? Γεμιζεις δηλαδη μνημη για το -1?

Βασικα νομιζω κανεις κατι αλλο.... θέτεις ολη την μνημη σε -1 και οσα εισαγει ο χρηστης γραφονται κανονικα... στις θεσεις οσα εχουν μεινει θεωρουμε πως τα αφησε κενα οποτε και φερουν απο πριν την τιμη -1 ?
Γνώσεις ⇛ 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, 20:27

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

Αρχικά είχα δίλημμα αν πρέπει να πούμε από τώρα για δομές, ή να φτιάξουμε πρώτα μερικές ακόμα συναρτήσεις. Επειδή όμως έτσι κι αλλιώς θα χρειαστεί να χρησιμοποιήσουμε δομές κάποια στιγμή και αν έχουμε γράψει πολύ κώδικα θα είναι πιο χρονοβόρα η αναπροσαρμογή του, λέω να το κάνουμε από τώρα που δεν έχουμε πολύ κώδικα να μετατρέψουμε.

Αν και νομίζω ξέρετε ήδη τι είναι οι δομές (struct) εν τάχει λέω τα βασικά.

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

Ένα κλασικό κι απλό παράδειγμα χρήσης δομής είναι όταν θέλουμε να διαχειριστούμε συντεταγμένες. Ας πούμε το πρόγραμμά μας θα ασχοληθεί με σημεία του καρτεσιανού επιπέδου, που το καθένα έχει μια x και μια y συντεταγμένη.

Αντί λοιπόν να χρησιμοποιούμε "ξέμπαρκες" μεταβλητές για τις συντεταγμένες ενός σημείου, μπορούμε να φτιάξουμε μια δομή που θα την ονομάσουμε π.χ. point και θα αποτελείται από 2 int, ένα για τη συντεταγμένη x κι έναν για την συντεταγμένη y...

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

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

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

#include <stdio.h>

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

/* ----------------------------------------------------------- */
int main( void )
{
struct point a, b; // ορισμός 2 σημείων a και b
...
a.x = 10;
a.y = 12;

b.x = 100;
b.y = 12;
...

Από το παράδειγμα είναι προφανές πως όταν θέλουμε να αναφερθούμε σε ένα από τα πεδία μιας μεταβλητής που έχει οριστεί ως δομή, τότε γράφουμε το όνομα της μεταβλητής, ακολουθούμενο από μια τελεία κι αμέσως μετά το όνομα του πεδίου, π.χ.
Κώδικας: Επιλογή όλων

struct point a;
a.x = 10;

Αν η μεταβλητή μας όμως δεν είναι απλή μεταβλητή αλλά δείκτης, τότε για να αναφερθούμε σε ένα πεδίο της αντί για τελεία χρησιμοποιούμε το σύμβολο ->

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

#include <stdio.h>

// ορισμός της δομής struct point
struct point {
int x;
int y;
};

/* ----------------------------------------------------------- */
int main( void )
{
struct point *a = NULL; // ορισμός ενός σημείου a ως δείκτη σε δομή struct point

a = calloc(1, sizeof( struct point ) );
if ( !a ) {
// διαχειριστείτε εδώ ενδεχόμενη αποτυχία δέσμευση μνήμης για το a
}
a->x = 10;
a->y = 12;
...
if ( a )
free( a );
a = NULL;
}

return 0;
}

Και για να μην "κουβαλάμε" συνέχεια το keyword struct όποτε χρειάζεται να αναφερθούμε στον τύπο της δομής, όταν την πρωτο-ορίζουμε μπορούμε να την δηλώσουμε ως δικό μας επιπρόσθετο τύπο δεδομένων, με την χρήση του typedef..

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

#include <stdio.h>

// ορισμός & κατοχύρωση της δομής struct point ως πρόσθετο τύπο δεδομένων με το όνομα Point
typedef struct point {
int x;
int y;
} Point;

/* ----------------------------------------------------------- */
int main( void )
{
Point *a = NULL; // ορισμός ενός σημείου a ως δείκτη σε δομή struct point

a = calloc(1, sizeof( Point ) );
if ( !a ) {
// διαχειριστείτε εδώ ενδεχόμενη αποτυχία δέσμευση μνήμης για το a
}
a->x = 10;
a->y = 12;
...
if ( a )
free( a );
a = NULL;
}

return 0;
}

Ελπίζω να είναι όλα κατανοητά μέχρι εδώ (τα έχουμε χρησιμοποιήσει άλλωστε ήδη πολλές φορές :) )

Πού είναι όμως το κέρδος της ομαδοποίησης; Αφού και χωρίς δομή πάλι 2 μεταβλητές θα χρησιμοποιούσαμε για τις συντεταγμένες κάθε σημείου, 2 χρησιμοποιούμε και τώρα.. και μάλιστα και με πιο περίεργη σύνταξη :lol:

Το κέρδος της ομαδοποίησης γίνεται εμφανές όταν περνάμε τις μεταβλητές ως ορίσματα σε συναρτήσεις. Φανταστείτε για παράδειγμα ότι στο παραπάνω πρόγραμμα θέλαμε να φτιάξουμε μια συνάρτηση draw_line() η οποία θα παίρνει για ορίσματα 2 σημεία και θα τα ενώνει με μια γραμμή.

Χωρίς τη δομή θα έπρεπε να περάσουμε στη συνάρτηση 4 ορίσματα, 2 για κάθε σημείο... π.χ...
Κώδικας: Επιλογή όλων

draw_line( int ax, int ay, int bx, int by );

ενώ με τη δομή μπορούμε να περάσουμε μόνο 2 ορίσματα...
Κώδικας: Επιλογή όλων

draw_line( Point a, Point b );

Το δεύτερο εκτός από πιο δομημένο είναι και πολύ πιο ευανάγνωστο, δεν συμφωνείτε; :) Κυρίως όμως είναι πιο εύκολα διαχειρίσιμο, ειδικά σε πολύπλοκα προγράμματα!

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

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

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

Star_Light έγραψε:
Δηλαδη αρχικα αρχικοποιεις τον δείκτη του πίνακα στο NULL μετα του δεσμευεις μνημη με malloc και μετα γεμιζεις μνημη με την memset σε αυτον?

Ακριβώς!

έγραψε:
Κώδικας: Επιλογή όλων
Γεμιζεις δηλαδη μνημη για το -1?

Όχι, γεμίζω τη δεσμευμένη μνήμη με τιμή -1 (δλδ TABLE_EMPTYCELL) σε όλες της τις θέσεις.

έγραψε:Βασικα νομιζω κανεις κατι αλλο.... θέτεις ολη την μνημη σε -1

Έτσι!
έγραψε: και οσα εισαγει ο χρηστης γραφονται κανονικα... στις θεσεις οσα εχουν μεινει θεωρουμε πως τα αφησε κενα οποτε και φερουν απο πριν την τιμη -1 ?

Yeap... το πως ακριβώς θα μπαίνουν στον πίνακα ότι μας δίνει ο χρήστης είναι δουλειά της table_insert_element() που θα την φτιάξουμε λίγο αργότερα. Μόλις τελειώσουμε με τις δομές, και σας πω και 2-3 πράγματα για τα macros.
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, 20:39

τι ειπα πιο πανω??? οτι γεμιζεις μνημη για -1? χαχαχαχαχαχα καλα κρασα.
Γνώσεις ⇛ 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, 20:49

χιχιχιχι... no problem, εγώ το κατάλαβα πάντως ;)

Και για να προχωρήσουμε, η λύση της 2ης άσκησης είναι να βάλετε έναν έλεγχο πρόωρης εξόδου στις αρχές των συναρτήσεων, ώστε όταν το όρισμα του δείκτη table είναι NULL η συνάρτηση να επιστρέφει (χωρίς δηλαδή να επιχειρήσει να εξετάσει κανένα στοιχείο του πίνακα ;). Το έχω βάλει ήδη στην table_print_contents() στο ideone.com εγώ, βάλτε το και στις υπόλοιπες και δώστε μου το ΟΚ να το βάλω κι εγώ στις υπόλοιπες συναρτήσεις στο ideone.com.

ΥΓ. Μιας και είμαστε όλοι εδώ τώρα (γεια σου Γιώργο) δεν συνεχίζω με τις δομές μέχρι να τελειώσετε με τα προηγούμενα και να μου δώσετε το οκ :)
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, 22:14

Λοιπον πηγα κτυπησα μια σοκολαταρα και ηρθα στα ισα μου.... μπορει να φαω και κανα σουβλακι μετα αν και δεν το κοβω...

αμα καπνιζα θα εκανα και μερικα τσιγαρακια .. εσυ migf1 καπνιζεις??? εχω να καπνισω 5 μηνες!

Τωρα σχετικα με τις συναρτησεις προς στιγμην μπερδευτηκα... και νομιζα μηπως θελεις να τις κανουμε οπωσδηποτε να δουλευουν και να επιστρεφουν κατι απο την στιγμη που ο δεικτης ειναι NULL Και λεω τι λεει αυτος... πως θα το κανουμε αυτο :lol: :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++

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

migf1 έγραψε:χιχιχιχι... no problem, εγώ το κατάλαβα πάντως ;)

Και για να προχωρήσουμε, η λύση της 2ης άσκησης είναι να βάλετε έναν έλεγχο πρόωρης εξόδου στις αρχές των συναρτήσεων, ώστε όταν το όρισμα του δείκτη table είναι NULL η συνάρτηση να επιστρέφει (χωρίς δηλαδή να επιχειρήσει να εξετάσει κανένα στοιχείο του πίνακα ;). Το έχω βάλει ήδη στην table_print_contents() στο ideone.com εγώ, βάλτε το και στις υπόλοιπες και δώστε μου το ΟΚ να το βάλω κι εγώ στις υπόλοιπες συναρτήσεις στο ideone.com.

ΥΓ. Μιας και είμαστε όλοι εδώ τώρα (γεια σου Γιώργο) δεν συνεχίζω με τις δομές μέχρι να τελειώσετε με τα προηγούμενα και να μου δώσετε το οκ :)


Λοιπον αν θυμαμαι καλα ο δεικτης ηταν *table?

επομενως στην αρχη της συναρτησης εγω θα εβαζα αυτο

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


if(!table)
return;



Με το σκεπτικο οτι ο δεικτης δεν υπάρχει μιας και δεν δειχνει πουθενα.....
ΑΝ δεν υπαρχει επομενως επεστρεψε πισω.... στην main()
Γνώσεις ⇛ 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
Εκτύπωση

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

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