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

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

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

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

Δημοσίευσηαπό Ilias95 » 05 Μαρ 2012, 17:33

migf1 έγραψε:Ακόμα έχεις όμως νομίζω ένα προβληματάκι, επειδή στη συνθήκη if μέσα στο κεντρικό σου for-loop ξεκινάς...
Μορφοποιημένος Κώδικας: Επιλογή όλων
for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ((table[row+1][col] != '.' || row == NUM_ROWS-1) && (table[row-1][col] != '.' || row == 0) && \ ...

ενώ κανονικά πρέπει να πάνε πρώτα οι έλεγχοι για την τρέχουσα γραμμή (row) ...
Μορφοποιημένος Κώδικας: Επιλογή όλων
for (int i = 1; i < NUM_ALPHABETA - 1; i++) {
if ( (row == NUM_ROWS-1 || table[row+1][col] != '.') && (row == 0 || table[row-1][col] != '.') && \ ...

διότι έτσι όπως το έχεις τώρα, αν βρίσκεσαι ήδη π.χ. στην row NUM_ROWS-1, τότε το ξεκίνημα της if με: table[ row+1 ][ col ] != '.' ... βγάζει το row+1 εκτός ορίων του table.

Σωστά. Βέβαια στην προκειμένη πάντα false θα επιστρέφει, αλλά μαντεύω ότι είναι καλύτερα να γραφεί όπως λες ώστε να αποφύγουμε "παράξενες" συμπεριφορές.

Κατάλαβα και την χρησιμότητα των const και την διαφορά τους με τις σταθερές που ορίζονται με #define.
Ορισμένες απορίες προκύπτουν σχετικά με τα macros και για ποιο λόγο να τα προτιμήσουμε έναντι συναρτήσεων που θα κάνουν ακριβώς την ίδια δουλειά, αλλά πιθανότατα θα βρω τις απαντήσεις στο βιβλίο μόλις φτάσω στα κατάλληλα κεφάλαια.

Ευχαριστώ πολύ για τις αναλύσεις!
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 19:10

Ilias95 έγραψε:
Κατάλαβα και την χρησιμότητα των const και την διαφορά τους με τις σταθερές που ορίζονται με #define.

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

Κοίταξα τώρα στο βιβλίο και είδα πως αρχικά αναφέρεται στο keyword const στο 8ο κεφάλαιο, εκεί που λέει για constant arrays, και κατόπιν παραπέμπει στη σελίδα 466 όπου αναλύει τις διαφορές με τα #define (btw, αυτό που γράφει εκεί, πως τα #define δεν εμφανίζονται στον debugger, ο gdb το έχει λύσει το θέμα αυτό, αν κάνεις compile τα προγράμματα σου με το flag -g3 στον gcc (νομίζω και με -g2 και -g1, δεν είμαι σίγουρος).

Για να σου εντυπωθεί, σκέψου πως όποια μεταβλητή την ορίσεις με const μπροστά, την θέτεις μόνιμα σε κατάσταση read-only

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

Οι βασικές τους διαφορές είναι δυο:

α) στα macros ο compiler δεν τσεκάρει για τους τύπους των ορισμάτων (άρα δεν μπορεί να πιάσει απροσεξίες σου)

β) με εξαίρεση τα ονόματα των ορισμάτων τους (που προσαρμόζονται αυτόματα κατά το κάλεσμά τους, όπως και στις συναρτήσεις) το κυρίως σώμα των macros είναι ένα απλό search & replace στα σημεία του κώδικα που καλείς το macro. Είναι δηλαδή σαν αν έχεις γράψει χειροκίνητα τον κώδικα του macro σε όλα τα σημεία στα οποία το καλείς. Άρα τα macros εκτελούνται ταχύτερα από ότι οι συναρτήσεις, επειδή δεν δημιουργείται νέο stack frame στο run-time, ούτε προφανώς σώζονται/φορτώνονται/μετακινούνται κλπ τα ορίσματα σε μνήμη ή σε registers.

Ας πάρουμε για παράδειγμα ότι χρειάζεσαι να συγκρίνεις δυο τιμές και να κρατάς την μικρότερη ανάμεσά τους, σε διάφορα σημεία του κώδικά σου.

Αν το υλοποιήσεις με συνάρτηση...
Μορφοποιημένος Κώδικας: Επιλογή όλων
int min(const int x, const int y)
{
return x < y ? x : y;
}

έχεις ως υπέρ ότι αν καλέσεις τη συνάρτηση με 2 τιμές ή μεταβλητές που ΔΕΝ είναι τύπου int, ο compiler θα το "πιάσει" και θα βγάλει σφάλμα (type-checking). Το ίδιο θα πράξει αν είναι int μονάχα το ένα από τα δυο ορίσματα.

Παράλληλα έχεις το μειονέκτημα πως αν η σύγκριση που χρειάζεσαι θες να μπορεί να εφαρμοστεί σε τιμές/μεταβλητές άλλου τύπου (π.χ. float) τότε θα πρέπει να φτιάξεις κι άλλη συνάρτηση, ειδικά για σύγκριση μεταξύ float, άρα 2 βασικά ίδιες συναρτήσεις με μόνη διαφορά τον τύπο (ορισμάτων & επιστροφής)...

Μορφοποιημένος Κώδικας: Επιλογή όλων
int min_int(const int x, const int y)
{
return x < y ? x : y;
}

float min_float(const float x, const float y)
{
return x < y ? x : y;
}


Αν το υλοποιήσεις με macro...

Μορφοποιημένος Κώδικας: Επιλογή όλων
#define MIN(x,y)    ( (x) < (y) ? (x) : (y) )

έχεις τα ακριβώς αντίθετα πλεονεκτήματα & μειονεκτήματα. Μπορείς να συγκρίνεις ελεύθερα με το ίδιο ακριβώς macro 2 μεταβλητές/τιμές ίδιου τύπου, αλλά ακόμα κι αν του περάσεις το ένα όρισμα ως float και το άλλο ως char, όχι μόνο δεν θα το "πιάσει" ο compiler αλλά στο run-time θα εκτελεστεί κανονικά το macro... το πόσο αξιόπιστη όμως θα είναι η σύγκριση και κυρίως τι θα επιστρέψει το γνωρίζει μονάχα ο καλός Θεούλης :lol:

έγραψε:Ευχαριστώ πολύ για τις αναλύσεις!

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

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

Δημοσίευσηαπό Star_Light » 05 Μαρ 2012, 19:17

Off topic:
@migf1 αμα λυθει το προβλημα της επικοινωνιας... οι ξενες ειναι καλη περιπτωση ... μονο αυτο θα με προβληματιζε. Πως μπορεις να επικοινωνησεις μαζι τους αν σου συμβει κατι
Γνώσεις ⇛ 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

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 19:43

Α, υπάρχει κι άλλη σημαντική διαφορά macros & functions, που έχει να κάνει με τον διαφορετικό τρόπο αντιμετώπισης των ορισμάτων τους (αλλά και των τιμών τους, αν πρόκειται μονάχα για απλά #define χωρίς ορίσματα). Έχει να κάνει με αυτό που σου είχα γράψει παλιότερα να χρησιμοποιείς πάντα παρενθέσεις όταν γράφεις το κυρίως σώμα ενός macro, τόσο στα ορίσματά του, όσο και σε ολόκληρο το κυρίως σώμα αν πρόκειται για expression)

Για να μην γράφω κι άλλο κατεβατό, ρίξε μια ματιά εδώ: http://stackoverflow.com/questions/3211 ... efine-in-c. Έχει πολύ χαρακτηριστικά παραδείγματα που μπορεί να πάνε στραβά αν δεν χρησιμοποιείς σωστά παρενθέσεις στο κυρίως σώμα των macros (μην σε τρομάξουν αυτά που λένε εκεί του τύπου "να μη χρησιμοποιείς ποτέ macros εκτός αν δεν μπορείς να κάνεις αλλιώς"... αυτά τα γράφουν για να υπερ-προστατέψουν αρχάριους. Η αλήθεια είναι πως υπάρχουν ευαίσθητα σημεία, ναι, αλλά η σωστή χρήση των macros και είναι πολύ διαδεδομένη και σε γλιτώνει κι από πολύ κώδικα και σου δίνει και ταχύτητα εκτέλεσης).

Δες επίσης κι αυτό: http://kernelnewbies.org/FAQ/DoWhile0

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

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

Δημοσίευσηαπό Star_Light » 05 Μαρ 2012, 19:50

@migf1 μπορεις να δωσεις ενα παραδειγμα σε C τι εννοουν οταν λενε
ας πουμε οτι ενας καταχωρητης των 32 μπιτ μπορει να αποθηκευσει ακεραιους ευρους 2^32?

επειδη δοκιμασα να το κανω... και μου ελεγε οτι ειναι πολυ μεγαλος ας πουμε....
Δεν μπορω να καταλαβω με αυτο το 2^32 τι ακριβως εννοουν ή και το 2^64.

Και δεν εννοω φυσικα οτι η απορια μου ειναι στην εκθετικη αυξηση :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

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 19:57

Star_Light έγραψε:@migf1 μπορεις να δωσεις ενα παραδειγμα σε C τι εννοουν οταν λενε
ας πουμε οτι ενας καταχωρητης των 32 μπιτ μπορει να αποθηκευσει ακεραιους ευρους 2^32?

επειδη δοκιμασα να το κανω... και μου ελεγε οτι ειναι πολυ μεγαλος ας πουμε....
Δεν μπορω να καταλαβω με αυτο το 2^32 τι ακριβως εννοουν ή και το 2^64.

Και δεν εννοω φυσικα οτι η απορια μου ειναι στην εκθετικη αυξηση :P


http://forum.ubuntu-gr.org/viewtopic.ph ... AE#p232344
Go under the hood with C: Pointers, Strings, Linked Lists
Άβαταρ μέλους
migf1
powerTUX
powerTUX
 
Δημοσιεύσεις: 2082
Εγγραφή: 03 Ιουν 2011, 16:32
Εκτύπωση

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

Δημοσίευσηαπό Ilias95 » 05 Μαρ 2012, 20:05

migf1 έγραψε:
Star_Light έγραψε:@migf1 μπορεις να δωσεις ενα παραδειγμα σε C τι εννοουν οταν λενε
ας πουμε οτι ενας καταχωρητης των 32 μπιτ μπορει να αποθηκευσει ακεραιους ευρους 2^32?

επειδη δοκιμασα να το κανω... και μου ελεγε οτι ειναι πολυ μεγαλος ας πουμε....
Δεν μπορω να καταλαβω με αυτο το 2^32 τι ακριβως εννοουν ή και το 2^64.

Και δεν εννοω φυσικα οτι η απορια μου ειναι στην εκθετικη αυξηση :P


viewtopic.php?f=6&t=18969&p=232344&hilit=+%CE%B4%CF%85%CE%B1%CE%B4%CE%B9%CE%BA%CE%AE+%CE%BC%CE%BF%CF%81%CF%86%CE%AE#p232344

Επίσης τα εξηγεί πολύ ωραία και αναλυτικά ο King στο 7ο κεφάλαιο.
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό Ilias95 » 05 Μαρ 2012, 20:20

Να και μια υλοποίηση του 17ου programming project στην σελίδα 181:

Μορφοποιημένος Κώδικας: Επιλογή όλων
#include <stdio.h>
#include <string.h> // memset()

#define EMPTY 0

#define ROW(pos, size) ( (pos) / size )
#define COL(pos, size) ( (pos) % size )
#define ROW_LENGTH(size) ( ((size) - 1) * (size) )

#define POSUPNRIGHT(pos, size) ( POSRT(POSUP((pos), (size)), (size)) )
#define POSRT(pos, size) ( COL((pos), (size)) == (size) - 1 ? (pos) - ((size) - 1): (pos) + 1 )
#define POSUP(pos, size) ( ROW((pos), (size)) == 0 ? (pos) + ROW_LENGTH((size)) : (pos) - (size) )
#define POSDN(pos, size) ( ROW((pos), (size)) == (size) -1 ? (pos) - ROW_LENGTH((size)) : (pos) + (size) )

int main(void)
{
int pos, size;
printf("Enter size of magic square (odd 1-99): ");
scanf("%d", &size);

int square[size * size];
memset(square, EMPTY, sizeof(square)); // init table to EMPTY

pos = size / 2;
square[pos] = 1;

for (int i = 2; i < (size * size) + 1; i++) {
int upnright = POSUPNRIGHT(pos, size);
pos = square[upnright] == EMPTY ? upnright : POSDN(pos, size);
square[pos] = i;
}

// print magic square
for (int i = 0; i < size * size; i++) {
if (i != 0 && i % size == 0)
putchar('\n');
printf("%4d", square[i]);
}
putchar('\n');

return 0;
}


Σαν πρότυπο έχει περισσότερο τις υλοποιήσεις του migf1 στο 15ο project και είναι υλοποιημένη με μονοδιάστατο πίνακα.
Δοκίμασα να χρησιμοποιήσω macros αν και ακόμα δεν έχω δει αναλυτικά γι' αυτά, αλλά νομίζω ότι τα έκανα λιγάκι δυσανάγνωστα. :(

Θα την κάνω αργότερα ξανά σε δισδιάστατο πίνακα όπως ζητάει η άσκηση και θα προσέξω ώστε να κάνω τον κώδικα πιο ευανάγνωστο.

Πάντως μου άρεσε πολύ η τεχνική διαχείρισης ενός μονοδιάστατου πίνακα σαν δισδιάστατο η οποία μπορεί να αποδειχθεί πολύ χρήσιμη και σε γλώσσες που δεν υποστηρίζουν multidimensional arrays. :)
Ilias95
saintTUX
saintTUX
 
Δημοσιεύσεις: 1548
Εγγραφή: 29 Απρ 2011, 23:26
Εκτύπωση

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

Δημοσίευσηαπό Star_Light » 05 Μαρ 2012, 20:31

Οκ παιδια... ευχαριστω ;)
Γνώσεις ⇛ 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

Δημοσίευσηαπό migf1 » 05 Μαρ 2012, 21:14

Είσαι ωραίος Ηλία ("σε πάω" που έλεγε και ο Χριστόδουλος :lol:). Δεν παρακολούθησα τη λογική του κώδικά σου (ξεκίνησα να ασχολούμαι με το HexVew) αλλά έχω να σου προτείνω 2 βελτιώσεις:

α) Τα macros POSUPNRIGHT() και ROW_LENGTH() μπορείς να τα μετονομάσεις: POSUPRT() και ROWLEN() αντίστοιχα, για να βελτιώσεις το ευανάγνωστο του κώδικα (ή μπορείς και LENROW() το δεύτερο)

β) Εκείνος ο πολλαπλασιασμός (size * size) που κάνεις μέσα στη συνθήκη των for-loops, επαναλαμβάνεται σε ΚΑΘΕ επανάληψη των loops. Μπορείς λοιπόν να το κάνεις μια int μεταβλητή (π.χ. int sizesize;) της οποίας την τιμή θα την υπολογίσεις μια και μόνη φορά, και θα την χρησιμοποιήσεις κατόπιν ήδη υπολογισμένη στις συνθήκες των loops.

Δηλαδή...

Μορφοποιημένος Κώδικας: Επιλογή όλων
...
int main(void)
{
int pos, size, sizesize;
printf("Enter size of magic square (odd 1-99): ");
scanf("%d", &size);

sizesize = size * size;
int square[ sizesize ];
memset(square, EMPTY, sizeof(square)); // init table to EMPTY

pos = size / 2;
square[pos] = 1;

for (int i = 2; i < sizesize + 1; i++) {
int uprt = POSUPRT(pos, size);
pos = square[uprt] == EMPTY ? uprt : POSDN(pos, size);
square[pos] = i;
}

// print magic square
for (int i = 0; i < sizesize; i++) {
if (i != 0 && i % size == 0)
putchar('\n');
printf("%4d", square[i]);
}
putchar('\n');

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

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

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